aboutsummaryrefslogtreecommitdiff
path: root/ubuntu
diff options
context:
space:
mode:
Diffstat (limited to 'ubuntu')
-rw-r--r--ubuntu/aufs/BOM2
-rw-r--r--ubuntu/aufs/Makefile1
-rw-r--r--ubuntu/aufs/branch.c40
-rw-r--r--ubuntu/aufs/branch.h5
-rw-r--r--ubuntu/aufs/cpup.c18
-rw-r--r--ubuntu/aufs/dcsub.c22
-rw-r--r--ubuntu/aufs/dcsub.h37
-rw-r--r--ubuntu/aufs/debug.c53
-rw-r--r--ubuntu/aufs/debug.h3
-rw-r--r--ubuntu/aufs/dentry.c444
-rw-r--r--ubuntu/aufs/dentry.h14
-rw-r--r--ubuntu/aufs/dinfo.c159
-rw-r--r--ubuntu/aufs/dir.c10
-rw-r--r--ubuntu/aufs/export.c56
-rw-r--r--ubuntu/aufs/f_op.c9
-rw-r--r--ubuntu/aufs/file.c83
-rw-r--r--ubuntu/aufs/hfsnotify.c63
-rw-r--r--ubuntu/aufs/hnotify.c80
-rw-r--r--ubuntu/aufs/i_op.c92
-rw-r--r--ubuntu/aufs/i_op_add.c88
-rw-r--r--ubuntu/aufs/i_op_del.c89
-rw-r--r--ubuntu/aufs/i_op_ren.c103
-rw-r--r--ubuntu/aufs/iinfo.c38
-rw-r--r--ubuntu/aufs/inode.c86
-rw-r--r--ubuntu/aufs/inode.h46
-rw-r--r--ubuntu/aufs/opts.c46
-rw-r--r--ubuntu/aufs/opts.h7
-rw-r--r--ubuntu/aufs/plink.c6
-rw-r--r--ubuntu/aufs/rdu.c7
-rw-r--r--ubuntu/aufs/sbinfo.c49
-rw-r--r--ubuntu/aufs/super.c239
-rw-r--r--ubuntu/aufs/super.h3
-rw-r--r--ubuntu/aufs/sysrq.c44
-rw-r--r--ubuntu/aufs/vfsub.h7
-rw-r--r--ubuntu/aufs/wbr_policy.c3
-rw-r--r--ubuntu/aufs/whout.c12
-rw-r--r--ubuntu/aufs/wkq.c4
-rw-r--r--ubuntu/aufs/xino.c2
-rw-r--r--ubuntu/include/linux/aufs_type.h6
39 files changed, 1441 insertions, 635 deletions
diff --git a/ubuntu/aufs/BOM b/ubuntu/aufs/BOM
index efa81f9de29..bdad0cd19c5 100644
--- a/ubuntu/aufs/BOM
+++ b/ubuntu/aufs/BOM
@@ -1,2 +1,2 @@
URL: http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-standalone.git
-COMMIT: 097bf62d6f49619359d34bf17f242df38562489a
+COMMIT: c5021514085a5d96364e096dbd34cadb2251abfd
diff --git a/ubuntu/aufs/Makefile b/ubuntu/aufs/Makefile
index 3d6b50f84ba..46615fe113e 100644
--- a/ubuntu/aufs/Makefile
+++ b/ubuntu/aufs/Makefile
@@ -1,3 +1,4 @@
+
include ${src}/magic.mk
ifeq (${CONFIG_AUFS_FS},m)
include ${src}/conf.mk
diff --git a/ubuntu/aufs/branch.c b/ubuntu/aufs/branch.c
index 4687a35d43f..25c523de95e 100644
--- a/ubuntu/aufs/branch.c
+++ b/ubuntu/aufs/branch.c
@@ -33,6 +33,8 @@ static void au_br_do_free(struct au_branch *br)
struct au_wbr *wbr;
struct au_dykey **key;
+ au_hnotify_fin_br(br);
+
if (br->br_xino.xi_file)
fput(br->br_xino.xi_file);
mutex_destroy(&br->br_xino.xi_nondir_mtx);
@@ -124,13 +126,17 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
if (unlikely(!add_branch))
goto out;
+ err = au_hnotify_init_br(add_branch, perm);
+ if (unlikely(err))
+ goto out_br;
+
add_branch->br_wbr = NULL;
if (au_br_writable(perm)) {
/* may be freed separately at changing the branch permission */
add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr),
GFP_NOFS);
if (unlikely(!add_branch->br_wbr))
- goto out_br;
+ goto out_hnotify;
}
err = au_sbr_realloc(au_sbi(sb), new_nbranch);
@@ -143,6 +149,8 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
kfree(add_branch->br_wbr);
+out_hnotify:
+ au_hnotify_fin_br(add_branch);
out_br:
kfree(add_branch);
out:
@@ -548,11 +556,18 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
for (j = 0; !err && j < ndentry; j++) {
d = dpage->dentries[j];
AuDebugOn(!atomic_read(&d->d_count));
- inode = d->d_inode;
- if (au_digen(d) == sigen && au_iigen(inode) == sigen)
+ if (!au_digen_test(d, sigen)) {
di_read_lock_child(d, AuLock_IR);
- else {
+ if (unlikely(au_dbrange_test(d))) {
+ di_read_unlock(d, AuLock_IR);
+ continue;
+ }
+ } else {
di_write_lock_child(d);
+ if (unlikely(au_dbrange_test(d))) {
+ di_write_unlock(d);
+ continue;
+ }
err = au_reval_dpath(d, sigen);
if (!err)
di_downgrade_lock(d, AuLock_IR);
@@ -562,14 +577,18 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
}
}
+ /* AuDbgDentry(d); */
+ inode = d->d_inode;
bstart = au_dbstart(d);
bend = au_dbend(d);
if (bstart <= bindex
&& bindex <= bend
&& au_h_dptr(d, bindex)
- && (!S_ISDIR(inode->i_mode) || bstart == bend)) {
+ && ((inode && !S_ISDIR(inode->i_mode))
+ || bstart == bend)) {
err = -EBUSY;
AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
+ AuDbgDentry(d);
}
di_read_unlock(d, AuLock_IR);
}
@@ -606,7 +625,8 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
ii_read_lock_child(i);
else {
ii_write_lock_child(i);
- err = au_refresh_hinode_self(i, /*do_attr*/1);
+ err = au_refresh_hinode_self(i);
+ au_iigen_dec(i);
if (!err)
ii_downgrade_lock(i);
else {
@@ -830,7 +850,7 @@ static void au_warn_ima(void)
{
#ifdef CONFIG_IMA
/* since it doesn't support mark_files_ro() */
- AuWarn1("RW -> RO makes IMA to produce wrong message");
+ AuWarn1("RW -> RO makes IMA to produce wrong message\n");
#endif
}
@@ -893,7 +913,6 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
unsigned long long ull, max;
aufs_bindex_t br_id;
struct file *file, *hf, **array;
- struct dentry *dentry;
struct inode *inode;
struct au_hfile *hfile;
@@ -906,8 +925,6 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
br_id = au_sbr_id(sb, bindex);
for (ull = 0; ull < max; ull++) {
file = array[ull];
- dentry = file->f_dentry;
- inode = dentry->d_inode;
/* AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); */
fi_read_lock(file);
@@ -919,6 +936,7 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
goto out_array;
}
+ inode = file->f_dentry->d_inode;
hfile = &au_fi(file)->fi_htop;
hf = hfile->hf_file;
if (!S_ISREG(inode->i_mode)
@@ -951,7 +969,9 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
hfile = &au_fi(file)->fi_htop;
hf = hfile->hf_file;
/* fi_read_unlock(file); */
+ spin_lock(&hf->f_lock);
hf->f_mode &= ~FMODE_WRITE;
+ spin_unlock(&hf->f_lock);
if (!file_check_writeable(hf)) {
file_release_write(hf);
mnt_drop_write(hf->f_vfsmnt);
diff --git a/ubuntu/aufs/branch.h b/ubuntu/aufs/branch.h
index ddbfbb81008..a273e60a597 100644
--- a/ubuntu/aufs/branch.h
+++ b/ubuntu/aufs/branch.h
@@ -81,6 +81,11 @@ struct au_branch {
blkcnt_t br_xino_upper; /* watermark in blocks */
atomic_t br_xino_running;
+#ifdef CONFIG_AUFS_HFSNOTIFY
+ struct fsnotify_group *br_hfsn_group;
+ struct fsnotify_ops br_hfsn_ops;
+#endif
+
#ifdef CONFIG_SYSFS
/* an entry under sysfs per mount-point */
char br_name[8];
diff --git a/ubuntu/aufs/cpup.c b/ubuntu/aufs/cpup.c
index 962fd507147..3f667dd6acc 100644
--- a/ubuntu/aufs/cpup.c
+++ b/ubuntu/aufs/cpup.c
@@ -576,8 +576,9 @@ static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
if (dst_inode) {
if (unlikely(!plink)) {
err = -EIO;
- AuIOErr("i%lu exists on a upper branch "
- "but plink is disabled\n", inode->i_ino);
+ AuIOErr("hi%lu(i%lu) exists on b%d "
+ "but plink is disabled\n",
+ dst_inode->i_ino, inode->i_ino, bdst);
goto out;
}
@@ -591,7 +592,8 @@ static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
if (unlikely(!h_src->d_inode)) {
err = -EIO;
AuIOErr("i%lu exists on a upper branch "
- "but plink is broken\n", inode->i_ino);
+ "but not pseudo-linked\n",
+ inode->i_ino);
dput(h_src);
goto out;
}
@@ -816,13 +818,15 @@ static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
h_d_dst = hdp[0 + bdst].hd_dentry;
dinfo->di_bstart = bdst;
hdp[0 + bdst].hd_dentry = wh_dentry;
- h_d_start = hdp[0 + bstart].hd_dentry;
- if (file)
+ if (file) {
+ h_d_start = hdp[0 + bstart].hd_dentry;
hdp[0 + bstart].hd_dentry = au_hf_top(file)->f_dentry;
+ }
err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME,
/*h_parent*/NULL);
- if (!err && file) {
- err = au_reopen_nondir(file);
+ if (file) {
+ if (!err)
+ err = au_reopen_nondir(file);
hdp[0 + bstart].hd_dentry = h_d_start;
}
hdp[0 + bdst].hd_dentry = h_d_dst;
diff --git a/ubuntu/aufs/dcsub.c b/ubuntu/aufs/dcsub.c
index d5ab3525791..d9755f77859 100644
--- a/ubuntu/aufs/dcsub.c
+++ b/ubuntu/aufs/dcsub.c
@@ -98,7 +98,8 @@ static int au_dpages_append(struct au_dcsub_pages *dpages,
dpages->ndpage++;
}
- dpage->dentries[dpage->ndentry++] = dget(dentry);
+ /* d_count can be zero */
+ dpage->dentries[dpage->ndentry++] = dget_locked(dentry);
return 0; /* success */
out:
@@ -120,8 +121,7 @@ repeat:
resume:
if (this_parent->d_sb == sb
&& !IS_ROOT(this_parent)
- && atomic_read(&this_parent->d_count)
- && this_parent->d_inode
+ && au_di(this_parent)
&& (!test || test(this_parent, arg))) {
err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
if (unlikely(err))
@@ -133,14 +133,12 @@ resume:
struct dentry *dentry = list_entry(tmp, struct dentry,
d_u.d_child);
next = tmp->next;
- if (/*d_unhashed(dentry) || */!dentry->d_inode)
- continue;
if (!list_empty(&dentry->d_subdirs)) {
this_parent = dentry;
goto repeat;
}
if (dentry->d_sb == sb
- && atomic_read(&dentry->d_count)
+ && au_di(dentry)
&& (!test || test(dentry, arg))) {
err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
if (unlikely(err))
@@ -185,6 +183,18 @@ out:
return err;
}
+static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
+{
+ return au_di(dentry) && dentry->d_sb == arg;
+}
+
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+ struct dentry *dentry, int do_include)
+{
+ return au_dcsub_pages_rev(dpages, dentry, do_include,
+ au_dcsub_dpages_aufs, dentry->d_sb);
+}
+
int au_test_subdir(struct dentry *d1, struct dentry *d2)
{
struct path path[2] = {
diff --git a/ubuntu/aufs/dcsub.h b/ubuntu/aufs/dcsub.h
index be25a134621..13b4fb2ca84 100644
--- a/ubuntu/aufs/dcsub.h
+++ b/ubuntu/aufs/dcsub.h
@@ -26,6 +26,7 @@
#ifdef __KERNEL__
#include <linux/dcache.h>
+#include <linux/fs.h>
#include <linux/types.h>
struct dentry;
@@ -50,6 +51,8 @@ int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
au_dpages_test test, void *arg);
int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
int do_include, au_dpages_test test, void *arg);
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+ struct dentry *dentry, int do_include);
int au_test_subdir(struct dentry *d1, struct dentry *d2);
/* ---------------------------------------------------------------------- */
@@ -59,5 +62,39 @@ static inline int au_d_removed(struct dentry *d)
return !IS_ROOT(d) && d_unhashed(d);
}
+static inline int au_d_hashed_positive(struct dentry *d)
+{
+ int err;
+ struct inode *inode = d->d_inode;
+ err = 0;
+ if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink))
+ err = -ENOENT;
+ return err;
+}
+
+static inline int au_d_alive(struct dentry *d)
+{
+ int err;
+ struct inode *inode;
+ err = 0;
+ if (!IS_ROOT(d))
+ err = au_d_hashed_positive(d);
+ else {
+ inode = d->d_inode;
+ if (unlikely(au_d_removed(d) || !inode || !inode->i_nlink))
+ err = -ENOENT;
+ }
+ return err;
+}
+
+static inline int au_alive_dir(struct dentry *d)
+{
+ int err;
+ err = au_d_alive(d);
+ if (unlikely(err || IS_DEADDIR(d->d_inode)))
+ err = -ENOENT;
+ return err;
+}
+
#endif /* __KERNEL__ */
#endif /* __AUFS_DCSUB_H__ */
diff --git a/ubuntu/aufs/debug.c b/ubuntu/aufs/debug.c
index ec8dc079edc..fd3ebd8481d 100644
--- a/ubuntu/aufs/debug.c
+++ b/ubuntu/aufs/debug.c
@@ -335,24 +335,63 @@ void au_dbg_iattr(struct iattr *ia)
/* ---------------------------------------------------------------------- */
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
+{
+ struct inode *h_inode, *inode = dentry->d_inode;
+ struct dentry *h_dentry;
+ aufs_bindex_t bindex, bend, bi;
+
+ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
+ return;
+
+ bend = au_dbend(dentry);
+ bi = au_ibend(inode);
+ if (bi < bend)
+ bend = bi;
+ bindex = au_dbstart(dentry);
+ bi = au_ibstart(inode);
+ if (bi > bindex)
+ bindex = bi;
+
+ for (; bindex <= bend; bindex++) {
+ h_dentry = au_h_dptr(dentry, bindex);
+ if (!h_dentry)
+ continue;
+ h_inode = au_h_iptr(inode, bindex);
+ if (unlikely(h_inode != h_dentry->d_inode)) {
+ int old = au_debug_test();
+ if (!old)
+ au_debug(1);
+ AuDbg("b%d, %s:%d\n", bindex, func, line);
+ AuDbgDentry(dentry);
+ AuDbgInode(inode);
+ if (!old)
+ au_debug(0);
+ BUG();
+ }
+ }
+}
+
void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen)
{
struct dentry *parent;
parent = dget_parent(dentry);
- AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)
- || IS_ROOT(dentry)
- || au_digen(parent) != sigen);
+ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
+ AuDebugOn(IS_ROOT(dentry));
+ AuDebugOn(au_digen_test(parent, sigen));
dput(parent);
}
void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
{
struct dentry *parent;
+ struct inode *inode;
parent = dget_parent(dentry);
- AuDebugOn(S_ISDIR(dentry->d_inode->i_mode)
- || au_digen(parent) != sigen);
+ inode = dentry->d_inode;
+ AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode));
+ AuDebugOn(au_digen_test(parent, sigen));
dput(parent);
}
@@ -365,13 +404,13 @@ void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
err = au_dpages_init(&dpages, GFP_NOFS);
AuDebugOn(err);
- err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL);
+ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1);
AuDebugOn(err);
for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
dpage = dpages.dpages + i;
dentries = dpage->dentries;
for (j = dpage->ndentry - 1; !err && j >= 0; j--)
- AuDebugOn(au_digen(dentries[j]) != sigen);
+ AuDebugOn(au_digen_test(dentries[j], sigen));
}
au_dpages_free(&dpages);
}
diff --git a/ubuntu/aufs/debug.h b/ubuntu/aufs/debug.h
index c6b2626dee7..cfe4413181b 100644
--- a/ubuntu/aufs/debug.h
+++ b/ubuntu/aufs/debug.h
@@ -132,6 +132,8 @@ void au_dbg_sleep_jiffy(int jiffy);
struct iattr;
void au_dbg_iattr(struct iattr *ia);
+#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__)
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line);
void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen);
void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen);
void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen);
@@ -196,6 +198,7 @@ void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
AuInfo("%s\n", sym); \
} while (0)
#else
+AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry)
AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen)
AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry,
unsigned int sigen)
diff --git a/ubuntu/aufs/dentry.c b/ubuntu/aufs/dentry.c
index 2743e26f5ee..8daf4a36aad 100644
--- a/ubuntu/aufs/dentry.c
+++ b/ubuntu/aufs/dentry.c
@@ -267,9 +267,11 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
}
err = npositive;
if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
- && au_dbstart(dentry) < 0))
- /* both of real entry and whiteout found */
+ && au_dbstart(dentry) < 0)) {
err = -EIO;
+ AuIOErr("both of real entry and whiteout found, %.*s, err %d\n",
+ AuDLNPair(dentry), err);
+ }
out_parent:
dput(parent);
@@ -320,8 +322,8 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
goto out;
if (unlikely(h_dentry->d_inode)) {
err = -EIO;
- AuIOErr("b%d %.*s should be negative.\n",
- bindex, AuDLNPair(h_dentry));
+ AuIOErr("%.*s should be negative on b%d.\n",
+ AuDLNPair(h_dentry), bindex);
dput(h_dentry);
goto out;
}
@@ -437,32 +439,30 @@ int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
/* ---------------------------------------------------------------------- */
-static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
- struct dentry *parent)
+static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
{
- struct dentry *h_d, *h_dp;
- struct au_hdentry tmp, *q;
- struct super_block *sb;
+ int err;
aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
+ struct au_hdentry tmp, *p, *q;
+ struct au_dinfo *dinfo;
+ struct super_block *sb;
- AuRwMustWriteLock(&dinfo->di_rwsem);
+ DiMustWriteLock(dentry);
+ sb = dentry->d_sb;
+ dinfo = au_di(dentry);
bend = dinfo->di_bend;
bwh = dinfo->di_bwh;
bdiropq = dinfo->di_bdiropq;
+ p = dinfo->di_hdentry + dinfo->di_bstart;
for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
- h_d = p->hd_dentry;
- if (!h_d)
+ if (!p->hd_dentry)
continue;
- h_dp = dget_parent(h_d);
- if (h_dp == au_h_dptr(parent, bindex)) {
- dput(h_dp);
+ new_bindex = au_br_index(sb, p->hd_id);
+ if (new_bindex == bindex)
continue;
- }
- new_bindex = au_find_dbindex(parent, h_dp);
- dput(h_dp);
if (dinfo->di_bwh == bindex)
bwh = new_bindex;
if (dinfo->di_bdiropq == bindex)
@@ -484,7 +484,6 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
}
}
- sb = parent->d_sb;
dinfo->di_bwh = -1;
if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
dinfo->di_bwh = bwh;
@@ -495,6 +494,9 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
&& au_sbr_whable(sb, bdiropq))
dinfo->di_bdiropq = bdiropq;
+ err = -EIO;
+ dinfo->di_bstart = -1;
+ dinfo->di_bend = -1;
bend = au_dbend(parent);
p = dinfo->di_hdentry;
for (bindex = 0; bindex <= bend; bindex++, p++)
@@ -503,61 +505,318 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
break;
}
- p = dinfo->di_hdentry + bend;
- for (bindex = bend; bindex >= 0; bindex--, p--)
- if (p->hd_dentry) {
- dinfo->di_bend = bindex;
- break;
+ if (dinfo->di_bstart >= 0) {
+ p = dinfo->di_hdentry + bend;
+ for (bindex = bend; bindex >= 0; bindex--, p--)
+ if (p->hd_dentry) {
+ dinfo->di_bend = bindex;
+ err = 0;
+ break;
+ }
+ }
+
+ return err;
+}
+
+static void au_do_hide(struct dentry *dentry)
+{
+ struct inode *inode;
+
+ inode = dentry->d_inode;
+ if (inode) {
+ if (!S_ISDIR(inode->i_mode)) {
+ if (inode->i_nlink && !d_unhashed(dentry))
+ drop_nlink(inode);
+ } else {
+ clear_nlink(inode);
+ /* stop next lookup */
+ inode->i_flags |= S_DEAD;
}
+ smp_mb(); /* necessary? */
+ }
+ d_drop(dentry);
+}
+
+static int au_hide_children(struct dentry *parent)
+{
+ int err, i, j, ndentry;
+ struct au_dcsub_pages dpages;
+ struct au_dpage *dpage;
+ struct dentry *dentry;
+
+ err = au_dpages_init(&dpages, GFP_NOFS);
+ if (unlikely(err))
+ goto out;
+ err = au_dcsub_pages(&dpages, parent, NULL, NULL);
+ if (unlikely(err))
+ goto out_dpages;
+
+ /* in reverse order */
+ for (i = dpages.ndpage - 1; i >= 0; i--) {
+ dpage = dpages.dpages + i;
+ ndentry = dpage->ndentry;
+ for (j = ndentry - 1; j >= 0; j--) {
+ dentry = dpage->dentries[j];
+ if (dentry != parent)
+ au_do_hide(dentry);
+ }
+ }
+
+out_dpages:
+ au_dpages_free(&dpages);
+out:
+ return err;
+}
+
+static void au_hide(struct dentry *dentry)
+{
+ int err;
+ struct inode *inode;
+
+ AuDbgDentry(dentry);
+ inode = dentry->d_inode;
+ if (inode && S_ISDIR(inode->i_mode)) {
+ /* shrink_dcache_parent(dentry); */
+ err = au_hide_children(dentry);
+ if (unlikely(err))
+ AuIOErr("%.*s, failed hiding children, ignored %d\n",
+ AuDLNPair(dentry), err);
+ }
+ au_do_hide(dentry);
}
/*
- * returns the number of found lower positive dentries,
- * otherwise an error.
+ * By adding a dirty branch, a cached dentry may be affected in various ways.
+ *
+ * a dirty branch is added
+ * - on the top of layers
+ * - in the middle of layers
+ * - to the bottom of layers
+ *
+ * on the added branch there exists
+ * - a whiteout
+ * - a diropq
+ * - a same named entry
+ * + exist
+ * * negative --> positive
+ * * positive --> positive
+ * - type is unchanged
+ * - type is changed
+ * + doesn't exist
+ * * negative --> negative
+ * * positive --> negative (rejected by au_br_del() for non-dir case)
+ * - none
*/
-int au_refresh_hdentry(struct dentry *dentry, mode_t type)
+static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
+ struct au_dinfo *tmp)
{
- int npositive, err;
+ int err;
+ aufs_bindex_t bindex, bend;
+ struct {
+ struct dentry *dentry;
+ struct inode *inode;
+ mode_t mode;
+ } orig_h, tmp_h;
+ struct au_hdentry *hd;
+ struct inode *inode, *h_inode;
+ struct dentry *h_dentry;
+
+ err = 0;
+ AuDebugOn(dinfo->di_bstart < 0);
+ orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
+ orig_h.inode = orig_h.dentry->d_inode;
+ orig_h.mode = 0;
+ if (orig_h.inode)
+ orig_h.mode = orig_h.inode->i_mode & S_IFMT;
+ memset(&tmp_h, 0, sizeof(tmp_h));
+ if (tmp->di_bstart >= 0) {
+ tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
+ tmp_h.inode = tmp_h.dentry->d_inode;
+ if (tmp_h.inode)
+ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
+ }
+
+ inode = dentry->d_inode;
+ if (!orig_h.inode) {
+ AuDbg("nagative originally\n");
+ if (inode) {
+ au_hide(dentry);
+ goto out;
+ }
+ AuDebugOn(inode);
+ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+ AuDebugOn(dinfo->di_bdiropq != -1);
+
+ if (!tmp_h.inode) {
+ AuDbg("negative --> negative\n");
+ /* should have only one negative lower */
+ if (tmp->di_bstart >= 0
+ && tmp->di_bstart < dinfo->di_bstart) {
+ AuDebugOn(tmp->di_bstart != tmp->di_bend);
+ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+ au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
+ au_di_cp(dinfo, tmp);
+ hd = tmp->di_hdentry + tmp->di_bstart;
+ au_set_h_dptr(dentry, tmp->di_bstart,
+ dget(hd->hd_dentry));
+ }
+ au_dbg_verify_dinode(dentry);
+ } else {
+ AuDbg("negative --> positive\n");
+ /*
+ * similar to the behaviour of creating with bypassing
+ * aufs.
+ * unhash it in order to force an error in the
+ * succeeding create operation.
+ * we should not set S_DEAD here.
+ */
+ d_drop(dentry);
+ /* au_di_swap(tmp, dinfo); */
+ au_dbg_verify_dinode(dentry);
+ }
+ } else {
+ AuDbg("positive originally\n");
+ /* inode may be NULL */
+ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
+ if (!tmp_h.inode) {
+ AuDbg("positive --> negative\n");
+ /* or bypassing aufs */
+ au_hide(dentry);
+ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
+ dinfo->di_bwh = tmp->di_bwh;
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ } else if (orig_h.mode == tmp_h.mode) {
+ AuDbg("positive --> positive, same type\n");
+ if (!S_ISDIR(orig_h.mode)
+ && dinfo->di_bstart > tmp->di_bstart) {
+ /*
+ * similar to the behaviour of removing and
+ * creating.
+ */
+ au_hide(dentry);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ } else {
+ /* fill empty slots */
+ if (dinfo->di_bstart > tmp->di_bstart)
+ dinfo->di_bstart = tmp->di_bstart;
+ if (dinfo->di_bend < tmp->di_bend)
+ dinfo->di_bend = tmp->di_bend;
+ dinfo->di_bwh = tmp->di_bwh;
+ dinfo->di_bdiropq = tmp->di_bdiropq;
+ hd = tmp->di_hdentry;
+ bend = dinfo->di_bend;
+ for (bindex = tmp->di_bstart; bindex <= bend;
+ bindex++) {
+ if (au_h_dptr(dentry, bindex))
+ continue;
+ h_dentry = hd[bindex].hd_dentry;
+ if (!h_dentry)
+ continue;
+ h_inode = h_dentry->d_inode;
+ AuDebugOn(!h_inode);
+ AuDebugOn(orig_h.mode
+ != (h_inode->i_mode
+ & S_IFMT));
+ au_set_h_dptr(dentry, bindex,
+ dget(h_dentry));
+ }
+ err = au_refresh_hinode(inode, dentry);
+ au_dbg_verify_dinode(dentry);
+ }
+ } else {
+ AuDbg("positive --> positive, different type\n");
+ /* similar to the behaviour of removing and creating */
+ au_hide(dentry);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ }
+ }
+
+out:
+ return err;
+}
+
+int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
+{
+ int err, ebrange;
unsigned int sigen;
- aufs_bindex_t bstart;
- struct au_dinfo *dinfo;
+ struct au_dinfo *dinfo, *tmp;
struct super_block *sb;
- struct dentry *parent;
+ struct inode *inode;
DiMustWriteLock(dentry);
+ AuDebugOn(IS_ROOT(dentry));
+ AuDebugOn(!parent->d_inode);
sb = dentry->d_sb;
- AuDebugOn(IS_ROOT(dentry));
+ inode = dentry->d_inode;
sigen = au_sigen(sb);
- parent = dget_parent(dentry);
- AuDebugOn(au_digen(parent) != sigen
- || au_iigen(parent->d_inode) != sigen);
+ err = au_digen_test(parent, sigen);
+ if (unlikely(err))
+ goto out;
dinfo = au_di(dentry);
err = au_di_realloc(dinfo, au_sbend(sb) + 1);
- npositive = err;
if (unlikely(err))
goto out;
- au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo,
- parent);
+ ebrange = au_dbrange_test(dentry);
+ if (!ebrange)
+ ebrange = au_do_refresh_hdentry(dentry, parent);
- npositive = 0;
- bstart = au_dbstart(parent);
- if (type != S_IFDIR && dinfo->di_bstart == bstart)
- goto out_dgen; /* success */
+ if (d_unhashed(dentry) || ebrange) {
+ AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ if (!err)
+ goto out_dgen; /* success */
+ goto out;
+ }
- npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL);
- if (npositive < 0)
+ /* temporary dinfo */
+ AuDbgDentry(dentry);
+ err = -ENOMEM;
+ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+ if (unlikely(!tmp))
+ goto out;
+ au_di_swap(tmp, dinfo);
+ /* returns the number of positive dentries */
+ /*
+ * if current working dir is removed, it returns an error.
+ * but the dentry is legal.
+ */
+ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
+ AuDbgDentry(dentry);
+ au_di_swap(tmp, dinfo);
+ if (err == -ENOENT)
+ err = 0;
+ if (err >= 0) {
+ /* compare/refresh by dinfo */
+ AuDbgDentry(dentry);
+ err = au_refresh_by_dinfo(dentry, dinfo, tmp);
+ au_dbg_verify_dinode(dentry);
+ AuTraceErr(err);
+ }
+ au_rw_write_unlock(&tmp->di_rwsem);
+ au_di_free(tmp);
+ if (unlikely(err))
goto out;
- if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart)
- d_drop(dentry);
out_dgen:
au_update_digen(dentry);
out:
- dput(parent);
- AuTraceErr(npositive);
- return npositive;
+ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
+ AuIOErr("failed refreshing %.*s, %d\n",
+ AuDLNPair(dentry), err);
+ AuDbgDentry(dentry);
+ }
+ AuTraceErr(err);
+ return err;
}
static noinline_for_stack
@@ -706,29 +965,23 @@ static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
return err;
}
+/* todo: consolidate with do_refresh() and au_reval_for_attr() */
static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
{
int err;
struct dentry *parent;
- struct inode *inode;
- inode = dentry->d_inode;
- if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
+ if (!au_digen_test(dentry, sigen))
return 0;
parent = dget_parent(dentry);
di_read_lock_parent(parent, AuLock_IR);
- AuDebugOn(au_digen(parent) != sigen
- || au_iigen(parent->d_inode) != sigen);
+ AuDebugOn(au_digen_test(parent, sigen));
au_dbg_verify_gen(parent, sigen);
-
- /* returns a number of positive dentries */
- err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
- if (err >= 0)
- err = au_refresh_hinode(inode, dentry);
-
+ err = au_refresh_dentry(dentry, parent);
di_read_unlock(parent, AuLock_IR);
dput(parent);
+ AuTraceErr(err);
return err;
}
@@ -738,36 +991,35 @@ int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
struct dentry *d, *parent;
struct inode *inode;
- if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS))
+ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR))
return simple_reval_dpath(dentry, sigen);
/* slow loop, keep it simple and stupid */
/* cf: au_cpup_dirs() */
err = 0;
parent = NULL;
- while (au_digen(dentry) != sigen
- || au_iigen(dentry->d_inode) != sigen) {
+ while (au_digen_test(dentry, sigen)) {
d = dentry;
while (1) {
dput(parent);
parent = dget_parent(d);
- if (au_digen(parent) == sigen
- && au_iigen(parent->d_inode) == sigen)
+ if (!au_digen_test(parent, sigen))
break;
d = parent;
}
inode = d->d_inode;
if (d != dentry)
- di_write_lock_child(d);
+ di_write_lock_child2(d);
/* someone might update our dentry while we were sleeping */
- if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) {
+ if (au_digen_test(d, sigen)) {
+ /*
+ * todo: consolidate with simple_reval_dpath(),
+ * do_refresh() and au_reval_for_attr().
+ */
di_read_lock_parent(parent, AuLock_IR);
- /* returns a number of positive dentries */
- err = au_refresh_hdentry(d, inode->i_mode & S_IFMT);
- if (err >= 0)
- err = au_refresh_hinode(inode, d);
+ err = au_refresh_dentry(d, parent);
di_read_unlock(parent, AuLock_IR);
}
@@ -792,6 +1044,10 @@ static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
struct super_block *sb;
struct inode *inode;
+ valid = 0;
+ if (unlikely(!au_di(dentry)))
+ goto out;
+
valid = 1;
sb = dentry->d_sb;
inode = dentry->d_inode;
@@ -803,38 +1059,48 @@ static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
if (unlikely(err)) {
valid = err;
+ AuTraceErr(err);
goto out;
}
- sigen = au_sigen(sb);
- if (au_digen(dentry) != sigen) {
- AuDebugOn(IS_ROOT(dentry));
- if (inode)
- err = au_reval_dpath(dentry, sigen);
- if (unlikely(err))
- goto out_dgrade;
+ if (unlikely(au_dbrange_test(dentry))) {
+ err = -EINVAL;
+ AuTraceErr(err);
+ goto out_dgrade;
}
- if (inode && au_iigen(inode) != sigen) {
+
+ sigen = au_sigen(sb);
+ if (au_digen_test(dentry, sigen)) {
AuDebugOn(IS_ROOT(dentry));
- err = au_refresh_hinode(inode, dentry);
- if (unlikely(err))
+ err = au_reval_dpath(dentry, sigen);
+ if (unlikely(err)) {
+ AuTraceErr(err);
goto out_dgrade;
+ }
}
di_downgrade_lock(dentry, AuLock_IR);
err = -EINVAL;
+ if (inode && (IS_DEADDIR(inode) || !inode->i_nlink))
+ goto out_inval;
+
do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
if (do_udba && inode) {
aufs_bindex_t bstart = au_ibstart(inode);
+ struct inode *h_inode;
- if (bstart >= 0
- && au_test_higen(inode, au_h_iptr(inode, bstart)))
- goto out_inval;
+ if (bstart >= 0) {
+ h_inode = au_h_iptr(inode, bstart);
+ if (h_inode && au_test_higen(inode, h_inode))
+ goto out_inval;
+ }
}
err = h_d_revalidate(dentry, inode, nd, do_udba);
- if (unlikely(!err && do_udba && au_dbstart(dentry) < 0))
- /* both of real entry and whiteout found */
+ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) {
err = -EIO;
+ AuDbg("both of real entry and whiteout found, %.*s, err %d\n",
+ AuDLNPair(dentry), err);
+ }
goto out_inval;
out_dgrade:
@@ -844,14 +1110,16 @@ out_inval:
AuTraceErr(err);
valid = !err;
out:
- if (!valid)
+ if (!valid) {
AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid);
+ d_drop(dentry);
+ }
return valid;
}
static void aufs_d_release(struct dentry *dentry)
{
- if (dentry->d_fsdata) {
+ if (au_di(dentry)) {
au_di_fin(dentry);
au_hn_di_reinit(dentry);
}
diff --git a/ubuntu/aufs/dentry.h b/ubuntu/aufs/dentry.h
index 2f2bb81db56..4865f5e0903 100644
--- a/ubuntu/aufs/dentry.h
+++ b/ubuntu/aufs/dentry.h
@@ -29,10 +29,9 @@
#include <linux/aufs_type.h>
#include "rwsem.h"
-/* make a single member structure for future use */
-/* todo: remove this structure */
struct au_hdentry {
struct dentry *hd_dentry;
+ aufs_bindex_t hd_id;
};
struct au_dinfo {
@@ -58,11 +57,15 @@ int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
struct nameidata *nd);
int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex);
-int au_refresh_hdentry(struct dentry *dentry, mode_t type);
+int au_refresh_dentry(struct dentry *dentry, struct dentry *parent);
int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
/* dinfo.c */
void au_di_init_once(void *_di);
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
+void au_di_free(struct au_dinfo *dinfo);
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
int au_di_init(struct dentry *dentry);
void au_di_fin(struct dentry *dentry);
int au_di_realloc(struct au_dinfo *dinfo, int nbr);
@@ -82,6 +85,8 @@ aufs_bindex_t au_dbtaildir(struct dentry *dentry);
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_dentry);
+int au_digen_test(struct dentry *dentry, unsigned int sigen);
+int au_dbrange_test(struct dentry *dentry);
void au_update_digen(struct dentry *dentry);
void au_update_dbrange(struct dentry *dentry, int do_put_zero);
void au_update_dbstart(struct dentry *dentry);
@@ -104,7 +109,8 @@ enum {
AuLsc_DI_CHILD3, /* copyup dirs */
AuLsc_DI_PARENT,
AuLsc_DI_PARENT2,
- AuLsc_DI_PARENT3
+ AuLsc_DI_PARENT3,
+ AuLsc_DI_TMP /* temp for replacing dinfo */
};
/*
diff --git a/ubuntu/aufs/dinfo.c b/ubuntu/aufs/dinfo.c
index 4a638dc92b5..fff8cdd2771 100644
--- a/ubuntu/aufs/dinfo.c
+++ b/ubuntu/aufs/dinfo.c
@@ -31,60 +31,118 @@ void au_di_init_once(void *_dinfo)
au_rw_class(&dinfo->di_rwsem, &aufs_di);
}
-int au_di_init(struct dentry *dentry)
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
{
struct au_dinfo *dinfo;
- struct super_block *sb;
- int nbr;
+ int nbr, i;
dinfo = au_cache_alloc_dinfo();
if (unlikely(!dinfo))
goto out;
- sb = dentry->d_sb;
nbr = au_sbend(sb) + 1;
if (nbr <= 0)
nbr = 1;
dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
- if (unlikely(!dinfo->di_hdentry))
- goto out_dinfo;
-
- atomic_set(&dinfo->di_generation, au_sigen(sb));
- /* smp_mb(); */ /* atomic_set */
- au_rw_write_lock_nested(&dinfo->di_rwsem, AuLsc_DI_CHILD);
- dinfo->di_bstart = -1;
- dinfo->di_bend = -1;
- dinfo->di_bwh = -1;
- dinfo->di_bdiropq = -1;
-
- dentry->d_fsdata = dinfo;
- dentry->d_op = &aufs_dop;
- return 0; /* success */
+ if (dinfo->di_hdentry) {
+ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
+ dinfo->di_bstart = -1;
+ dinfo->di_bend = -1;
+ dinfo->di_bwh = -1;
+ dinfo->di_bdiropq = -1;
+ for (i = 0; i < nbr; i++)
+ dinfo->di_hdentry[i].hd_id = -1;
+ goto out;
+ }
-out_dinfo:
au_cache_free_dinfo(dinfo);
+ dinfo = NULL;
+
out:
- return -ENOMEM;
+ return dinfo;
}
-void au_di_fin(struct dentry *dentry)
+void au_di_free(struct au_dinfo *dinfo)
{
- struct au_dinfo *di;
struct au_hdentry *p;
aufs_bindex_t bend, bindex;
/* dentry may not be revalidated */
- di = dentry->d_fsdata;
- bindex = di->di_bstart;
+ bindex = dinfo->di_bstart;
if (bindex >= 0) {
- bend = di->di_bend;
- p = di->di_hdentry + bindex;
+ bend = dinfo->di_bend;
+ p = dinfo->di_hdentry + bindex;
while (bindex++ <= bend)
au_hdput(p++);
}
- kfree(di->di_hdentry);
- AuRwDestroy(&di->di_rwsem);
- au_cache_free_dinfo(di);
+ kfree(dinfo->di_hdentry);
+ au_cache_free_dinfo(dinfo);
+}
+
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
+{
+ struct au_hdentry *p;
+ aufs_bindex_t bi;
+
+ AuRwMustWriteLock(&a->di_rwsem);
+ AuRwMustWriteLock(&b->di_rwsem);
+
+#define DiSwap(v, name) \
+ do { \
+ v = a->di_##name; \
+ a->di_##name = b->di_##name; \
+ b->di_##name = v; \
+ } while (0)
+
+ DiSwap(p, hdentry);
+ DiSwap(bi, bstart);
+ DiSwap(bi, bend);
+ DiSwap(bi, bwh);
+ DiSwap(bi, bdiropq);
+ /* smp_mb(); */
+
+#undef DiSwap
+}
+
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src)
+{
+ AuRwMustWriteLock(&dst->di_rwsem);
+ AuRwMustWriteLock(&src->di_rwsem);
+
+ dst->di_bstart = src->di_bstart;
+ dst->di_bend = src->di_bend;
+ dst->di_bwh = src->di_bwh;
+ dst->di_bdiropq = src->di_bdiropq;
+ /* smp_mb(); */
+}
+
+int au_di_init(struct dentry *dentry)
+{
+ int err;
+ struct super_block *sb;
+ struct au_dinfo *dinfo;
+
+ err = 0;
+ sb = dentry->d_sb;
+ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
+ if (dinfo) {
+ atomic_set(&dinfo->di_generation, au_sigen(sb));
+ /* smp_mb(); */ /* atomic_set */
+ dentry->d_op = &aufs_dop;
+ dentry->d_fsdata = dinfo;
+ } else
+ err = -ENOMEM;
+
+ return err;
+}
+
+void au_di_fin(struct dentry *dentry)
+{
+ struct au_dinfo *dinfo;
+
+ dinfo = au_di(dentry);
+ AuRwDestroy(&dinfo->di_rwsem);
+ au_di_free(dinfo);
}
int au_di_realloc(struct au_dinfo *dinfo, int nbr)
@@ -175,10 +233,13 @@ void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
void di_read_unlock(struct dentry *d, int flags)
{
if (d->d_inode) {
- if (au_ftest_lock(flags, IW))
+ if (au_ftest_lock(flags, IW)) {
+ au_dbg_verify_dinode(d);
ii_write_unlock(d->d_inode);
- else if (au_ftest_lock(flags, IR))
+ } else if (au_ftest_lock(flags, IR)) {
+ au_dbg_verify_dinode(d);
ii_read_unlock(d->d_inode);
+ }
}
au_rw_read_unlock(&au_di(d)->di_rwsem);
}
@@ -199,6 +260,7 @@ void di_write_lock(struct dentry *d, unsigned int lsc)
void di_write_unlock(struct dentry *d)
{
+ au_dbg_verify_dinode(d);
if (d->d_inode)
ii_write_unlock(d->d_inode);
au_rw_write_unlock(&au_di(d)->di_rwsem);
@@ -295,11 +357,46 @@ void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_dentry)
{
struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
+ struct au_branch *br;
DiMustWriteLock(dentry);
au_hdput(hd);
hd->hd_dentry = h_dentry;
+ if (h_dentry) {
+ br = au_sbr(dentry->d_sb, bindex);
+ hd->hd_id = br->br_id;
+ }
+}
+
+int au_dbrange_test(struct dentry *dentry)
+{
+ int err;
+ aufs_bindex_t bstart, bend;
+
+ err = 0;
+ bstart = au_dbstart(dentry);
+ bend = au_dbend(dentry);
+ if (bstart >= 0)
+ AuDebugOn(bend < 0 && bstart > bend);
+ else {
+ err = -EIO;
+ AuDebugOn(bend >= 0);
+ }
+
+ return err;
+}
+
+int au_digen_test(struct dentry *dentry, unsigned int sigen)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(au_digen(dentry) != sigen
+ || au_iigen_test(dentry->d_inode, sigen)))
+ err = -EIO;
+
+ return err;
}
void au_update_digen(struct dentry *dentry)
diff --git a/ubuntu/aufs/dir.c b/ubuntu/aufs/dir.c
index d97ec02e0eb..f2d9750c42f 100644
--- a/ubuntu/aufs/dir.c
+++ b/ubuntu/aufs/dir.c
@@ -145,8 +145,11 @@ static int do_open_dir(struct file *file, int flags)
FiMustWriteLock(file);
- err = 0;
dentry = file->f_dentry;
+ err = au_alive_dir(dentry);
+ if (unlikely(err))
+ goto out;
+
file->f_version = dentry->d_inode->i_version;
bindex = au_dbstart(dentry);
au_set_fbstart(file, bindex);
@@ -176,6 +179,7 @@ static int do_open_dir(struct file *file, int flags)
au_set_fbstart(file, -1);
au_set_fbend_dir(file, -1);
+out:
return err;
}
@@ -388,7 +392,9 @@ static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir)
err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
if (unlikely(err))
goto out;
- err = au_vdir_init(file);
+ err = au_alive_dir(dentry);
+ if (!err)
+ err = au_vdir_init(file);
di_downgrade_lock(dentry, AuLock_IR);
if (unlikely(err))
goto out_unlock;
diff --git a/ubuntu/aufs/export.c b/ubuntu/aufs/export.c
index 05a9a75c65f..b638ba60098 100644
--- a/ubuntu/aufs/export.c
+++ b/ubuntu/aufs/export.c
@@ -236,7 +236,7 @@ static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
}
spin_unlock(&dcache_lock);
}
- if (unlikely(dentry && sigen != au_digen(dentry))) {
+ if (unlikely(dentry && au_digen_test(dentry, sigen))) {
dput(dentry);
dentry = ERR_PTR(-ESTALE);
}
@@ -292,28 +292,32 @@ static struct vfsmount *au_mnt_get(struct super_block *sb)
struct au_nfsd_si_lock {
unsigned int sigen;
- aufs_bindex_t br_id;
+ aufs_bindex_t bindex, br_id;
unsigned char force_lock;
};
-static aufs_bindex_t si_nfsd_read_lock(struct super_block *sb,
- struct au_nfsd_si_lock *nsi_lock)
+static int si_nfsd_read_lock(struct super_block *sb,
+ struct au_nfsd_si_lock *nsi_lock)
{
+ int err;
aufs_bindex_t bindex;
si_read_lock(sb, AuLock_FLUSH);
/* branch id may be wrapped around */
+ err = 0;
bindex = au_br_index(sb, nsi_lock->br_id);
if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
goto out; /* success */
+ err = -ESTALE;
+ bindex = -1;
if (!nsi_lock->force_lock)
si_read_unlock(sb);
- bindex = -1;
out:
- return bindex;
+ nsi_lock->bindex = bindex;
+ return err;
}
struct find_name_by_ino {
@@ -470,9 +474,8 @@ out:
}
static
-struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
- ino_t ino, __u32 *fh, int fh_len,
- struct au_nfsd_si_lock *nsi_lock)
+struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh,
+ int fh_len, struct au_nfsd_si_lock *nsi_lock)
{
struct dentry *dentry, *h_parent, *root;
struct super_block *h_sb;
@@ -482,8 +485,7 @@ struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
int err;
struct path path;
- br = au_sbr(sb, bindex);
- /* au_br_get(br); */
+ br = au_sbr(sb, nsi_lock->bindex);
h_mnt = br->br_mnt;
h_sb = h_mnt->mnt_sb;
/* todo: call lower fh_to_dentry()? fh_to_parent()? */
@@ -511,7 +513,7 @@ struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
root = sb->s_root;
path.mnt = h_mnt;
di_read_lock_parent(root, !AuLock_IR);
- path.dentry = au_h_dptr(root, bindex);
+ path.dentry = au_h_dptr(root, nsi_lock->bindex);
di_read_unlock(root, !AuLock_IR);
p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
dentry = (void *)p;
@@ -547,7 +549,6 @@ out_pathname:
out_h_parent:
dput(h_parent);
out:
- /* au_br_put(br); */
AuTraceErrPtr(dentry);
return dentry;
}
@@ -560,8 +561,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
{
struct dentry *dentry;
__u32 *fh = fid->raw;
+ struct au_branch *br;
ino_t ino, dir_ino;
- aufs_bindex_t bindex;
struct au_nfsd_si_lock nsi_lock = {
.force_lock = 0
};
@@ -574,8 +575,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
nsi_lock.br_id = fh[Fh_br_id];
/* branch id may be wrapped around */
- bindex = si_nfsd_read_lock(sb, &nsi_lock);
- if (unlikely(bindex < 0))
+ br = NULL;
+ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock)))
goto out;
nsi_lock.force_lock = 1;
@@ -593,6 +594,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto accept;
/* is the parent dir cached? */
+ br = au_sbr(sb, nsi_lock.bindex);
+ atomic_inc(&br->br_count);
dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
if (IS_ERR(dentry))
goto out_unlock;
@@ -600,7 +603,7 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto accept;
/* lookup path */
- dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
+ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock);
if (IS_ERR(dentry))
goto out_unlock;
if (unlikely(!dentry))
@@ -608,12 +611,15 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto out_unlock;
accept:
- if (dentry->d_inode->i_generation == fh[Fh_igen])
+ if (!au_digen_test(dentry, au_sigen(sb))
+ && dentry->d_inode->i_generation == fh[Fh_igen])
goto out_unlock; /* success */
dput(dentry);
dentry = ERR_PTR(-ESTALE);
out_unlock:
+ if (br)
+ atomic_dec(&br->br_count);
si_read_unlock(sb);
out:
AuTraceErrPtr(dentry);
@@ -670,19 +676,21 @@ static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
goto out;
}
- err = -EIO;
h_parent = NULL;
- sb = dentry->d_sb;
- aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR);
- parent = dget_parent(dentry);
- di_read_lock_parent(parent, !AuLock_IR);
+ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+
inode = dentry->d_inode;
AuDebugOn(!inode);
+ sb = dentry->d_sb;
#ifdef CONFIG_AUFS_DEBUG
if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
AuWarn1("NFS-exporting requires xino\n");
#endif
-
+ err = -EIO;
+ parent = dget_parent(dentry);
+ di_read_lock_parent(parent, !AuLock_IR);
bend = au_dbtaildir(parent);
for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
h_parent = au_h_dptr(parent, bindex);
diff --git a/ubuntu/aufs/f_op.c b/ubuntu/aufs/f_op.c
index 829a67e3c2d..ff0f44bd201 100644
--- a/ubuntu/aufs/f_op.c
+++ b/ubuntu/aufs/f_op.c
@@ -37,8 +37,11 @@ int au_do_open_nondir(struct file *file, int flags)
FiMustWriteLock(file);
- err = 0;
dentry = file->f_dentry;
+ err = au_d_alive(dentry);
+ if (unlikely(err))
+ goto out;
+
finfo = au_fi(file);
memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
finfo->fi_hvmop = NULL;
@@ -53,6 +56,8 @@ int au_do_open_nondir(struct file *file, int flags)
/* todo: necessary? */
/* file->f_ra = h_file->f_ra; */
}
+
+out:
return err;
}
@@ -376,7 +381,7 @@ static struct file *au_safe_file(struct vm_area_struct *vma)
struct file *file;
file = vma->vm_file;
- if (file->private_data && au_test_aufs(file->f_dentry->d_sb))
+ if (au_fi(file) && au_test_aufs(file->f_dentry->d_sb))
return file;
return NULL;
}
diff --git a/ubuntu/aufs/file.c b/ubuntu/aufs/file.c
index 15e38ce31c6..2ba0c000f16 100644
--- a/ubuntu/aufs/file.c
+++ b/ubuntu/aufs/file.c
@@ -65,7 +65,7 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
h_file = ERR_PTR(-EACCES);
exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC);
if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC))
- goto out;
+ goto out;
/* drop flags for writing */
if (au_test_ro(sb, bindex, dentry->d_inode))
@@ -202,14 +202,20 @@ static int au_ready_to_write_wh(struct file *file, loff_t len,
aufs_bindex_t bcpup)
{
int err;
- struct inode *inode;
- struct dentry *dentry, *hi_wh;
+ struct inode *inode, *h_inode;
+ struct dentry *dentry, *h_dentry, *hi_wh;
dentry = file->f_dentry;
au_update_dbstart(dentry);
inode = dentry->d_inode;
+ h_inode = NULL;
+ if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ if (h_dentry)
+ h_inode = h_dentry->d_inode;
+ }
hi_wh = au_hi_wh(inode, bcpup);
- if (!hi_wh)
+ if (!hi_wh && !h_inode)
err = au_sio_cpup_wh(dentry, bcpup, len, file);
else
/* already copied-up after unlink */
@@ -229,7 +235,7 @@ static int au_ready_to_write_wh(struct file *file, loff_t len,
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
int err;
- aufs_bindex_t bstart, bcpup;
+ aufs_bindex_t bstart, bcpup, dbstart;
struct dentry *dentry, *parent, *h_dentry;
struct inode *h_inode, *inode;
struct super_block *sb;
@@ -246,7 +252,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out;
}
- /* need to cpup */
+ /* need to cpup or reopen */
parent = dget_parent(dentry);
di_write_lock_parent(parent);
err = AuWbrCopyup(au_sbi(sb), dentry);
@@ -255,7 +261,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out_dgrade;
err = 0;
- if (!au_h_dptr(parent, bcpup)) {
+ if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
err = au_cpup_dirs(dentry, bcpup);
if (unlikely(err))
goto out_dgrade;
@@ -268,25 +274,43 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
h_dentry = au_hf_top(file)->f_dentry;
h_inode = h_dentry->d_inode;
- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
- h_file = au_h_open_pre(dentry, bstart);
- if (IS_ERR(h_file)) {
- err = PTR_ERR(h_file);
- h_file = NULL;
- } else if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
- /* || !h_inode->i_nlink */) {
+ dbstart = au_dbstart(dentry);
+ if (dbstart <= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ AuDebugOn(!h_dentry);
+ h_inode = h_dentry->d_inode;
+ AuDebugOn(!h_inode);
+ bstart = bcpup;
+ }
+
+ if (dbstart <= bcpup /* just reopen */
+ || !d_unhashed(dentry) /* copyup and reopen */
+ ) {
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+ h_file = au_h_open_pre(dentry, bstart);
+ if (IS_ERR(h_file)) {
+ err = PTR_ERR(h_file);
+ h_file = NULL;
+ } else {
+ di_downgrade_lock(parent, AuLock_IR);
+ if (dbstart > bcpup)
+ err = au_sio_cpup_simple(dentry, bcpup, len,
+ AuCpup_DTIME);
+ if (!err)
+ err = au_reopen_nondir(file);
+ }
+ mutex_unlock(&h_inode->i_mutex);
+ au_h_open_post(dentry, bstart, h_file);
+ } else { /* copyup as wh and reopen */
+ /*
+ * since writable hfsplus branch is not supported,
+ * h_open_pre/post() are unnecessary.
+ */
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
err = au_ready_to_write_wh(file, len, bcpup);
di_downgrade_lock(parent, AuLock_IR);
- } else {
- di_downgrade_lock(parent, AuLock_IR);
- if (!au_h_dptr(dentry, bcpup))
- err = au_sio_cpup_simple(dentry, bcpup, len,
- AuCpup_DTIME);
- if (!err)
- err = au_reopen_nondir(file);
+ mutex_unlock(&h_inode->i_mutex);
}
- mutex_unlock(&h_inode->i_mutex);
- au_h_open_post(dentry, bstart, h_file);
if (!err) {
au_pin_set_parent_lflag(pin, /*lflag*/0);
@@ -351,7 +375,7 @@ static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
sb = dentry->d_sb;
inode = dentry->d_inode;
bstart = au_ibstart(inode);
- if (bstart == finfo->fi_btop)
+ if (bstart == finfo->fi_btop || IS_ROOT(dentry))
goto out;
parent = dget_parent(dentry);
@@ -549,16 +573,13 @@ int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
}
AuDbg("sigen %d, figen %d\n", sigen, figen);
- if (sigen != au_digen(dentry)
- || sigen != au_iigen(inode)) {
+ if (au_digen_test(dentry, sigen)) {
err = au_reval_dpath(dentry, sigen);
- if (unlikely(err < 0))
- goto out;
- AuDebugOn(au_digen(dentry) != sigen
- || au_iigen(inode) != sigen);
+ AuDebugOn(!err && au_digen_test(dentry, sigen));
}
- err = refresh_file(file, reopen);
+ if (!err)
+ err = refresh_file(file, reopen);
if (!err) {
if (!wlock) {
di_downgrade_lock(dentry, AuLock_IR);
diff --git a/ubuntu/aufs/hfsnotify.c b/ubuntu/aufs/hfsnotify.c
index 621b5380704..eaed1f12395 100644
--- a/ubuntu/aufs/hfsnotify.c
+++ b/ubuntu/aufs/hfsnotify.c
@@ -25,7 +25,6 @@
/* FS_IN_IGNORED is unnecessary */
static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
| FS_CREATE | FS_EVENT_ON_CHILD);
-static struct fsnotify_group *au_hfsn_group;
static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
static void au_hfsn_free_mark(struct fsnotify_mark *mark)
@@ -38,10 +37,18 @@ static void au_hfsn_free_mark(struct fsnotify_mark *mark)
wake_up_all(&au_hfsn_wq);
}
-static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode)
+static int au_hfsn_alloc(struct au_hinode *hinode)
{
+ struct au_hnotify *hn;
+ struct super_block *sb;
+ struct au_branch *br;
struct fsnotify_mark *mark;
+ aufs_bindex_t bindex;
+ hn = hinode->hi_notify;
+ sb = hn->hn_aufs_inode->i_sb;
+ bindex = au_br_index(sb, hinode->hi_id);
+ br = au_sbr(sb, bindex);
hn->hn_mark_dead = 0;
mark = &hn->hn_mark;
fsnotify_init_mark(mark, au_hfsn_free_mark);
@@ -50,14 +57,16 @@ static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode)
* by udba rename or rmdir, aufs assign a new inode to the known
* h_inode, so specify 1 to allow dups.
*/
- return fsnotify_add_mark(mark, au_hfsn_group, h_inode, /*mnt*/NULL,
- /*allow_dups*/1);
+ return fsnotify_add_mark(mark, br->br_hfsn_group, hinode->hi_inode,
+ /*mnt*/NULL, /*allow_dups*/1);
}
-static void au_hfsn_free(struct au_hnotify *hn)
+static void au_hfsn_free(struct au_hinode *hinode)
{
+ struct au_hnotify *hn;
struct fsnotify_mark *mark;
+ hn = hinode->hi_notify;
mark = &hn->hn_mark;
fsnotify_destroy_mark(mark);
fsnotify_put_mark(mark);
@@ -167,6 +176,7 @@ out:
return err;
}
+/* isn't it waste to ask every registered 'group'? */
/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
/* it should be exported to modules */
static bool au_hfsn_should_send_event(struct fsnotify_group *group,
@@ -186,31 +196,52 @@ static struct fsnotify_ops au_hfsn_ops = {
/* ---------------------------------------------------------------------- */
-static int __init au_hfsn_init(void)
+static void au_hfsn_fin_br(struct au_branch *br)
+{
+ if (br->br_hfsn_group)
+ fsnotify_put_group(br->br_hfsn_group);
+}
+
+static int au_hfsn_init_br(struct au_branch *br, int perm)
+{
+ br->br_hfsn_group = NULL;
+ br->br_hfsn_ops = au_hfsn_ops;
+ return 0;
+}
+
+static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
{
int err;
err = 0;
- au_hfsn_group = fsnotify_alloc_group(&au_hfsn_ops);
- if (IS_ERR(au_hfsn_group)) {
- err = PTR_ERR(au_hfsn_group);
+ if (udba != AuOpt_UDBA_HNOTIFY
+ || !au_br_hnotifyable(perm)) {
+ au_hfsn_fin_br(br);
+ br->br_hfsn_group = NULL;
+ goto out;
+ }
+
+ if (br->br_hfsn_group)
+ goto out;
+
+ br->br_hfsn_group = fsnotify_alloc_group(&br->br_hfsn_ops);
+ if (IS_ERR(br->br_hfsn_group)) {
+ err = PTR_ERR(br->br_hfsn_group);
pr_err("fsnotify_alloc_group() failed, %d\n", err);
+ br->br_hfsn_group = NULL;
}
+out:
AuTraceErr(err);
return err;
}
-static void au_hfsn_fin(void)
-{
- fsnotify_put_group(au_hfsn_group);
-}
-
const struct au_hnotify_op au_hnotify_op = {
.ctl = au_hfsn_ctl,
.alloc = au_hfsn_alloc,
.free = au_hfsn_free,
- .fin = au_hfsn_fin,
- .init = au_hfsn_init
+ .reset_br = au_hfsn_reset_br,
+ .fin_br = au_hfsn_fin_br,
+ .init_br = au_hfsn_init_br
};
diff --git a/ubuntu/aufs/hnotify.c b/ubuntu/aufs/hnotify.c
index 535a5ceeec9..68279f9fa04 100644
--- a/ubuntu/aufs/hnotify.c
+++ b/ubuntu/aufs/hnotify.c
@@ -22,8 +22,7 @@
#include "aufs.h"
-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
- struct inode *h_inode)
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode)
{
int err;
struct au_hnotify *hn;
@@ -32,10 +31,11 @@ int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
hn = au_cache_alloc_hnotify();
if (hn) {
hn->hn_aufs_inode = inode;
- err = au_hnotify_op.alloc(hn, h_inode);
- if (!err)
- hinode->hi_notify = hn;
- else {
+ hinode->hi_notify = hn;
+ err = au_hnotify_op.alloc(hinode);
+ AuTraceErr(err);
+ if (unlikely(err)) {
+ hinode->hi_notify = NULL;
au_cache_free_hnotify(hn);
/*
* The upper dir was removed by udba, but the same named
@@ -48,6 +48,7 @@ int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
}
}
+ AuTraceErr(err);
return err;
}
@@ -57,7 +58,7 @@ void au_hn_free(struct au_hinode *hinode)
hn = hinode->hi_notify;
if (hn) {
- au_hnotify_op.free(hn);
+ au_hnotify_op.free(hinode);
au_cache_free_hnotify(hn);
hinode->hi_notify = NULL;
}
@@ -170,7 +171,6 @@ static int hn_gen_tree(struct dentry *dentry)
if (IS_ROOT(d))
continue;
- d_drop(d);
au_digen_dec(d);
if (d->d_inode)
/* todo: reset children xino?
@@ -216,15 +216,12 @@ static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
&& memcmp(dname->name, name, nlen))
continue;
err = 0;
- spin_lock(&d->d_lock);
- __d_drop(d);
au_digen_dec(d);
- spin_unlock(&d->d_lock);
break;
}
spin_unlock(&dcache_lock);
} else {
- au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS);
+ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
d = d_find_alias(inode);
if (!d) {
au_iigen_dec(inode);
@@ -257,12 +254,11 @@ static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
err = 0;
if (!isdir) {
- d_drop(dentry);
au_digen_dec(dentry);
if (inode)
au_iigen_dec(inode);
} else {
- au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS);
+ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR);
if (inode)
err = hn_gen_tree(dentry);
}
@@ -376,12 +372,12 @@ static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
dname = &d->d_name;
if (dname->len != nlen || memcmp(dname->name, name, nlen))
continue;
- if (!atomic_read(&d->d_count) || !d->d_fsdata) {
- spin_lock(&d->d_lock);
- __d_drop(d);
- spin_unlock(&d->d_lock);
+ if (au_di(d))
+ au_digen_dec(d);
+ else
+ continue;
+ if (!atomic_read(&d->d_count))
continue;
- }
dentry = dget(d);
break;
@@ -498,7 +494,7 @@ static void au_hn_bh(void *_args)
args.h_nlen = a->h_child_nlen;
err = hn_job(&args);
if (dentry) {
- if (dentry->d_fsdata)
+ if (au_di(dentry))
di_write_unlock(dentry);
dput(dentry);
}
@@ -520,12 +516,11 @@ static void au_hn_bh(void *_args)
ii_write_unlock(a->dir);
out:
- au_nwt_done(&sbinfo->si_nowait);
- si_write_unlock(sb);
-
iput(a->h_child_inode);
iput(a->h_dir);
iput(a->dir);
+ si_write_unlock(sb);
+ au_nwt_done(&sbinfo->si_nowait);
kfree(a);
}
@@ -634,6 +629,38 @@ out:
return err;
}
+/* ---------------------------------------------------------------------- */
+
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm)
+{
+ int err;
+
+ AuDebugOn(!(udba & AuOptMask_UDBA));
+
+ err = 0;
+ if (au_hnotify_op.reset_br)
+ err = au_hnotify_op.reset_br(udba, br, perm);
+
+ return err;
+}
+
+int au_hnotify_init_br(struct au_branch *br, int perm)
+{
+ int err;
+
+ err = 0;
+ if (au_hnotify_op.init_br)
+ err = au_hnotify_op.init_br(br, perm);
+
+ return err;
+}
+
+void au_hnotify_fin_br(struct au_branch *br)
+{
+ if (au_hnotify_op.fin_br)
+ au_hnotify_op.fin_br(br);
+}
+
static void au_hn_destroy_cache(void)
{
kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
@@ -647,7 +674,9 @@ int __init au_hnotify_init(void)
err = -ENOMEM;
au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
if (au_cachep[AuCache_HNOTIFY]) {
- err = au_hnotify_op.init();
+ err = 0;
+ if (au_hnotify_op.init)
+ err = au_hnotify_op.init();
if (unlikely(err))
au_hn_destroy_cache();
}
@@ -657,7 +686,8 @@ int __init au_hnotify_init(void)
void au_hnotify_fin(void)
{
- au_hnotify_op.fin();
+ if (au_hnotify_op.fin)
+ au_hnotify_op.fin();
/* cf. au_cache_fin() */
if (au_cachep[AuCache_HNOTIFY])
au_hn_destroy_cache();
diff --git a/ubuntu/aufs/i_op.c b/ubuntu/aufs/i_op.c
index bbda6e4a2f2..dddcaca16a9 100644
--- a/ubuntu/aufs/i_op.c
+++ b/ubuntu/aufs/i_op.c
@@ -95,6 +95,11 @@ static int aufs_permission(struct inode *inode, int mask)
sb = inode->i_sb;
si_read_lock(sb, AuLock_FLUSH);
ii_read_lock_child(inode);
+#if 0
+ err = au_iigen_test(inode, au_sigen(sb));
+ if (unlikely(err))
+ goto out;
+#endif
if (!isdir || write_mask) {
err = au_busy_or_stale();
@@ -170,11 +175,18 @@ static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
if (unlikely(err))
goto out_si;
+ npositive = 0; /* suppress a warning */
parent = dentry->d_parent; /* dir inode is locked */
di_read_lock_parent(parent, AuLock_IR);
- npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, nd);
+ err = au_alive_dir(parent);
+ if (!err)
+ err = au_digen_test(parent, au_sigen(sb));
+ if (!err) {
+ npositive = au_lkup_dentry(dentry, au_dbstart(parent),
+ /*type*/0, nd);
+ err = npositive;
+ }
di_read_unlock(parent, AuLock_IR);
- err = npositive;
ret = ERR_PTR(err);
if (unlikely(err < 0))
goto out_unlock;
@@ -211,10 +223,9 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
struct dentry *h_parent;
struct inode *h_dir;
- if (add_entry) {
- au_update_dbstart(dentry);
+ if (add_entry)
IMustLock(parent->d_inode);
- } else
+ else
di_write_lock_parent(parent);
err = 0;
@@ -231,8 +242,11 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
err = au_lkup_neg(dentry, bcpup);
/* todo: no unlock here */
mutex_unlock(&h_dir->i_mutex);
- if (bstart < bcpup && au_dbstart(dentry) < 0) {
- au_set_dbstart(dentry, 0);
+
+ AuDbg("bcpup %d\n", bcpup);
+ if (!err) {
+ if (!dentry->d_inode)
+ au_set_h_dptr(dentry, bstart, NULL);
au_update_dbrange(dentry, /*do_put_zero*/0);
}
}
@@ -242,6 +256,7 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
if (!err)
err = bcpup; /* success */
+ AuTraceErr(err);
return err;
}
@@ -296,15 +311,22 @@ int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
bcpup = args->force_btgt;
AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
}
+
AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
err = bcpup;
if (bcpup == bstart)
goto out; /* success */
- else if (bstart < bcpup)
- au_update_dbrange(dentry, /*do_put_zero*/1);
/* copyup the new parent into the branch we process */
err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
+ if (err >= 0) {
+ if (!dentry->d_inode) {
+ au_set_h_dptr(dentry, bstart, NULL);
+ au_set_dbstart(dentry, bcpup);
+ au_set_dbend(dentry, bcpup);
+ }
+ AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup));
+ }
out:
dput(parent);
@@ -455,6 +477,7 @@ int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
* unhashed.
* for ->setattr(), ia->ia_file is passed from ftruncate only.
*/
+/* todo: consolidate with do_refresh() and simple_reval_dpath() */
static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
{
int err;
@@ -463,13 +486,10 @@ static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
err = 0;
inode = dentry->d_inode;
- if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) {
+ if (au_digen_test(dentry, sigen)) {
parent = dget_parent(dentry);
di_read_lock_parent(parent, AuLock_IR);
- /* returns a number of positive dentries */
- err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
- if (err >= 0)
- err = au_refresh_hinode(inode, dentry);
+ err = au_refresh_dentry(dentry, parent);
di_read_unlock(parent, AuLock_IR);
dput(parent);
}
@@ -515,7 +535,7 @@ static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
au_fset_wrdir(wr_dir_args.flags, ISDIR);
/* plink or hi_wh() case */
ibstart = au_ibstart(inode);
- if (bstart != ibstart)
+ if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode))
wr_dir_args.force_btgt = ibstart;
err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
if (unlikely(err < 0))
@@ -692,6 +712,8 @@ static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
out_unlock:
mutex_unlock(&a->h_inode->i_mutex);
au_unpin(&a->pin);
+ if (unlikely(err))
+ au_update_dbstart(dentry);
out_dentry:
di_write_unlock(dentry);
if (file) {
@@ -753,12 +775,18 @@ static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
/* support fstat(2) */
if (!au_d_removed(dentry) && !udba_none) {
unsigned int sigen = au_sigen(sb);
- if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
+ err = au_digen_test(dentry, sigen);
+ if (!err) {
di_read_lock_child(dentry, AuLock_IR);
- else {
+ err = au_dbrange_test(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ } else {
AuDebugOn(IS_ROOT(dentry));
di_write_lock_child(dentry);
- err = au_reval_for_attr(dentry, sigen);
+ err = au_dbrange_test(dentry);
+ if (!err)
+ err = au_reval_for_attr(dentry, sigen);
di_downgrade_lock(dentry, AuLock_IR);
if (unlikely(err))
goto out_unlock;
@@ -839,10 +867,15 @@ static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
{
int err;
- aufs_read_lock(dentry, AuLock_IR);
- err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
+ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_hashed_positive(dentry);
+ if (!err)
+ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
aufs_read_unlock(dentry, AuLock_IR);
+out:
return err;
}
@@ -860,11 +893,17 @@ static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
if (unlikely(!buf.k))
goto out;
- aufs_read_lock(dentry, AuLock_IR);
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
- set_fs(old_fs);
+ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out_name;
+
+ err = au_d_hashed_positive(dentry);
+ if (!err) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
+ set_fs(old_fs);
+ }
aufs_read_unlock(dentry, AuLock_IR);
if (err >= 0) {
@@ -873,8 +912,9 @@ static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
nd_set_link(nd, buf.k);
return NULL; /* success */
}
- __putname(buf.k);
+out_name:
+ __putname(buf.k);
out:
path_put(&nd->path);
AuTraceErr(err);
diff --git a/ubuntu/aufs/i_op_add.c b/ubuntu/aufs/i_op_add.c
index 18635718325..cd11360361d 100644
--- a/ubuntu/aufs/i_op_add.c
+++ b/ubuntu/aufs/i_op_add.c
@@ -81,6 +81,18 @@ out:
return err;
}
+static int au_d_may_add(struct dentry *dentry)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(d_unhashed(dentry)))
+ err = -ENOENT;
+ if (unlikely(dentry->d_inode))
+ err = -EEXIST;
+ return err;
+}
+
/*
* simple tests for the adding inode operations.
* following the checks in vfs, plus the parent-child relationship.
@@ -236,13 +248,18 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
IMustLock(dir);
parent = dentry->d_parent; /* dir inode is locked */
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
di_write_lock_parent(parent);
wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
&wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out;
+ goto out_parent;
bstart = au_dbstart(dentry);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -275,19 +292,20 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
err = -EIO;
}
au_dtime_revert(&dt);
- d_drop(dentry);
}
au_unpin(&pin);
dput(wh_dentry);
-out:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -456,19 +474,22 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
inode = src_dentry->d_inode;
IMustLock(inode);
- err = -ENOENT;
- if (unlikely(!inode->i_nlink))
- goto out;
-
err = -ENOMEM;
a = kzalloc(sizeof(*a), GFP_NOFS);
if (unlikely(!a))
goto out;
a->parent = dentry->d_parent; /* dir inode is locked */
- err = aufs_read_and_write_lock2(dentry, src_dentry, AuLock_NOPLM);
+ err = aufs_read_and_write_lock2(dentry, src_dentry,
+ AuLock_NOPLM | AuLock_GEN);
if (unlikely(err))
goto out_kfree;
+ err = au_d_hashed_positive(src_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
a->src_parent = dget_parent(src_dentry);
wr_dir_args.force_btgt = au_dbstart(src_dentry);
@@ -479,7 +500,7 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
&wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_unlock;
+ goto out_parent;
err = 0;
sb = dentry->d_sb;
@@ -539,34 +560,32 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
au_cpup_attr_timesizes(dir);
inc_nlink(inode);
inode->i_ctime = dir->i_ctime;
- if (!d_unhashed(a->h_path.dentry))
- d_instantiate(dentry, au_igrab(inode));
- else
+ d_instantiate(dentry, au_igrab(inode));
+ if (d_unhashed(a->h_path.dentry))
/* some filesystem calls d_drop() */
d_drop(dentry);
goto out_unpin; /* success */
out_revert:
rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
- if (!rerr)
- goto out_dt;
- AuIOErr("%.*s reverting failed(%d, %d)\n",
- AuDLNPair(dentry), err, rerr);
- err = -EIO;
-out_dt:
- d_drop(dentry);
+ if (unlikely(rerr)) {
+ AuIOErr("%.*s reverting failed(%d, %d)\n",
+ AuDLNPair(dentry), err, rerr);
+ err = -EIO;
+ }
au_dtime_revert(&dt);
out_unpin:
au_unpin(&a->pin);
out_wh:
dput(wh_dentry);
+out_parent:
+ di_write_unlock(a->parent);
+ dput(a->src_parent);
out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(a->parent);
- dput(a->src_parent);
aufs_read_and_write_unlock2(dentry, src_dentry);
out_kfree:
kfree(a);
@@ -599,14 +618,20 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (unlikely(!a))
goto out;
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out_free;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+
parent = dentry->d_parent; /* dir inode is locked */
di_write_lock_parent(parent);
wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
&a->pin, &wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_free;
+ goto out_parent;
sb = dentry->d_sb;
bindex = au_dbstart(dentry);
@@ -614,7 +639,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
h_path.mnt = au_sbr_mnt(sb, bindex);
err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
if (unlikely(err))
- goto out_unlock;
+ goto out_unpin;
/* make the dir opaque */
diropq = 0;
@@ -634,7 +659,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err = epilog(dir, bindex, wh_dentry, dentry);
if (!err) {
inc_nlink(dir);
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -658,18 +683,19 @@ out_dir:
AuDLNPair(dentry), err, rerr);
err = -EIO;
}
- d_drop(dentry);
au_dtime_revert(&a->dt);
-out_unlock:
+out_unpin:
au_unpin(&a->pin);
dput(wh_dentry);
-out_free:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out_free:
kfree(a);
out:
return err;
diff --git a/ubuntu/aufs/i_op_del.c b/ubuntu/aufs/i_op_del.c
index 5b31bbd8876..1019bf91aea 100644
--- a/ubuntu/aufs/i_op_del.c
+++ b/ubuntu/aufs/i_op_del.c
@@ -59,24 +59,20 @@ int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
goto out;
need_wh = 1;
} else {
- aufs_bindex_t old_bend, new_bend, bdiropq = -1;
-
- old_bend = au_dbend(dentry);
- if (isdir) {
- bdiropq = au_dbdiropq(dentry);
- au_set_dbdiropq(dentry, -1);
- }
- need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
- /*nd*/NULL);
- err = need_wh;
- if (isdir)
- au_set_dbdiropq(dentry, bdiropq);
- if (unlikely(err < 0))
- goto out;
- new_bend = au_dbend(dentry);
- if (!need_wh && old_bend != new_bend) {
- au_set_h_dptr(dentry, new_bend, NULL);
- au_set_dbend(dentry, old_bend);
+ struct au_dinfo *dinfo, *tmp;
+
+ need_wh = -ENOMEM;
+ dinfo = au_di(dentry);
+ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+ if (tmp) {
+ au_di_cp(tmp, dinfo);
+ au_di_swap(tmp, dinfo);
+ /* returns the number of positive dentries */
+ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
+ /*nd*/NULL);
+ au_di_swap(tmp, dinfo);
+ au_rw_write_unlock(&tmp->di_rwsem);
+ au_di_free(tmp);
}
}
AuDbg("need_wh %d\n", need_wh);
@@ -268,10 +264,6 @@ static void epilog(struct inode *dir, struct dentry *dentry,
d_drop(dentry);
inode->i_ctime = dir->i_ctime;
- if (atomic_read(&dentry->d_count) == 1) {
- au_set_h_dptr(dentry, au_dbstart(dentry), NULL);
- au_update_dbstart(dentry);
- }
if (au_ibstart(dir) == bindex)
au_cpup_attr_timesizes(dir);
dir->i_version++;
@@ -315,22 +307,28 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
struct dentry *parent, *wh_dentry;
IMustLock(dir);
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_hashed_positive(dentry);
+ if (unlikely(err))
+ goto out_unlock;
inode = dentry->d_inode;
- if (unlikely(!inode))
- return -ENOENT; /* possible? */
IMustLock(inode);
-
- aufs_read_lock(dentry, AuLock_DW);
- parent = dentry->d_parent; /* dir inode is locked */
- di_write_lock_parent(parent);
+ err = -EISDIR;
+ if (unlikely(S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
bindex = -1;
+ parent = dentry->d_parent; /* dir inode is locked */
+ di_write_lock_parent(parent);
wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out;
+ goto out_parent;
h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -356,7 +354,7 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
} else
/* todo: this timestamp may be reverted later */
inode->i_ctime = h_dir->i_ctime;
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -368,13 +366,15 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
err = rerr;
}
-out_unlock:
+out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_path.dentry);
-out:
+out_parent:
di_write_unlock(parent);
+out_unlock:
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -389,13 +389,22 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
struct au_whtmp_rmdir *args;
IMustLock(dir);
- inode = dentry->d_inode;
- err = -ENOENT; /* possible? */
- if (unlikely(!inode))
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
+ if (unlikely(err))
goto out;
+
+ /* VFS already unhashes it */
+ inode = dentry->d_inode;
+ err = -ENOENT;
+ if (unlikely(!inode || !inode->i_nlink
+ || IS_DEADDIR(inode)))
+ goto out_unlock;
IMustLock(inode);
+ err = -ENOTDIR;
+ if (unlikely(!S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
- aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
err = -ENOMEM;
args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
if (unlikely(!args))
@@ -405,7 +414,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
di_write_lock_parent(parent);
err = au_test_empty(dentry, &args->whlist);
if (unlikely(err))
- goto out_args;
+ goto out_parent;
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
@@ -413,7 +422,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_args;
+ goto out_parent;
h_dentry = au_h_dptr(dentry, bstart);
dget(h_dentry);
@@ -434,7 +443,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
}
if (!err) {
- clear_nlink(inode);
+ vfsub_dead_dir(inode);
au_set_dbdiropq(dentry, -1);
epilog(dir, dentry, bindex);
@@ -460,7 +469,7 @@ out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_dentry);
-out_args:
+out_parent:
di_write_unlock(parent);
if (args)
au_whtmp_rmdir_free(args);
diff --git a/ubuntu/aufs/i_op_ren.c b/ubuntu/aufs/i_op_ren.c
index 89efe679fea..e1d23928cf7 100644
--- a/ubuntu/aufs/i_op_ren.c
+++ b/ubuntu/aufs/i_op_ren.c
@@ -79,7 +79,7 @@ struct au_ren_args {
struct au_hinode *src_hinode;
struct path h_path;
struct au_nhash whlist;
- aufs_bindex_t btgt;
+ aufs_bindex_t btgt, src_bwh, src_bdiropq;
unsigned int flags;
@@ -110,6 +110,7 @@ static void au_ren_rev_diropq(int err, struct au_ren_args *a)
au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
rerr = au_diropq_remove(a->src_dentry, a->btgt);
au_hn_imtx_unlock(a->src_hinode);
+ au_set_dbdiropq(a->src_dentry, a->src_bdiropq);
if (rerr)
RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
}
@@ -180,31 +181,10 @@ static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
a->h_path.dentry = a->src_wh_dentry;
rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
+ au_set_dbwh(a->src_dentry, a->src_bwh);
if (rerr)
RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry));
}
-
-static void au_ren_rev_drop(struct au_ren_args *a)
-{
- struct dentry *d, *h_d;
- int i;
- aufs_bindex_t bend, bindex;
-
- for (i = 0; i < AuSrcDst; i++) {
- d = a->sd[i].dentry;
- d_drop(d);
- bend = au_dbend(d);
- for (bindex = au_dbstart(d); bindex <= bend; bindex++) {
- h_d = au_h_dptr(d, bindex);
- if (h_d)
- d_drop(h_d);
- }
- }
-
- au_update_dbstart(a->dst_dentry);
- if (a->thargs)
- d_drop(a->h_dst);
-}
#undef RevertFailure
/* ---------------------------------------------------------------------- */
@@ -254,6 +234,9 @@ static int au_ren_or_cpup(struct au_ren_args *a)
au_set_dbstart(d, a->src_bstart);
}
}
+ if (!err && a->h_dst)
+ /* it will be set to dinfo later */
+ dget(a->h_dst);
return err;
}
@@ -292,6 +275,7 @@ static int au_ren_diropq(struct au_ren_args *a)
struct dentry *diropq;
err = 0;
+ a->src_bdiropq = au_dbdiropq(a->src_dentry);
a->src_hinode = au_hi(a->src_inode, a->btgt);
au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
diropq = au_diropq_create(a->src_dentry, a->btgt);
@@ -320,6 +304,8 @@ static int do_rename(struct au_ren_args *a)
/* create whiteout for src_dentry */
if (au_ftest_ren(a->flags, WHSRC)) {
+ a->src_bwh = au_dbwh(a->src_dentry);
+ AuDebugOn(a->src_bwh >= 0);
a->src_wh_dentry
= au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
err = PTR_ERR(a->src_wh_dentry);
@@ -425,6 +411,7 @@ out_rename:
au_ren_rev_rename(err, a);
else
au_ren_rev_cpup(err, a);
+ dput(a->h_dst);
out_whtmp:
if (a->thargs)
au_ren_rev_whtmp(err, a);
@@ -434,7 +421,6 @@ out_whdst:
out_whsrc:
if (a->src_wh_dentry)
au_ren_rev_whsrc(err, a);
- au_ren_rev_drop(a);
out_success:
dput(a->src_wh_dentry);
dput(a->dst_wh_dentry);
@@ -685,11 +671,8 @@ static void au_ren_refresh_dir(struct au_ren_args *a)
/* is this updating defined in POSIX? */
au_cpup_attr_timesizes(a->src_inode);
au_cpup_attr_nlink(dir, /*force*/1);
- if (a->dst_inode) {
- clear_nlink(a->dst_inode);
- au_cpup_attr_timesizes(a->dst_inode);
- }
}
+
if (au_ibstart(dir) == a->btgt)
au_cpup_attr_timesizes(dir);
@@ -711,6 +694,31 @@ static void au_ren_refresh(struct au_ren_args *a)
struct inode *i, *h_i;
struct super_block *sb;
+ d = a->dst_dentry;
+ d_drop(d);
+ if (a->h_dst)
+ /* already dget-ed by au_ren_or_cpup() */
+ au_set_h_dptr(d, a->btgt, a->h_dst);
+
+ i = a->dst_inode;
+ if (i) {
+ if (!au_ftest_ren(a->flags, ISDIR))
+ vfsub_drop_nlink(i);
+ else {
+ vfsub_dead_dir(i);
+ au_cpup_attr_timesizes(i);
+ }
+ au_update_dbrange(d, /*do_put_zero*/1);
+ } else {
+ bend = a->btgt;
+ for (bindex = au_dbstart(d); bindex < bend; bindex++)
+ au_set_h_dptr(d, bindex, NULL);
+ bend = au_dbend(d);
+ for (bindex = a->btgt + 1; bindex <= bend; bindex++)
+ au_set_h_dptr(d, bindex, NULL);
+ au_update_dbrange(d, /*do_put_zero*/0);
+ }
+
d = a->src_dentry;
au_set_dbwh(d, -1);
bend = au_dbend(d);
@@ -866,7 +874,7 @@ int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
}
err = -ENOTDIR;
- flags = AuLock_FLUSH | AuLock_NOPLM;
+ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN;
if (S_ISDIR(a->src_inode->i_mode)) {
au_fset_ren(a->flags, ISDIR);
if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode)))
@@ -879,13 +887,33 @@ int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
if (unlikely(err))
goto out_free;
+ err = au_d_hashed_positive(a->src_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ err = -ENOENT;
+ if (a->dst_inode) {
+ /*
+ * If it is a dir, VFS unhash dst_dentry before this
+ * function. It means we cannot rely upon d_unhashed().
+ */
+ if (unlikely(!a->dst_inode->i_nlink))
+ goto out_unlock;
+ if (!S_ISDIR(a->dst_inode->i_mode)) {
+ err = au_d_hashed_positive(a->dst_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ } else if (unlikely(IS_DEADDIR(a->dst_inode)))
+ goto out_unlock;
+ } else if (unlikely(d_unhashed(a->dst_dentry)))
+ goto out_unlock;
+
au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
di_write_lock_parent(a->dst_parent);
/* which branch we process */
err = au_ren_wbr(a);
if (unlikely(err < 0))
- goto out_unlock;
+ goto out_parent;
a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
a->h_path.mnt = a->br->br_mnt;
@@ -959,17 +987,24 @@ out_hdir:
au_ren_unlock(a);
out_children:
au_nhash_wh_free(&a->whlist);
-out_unlock:
- if (unlikely(err && au_ftest_ren(a->flags, ISDIR))) {
- au_update_dbstart(a->dst_dentry);
- d_drop(a->dst_dentry);
+ if (err && a->dst_inode && a->dst_bstart != a->btgt) {
+ AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt);
+ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
+ au_set_dbstart(a->dst_dentry, a->dst_bstart);
}
+out_parent:
if (!err)
d_move(a->src_dentry, a->dst_dentry);
+ else {
+ au_update_dbstart(a->dst_dentry);
+ if (!a->dst_inode)
+ d_drop(a->dst_dentry);
+ }
if (au_ftest_ren(a->flags, ISSAMEDIR))
di_write_unlock(a->dst_parent);
else
di_write_unlock2(a->src_parent, a->dst_parent);
+out_unlock:
aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
out_free:
iput(a->dst_inode);
diff --git a/ubuntu/aufs/iinfo.c b/ubuntu/aufs/iinfo.c
index 6bccfdf18e4..571b21d25fc 100644
--- a/ubuntu/aufs/iinfo.c
+++ b/ubuntu/aufs/iinfo.c
@@ -75,6 +75,9 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
struct super_block *sb = inode->i_sb;
struct au_branch *br;
+ AuDebugOn(inode->i_mode
+ && (h_inode->i_mode & S_IFMT)
+ != (inode->i_mode & S_IFMT));
if (bindex == iinfo->ii_bstart)
au_cpup_igen(inode, h_inode);
br = au_sbr(sb, bindex);
@@ -88,7 +91,7 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
if (au_ftest_hi(flags, HNOTIFY)
&& au_br_hnotifyable(br->br_perm)) {
- err = au_hn_alloc(hinode, inode, h_inode);
+ err = au_hn_alloc(hinode, inode);
if (unlikely(err))
AuIOErr1("au_hn_alloc() %d\n", err);
}
@@ -117,16 +120,15 @@ void au_update_iigen(struct inode *inode)
void au_update_ibrange(struct inode *inode, int do_put_zero)
{
struct au_iinfo *iinfo;
+ aufs_bindex_t bindex, bend;
iinfo = au_ii(inode);
- if (!iinfo || iinfo->ii_bstart < 0)
+ if (!iinfo)
return;
IiMustWriteLock(inode);
- if (do_put_zero) {
- aufs_bindex_t bindex;
-
+ if (do_put_zero && iinfo->ii_bstart >= 0) {
for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
bindex++) {
struct inode *h_i;
@@ -138,20 +140,20 @@ void au_update_ibrange(struct inode *inode, int do_put_zero)
}
iinfo->ii_bstart = -1;
- while (++iinfo->ii_bstart <= iinfo->ii_bend)
- if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode)
- break;
- if (iinfo->ii_bstart > iinfo->ii_bend) {
- iinfo->ii_bstart = -1;
- iinfo->ii_bend = -1;
- return;
- }
-
- iinfo->ii_bend++;
- while (0 <= --iinfo->ii_bend)
- if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode)
+ iinfo->ii_bend = -1;
+ bend = au_sbend(inode->i_sb);
+ for (bindex = 0; bindex <= bend; bindex++)
+ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+ iinfo->ii_bstart = bindex;
break;
- AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0);
+ }
+ if (iinfo->ii_bstart >= 0)
+ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--)
+ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+ iinfo->ii_bend = bindex;
+ break;
+ }
+ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend);
}
/* ---------------------------------------------------------------------- */
diff --git a/ubuntu/aufs/inode.c b/ubuntu/aufs/inode.c
index fe4ee9bd626..9fe4d50e20f 100644
--- a/ubuntu/aufs/inode.c
+++ b/ubuntu/aufs/inode.c
@@ -39,37 +39,39 @@ static void au_refresh_hinode_attr(struct inode *inode, int do_version)
inode->i_version++;
}
-int au_refresh_hinode_self(struct inode *inode, int do_attr)
+static int au_ii_refresh(struct inode *inode, int *update)
{
int err, e;
+ umode_t type;
aufs_bindex_t bindex, new_bindex;
- unsigned char update;
- struct au_hinode *p, *q, tmp;
struct super_block *sb;
struct au_iinfo *iinfo;
+ struct au_hinode *p, *q, tmp;
IiMustWriteLock(inode);
- update = 0;
+ *update = 0;
sb = inode->i_sb;
+ type = inode->i_mode & S_IFMT;
iinfo = au_ii(inode);
err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
if (unlikely(err))
goto out;
+ AuDebugOn(iinfo->ii_bstart < 0);
p = iinfo->ii_hinode + iinfo->ii_bstart;
- err = 0;
for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
bindex++, p++) {
if (!p->hi_inode)
continue;
+ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
new_bindex = au_br_index(sb, p->hi_id);
if (new_bindex == bindex)
continue;
if (new_bindex < 0) {
- update = 1;
+ *update = 1;
au_hiput(p);
p->hi_inode = NULL;
continue;
@@ -93,30 +95,43 @@ int au_refresh_hinode_self(struct inode *inode, int do_attr)
e = au_dy_irefresh(inode);
if (unlikely(e && !err))
err = e;
- if (do_attr)
- au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
out:
+ AuTraceErr(err);
+ return err;
+}
+
+int au_refresh_hinode_self(struct inode *inode)
+{
+ int err, update;
+
+ err = au_ii_refresh(inode, &update);
+ if (!err)
+ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
+
+ AuTraceErr(err);
return err;
}
int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
{
- int err, e;
+ int err, e, update;
unsigned int flags;
+ umode_t mode;
aufs_bindex_t bindex, bend;
- unsigned char isdir, update;
+ unsigned char isdir;
struct au_hinode *p;
struct au_iinfo *iinfo;
- err = au_refresh_hinode_self(inode, /*do_attr*/0);
+ err = au_ii_refresh(inode, &update);
if (unlikely(err))
goto out;
update = 0;
iinfo = au_ii(inode);
p = iinfo->ii_hinode + iinfo->ii_bstart;
- isdir = S_ISDIR(inode->i_mode);
+ mode = (inode->i_mode & S_IFMT);
+ isdir = S_ISDIR(mode);
flags = au_hi_flags(inode, isdir);
bend = au_dbend(dentry);
for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
@@ -127,6 +142,7 @@ int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
if (!h_d || !h_d->d_inode)
continue;
+ AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT));
if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
h_i = au_h_iptr(inode, bindex);
if (h_i) {
@@ -147,7 +163,8 @@ int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
e = au_dy_irefresh(inode);
if (unlikely(e && !err))
err = e;
- au_refresh_hinode_attr(inode, update && isdir);
+ if (!err)
+ au_refresh_hinode_attr(inode, update && isdir);
out:
AuTraceErr(err);
@@ -227,15 +244,18 @@ out:
return err;
}
-/* successful returns with iinfo write_locked */
-static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
+/*
+ * successful returns with iinfo write_locked
+ * minus: errno
+ * zero: success, matched
+ * plus: no error, but unmatched
+ */
+static int reval_inode(struct inode *inode, struct dentry *dentry)
{
int err;
aufs_bindex_t bindex, bend;
struct inode *h_inode, *h_dinode;
- *matched = 0;
-
/*
* before this function, if aufs got any iinfo lock, it must be only
* one, the parent dir.
@@ -245,16 +265,15 @@ static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
if (unlikely(inode->i_ino == parent_ino(dentry)))
goto out;
- err = 0;
+ err = 1;
ii_write_lock_new_child(inode);
h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode;
bend = au_ibend(inode);
for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
h_inode = au_h_iptr(inode, bindex);
if (h_inode && h_inode == h_dinode) {
- *matched = 1;
err = 0;
- if (au_iigen(inode) != au_digen(dentry))
+ if (au_iigen_test(inode, au_digen(dentry)))
err = au_refresh_hinode(inode, dentry);
break;
}
@@ -307,7 +326,7 @@ struct inode *au_new_inode(struct dentry *dentry, int must_new)
struct super_block *sb;
struct mutex *mtx;
ino_t h_ino, ino;
- int err, match;
+ int err;
aufs_bindex_t bstart;
sb = dentry->d_sb;
@@ -355,23 +374,33 @@ new_ino:
goto out; /* success */
}
- ii_write_unlock(inode);
+ /*
+ * iget_failed() calls iput(), but we need to call
+ * ii_write_unlock() after iget_failed(). so dirty hack for
+ * i_count.
+ */
+ atomic_inc(&inode->i_count);
iget_failed(inode);
- goto out_err;
- } else if (!must_new) {
+ ii_write_unlock(inode);
+ au_xino_write(sb, bstart, h_ino, /*ino*/0);
+ /* ignore this error */
+ goto out_iput;
+ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
/*
* horrible race condition between lookup, readdir and copyup
* (or something).
*/
if (mtx)
mutex_unlock(mtx);
- err = reval_inode(inode, dentry, &match);
+ err = reval_inode(inode, dentry);
+ if (unlikely(err < 0)) {
+ mtx = NULL;
+ goto out_iput;
+ }
+
if (!err) {
mtx = NULL;
goto out; /* success */
- } else if (match) {
- mtx = NULL;
- goto out_iput;
} else if (mtx)
mutex_lock(mtx);
}
@@ -392,7 +421,6 @@ new_ino:
out_iput:
iput(inode);
-out_err:
inode = ERR_PTR(err);
out:
if (mtx)
diff --git a/ubuntu/aufs/inode.h b/ubuntu/aufs/inode.h
index ecb91be37d2..9f004a03d93 100644
--- a/ubuntu/aufs/inode.h
+++ b/ubuntu/aufs/inode.h
@@ -109,7 +109,7 @@ static inline struct au_iinfo *au_ii(struct inode *inode)
/* inode.c */
struct inode *au_igrab(struct inode *inode);
-int au_refresh_hinode_self(struct inode *inode, int do_attr);
+int au_refresh_hinode_self(struct inode *inode);
int au_refresh_hinode(struct inode *inode, struct dentry *dentry);
int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
unsigned int d_type, ino_t *ino);
@@ -305,6 +305,13 @@ AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
/* ---------------------------------------------------------------------- */
+static inline void au_icntnr_init(struct au_icntnr *c)
+{
+#ifdef CONFIG_AUFS_DEBUG
+ c->vfs_inode.i_mode = 0;
+#endif
+}
+
static inline unsigned int au_iigen(struct inode *inode)
{
return atomic_read(&au_ii(inode)->ii_generation);
@@ -324,9 +331,18 @@ static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
static inline void au_iigen_dec(struct inode *inode)
{
-#ifdef CONFIG_AUFS_HNOTIFY
atomic_dec(&au_ii(inode)->ii_generation);
-#endif
+}
+
+static inline int au_iigen_test(struct inode *inode, unsigned int sigen)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(inode && au_iigen(inode) != sigen))
+ err = -EIO;
+
+ return err;
}
/* ---------------------------------------------------------------------- */
@@ -436,24 +452,31 @@ static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
/* ---------------------------------------------------------------------- */
+struct au_branch;
#ifdef CONFIG_AUFS_HNOTIFY
struct au_hnotify_op {
void (*ctl)(struct au_hinode *hinode, int do_set);
- int (*alloc)(struct au_hnotify *hn, struct inode *h_inode);
- void (*free)(struct au_hnotify *hn);
+ int (*alloc)(struct au_hinode *hinode);
+ void (*free)(struct au_hinode *hinode);
void (*fin)(void);
int (*init)(void);
+
+ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm);
+ void (*fin_br)(struct au_branch *br);
+ int (*init_br)(struct au_branch *br, int perm);
};
/* hnotify.c */
-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
- struct inode *h_inode);
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode);
void au_hn_free(struct au_hinode *hinode);
void au_hn_ctl(struct au_hinode *hinode, int do_set);
void au_hn_reset(struct inode *inode, unsigned int flags);
int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
struct qstr *h_child_qstr, struct inode *h_child_inode);
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm);
+int au_hnotify_init_br(struct au_branch *br, int perm);
+void au_hnotify_fin_br(struct au_branch *br);
int __init au_hnotify_init(void);
void au_hnotify_fin(void);
@@ -469,8 +492,7 @@ void au_hn_init(struct au_hinode *hinode)
#else
static inline
int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
- struct inode *inode __maybe_unused,
- struct inode *h_inode __maybe_unused)
+ struct inode *inode __maybe_unused)
{
return -EOPNOTSUPP;
}
@@ -480,6 +502,12 @@ AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
int do_set __maybe_unused)
AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
unsigned int flags __maybe_unused)
+AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused,
+ struct au_branch *br __maybe_unused,
+ int perm __maybe_unused)
+AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused,
+ int perm __maybe_unused)
+AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused)
AuStubInt0(__init au_hnotify_init, void)
AuStubVoid(au_hnotify_fin, void)
AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
diff --git a/ubuntu/aufs/opts.c b/ubuntu/aufs/opts.c
index bdb2712f628..b41f5a1944c 100644
--- a/ubuntu/aufs/opts.c
+++ b/ubuntu/aufs/opts.c
@@ -299,7 +299,7 @@ static int au_wbr_mfs_sec(substring_t *arg, char *str,
int n, err;
err = 0;
- if (!match_int(arg, &n) && 0 <= n && n <= MAX_SEC_IN_JIFFIES)
+ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
create->mfs_second = n;
else {
pr_err("bad integer in %s\n", str);
@@ -334,7 +334,7 @@ au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
/*FALLTHROUGH*/
case AuWbrCreate_MFS:
case AuWbrCreate_PMFS:
- create->mfs_second = AUFS_MFS_SECOND_DEF;
+ create->mfs_second = AUFS_MFS_DEF_SEC;
break;
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFSV:
@@ -929,9 +929,16 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
break;
case Opt_rdcache:
- if (unlikely(match_int(&a->args[0], &opt->rdcache)
- || opt->rdcache > MAX_SEC_IN_JIFFIES))
+ if (unlikely(match_int(&a->args[0], &n))) {
+ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ if (unlikely(n > AUFS_RDCACHE_MAX)) {
+ pr_err("rdcache must be smaller than %d\n",
+ AUFS_RDCACHE_MAX);
break;
+ }
+ opt->rdcache = n;
err = 0;
opt->type = token;
break;
@@ -1265,8 +1272,7 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
au_ftest_opts(opts->flags, REMOUNT));
if (!err) {
err = 1;
- au_fset_opts(opts->flags, REFRESH_DIR);
- au_fset_opts(opts->flags, REFRESH_NONDIR);
+ au_fset_opts(opts->flags, REFRESH);
}
break;
@@ -1277,8 +1283,7 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
if (!err) {
err = 1;
au_fset_opts(opts->flags, TRUNC_XIB);
- au_fset_opts(opts->flags, REFRESH_DIR);
- au_fset_opts(opts->flags, REFRESH_NONDIR);
+ au_fset_opts(opts->flags, REFRESH);
}
break;
@@ -1289,10 +1294,8 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
&do_refresh);
if (!err) {
err = 1;
- if (do_refresh) {
- au_fset_opts(opts->flags, REFRESH_DIR);
- au_fset_opts(opts->flags, REFRESH_NONDIR);
- }
+ if (do_refresh)
+ au_fset_opts(opts->flags, REFRESH);
}
break;
}
@@ -1451,10 +1454,11 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
{
int err;
unsigned int tmp;
- aufs_bindex_t bend;
+ aufs_bindex_t bindex, bend;
struct au_opt *opt;
struct au_opt_xino *opt_xino, xino;
struct au_sbinfo *sbinfo;
+ struct au_branch *br;
SiMustWriteLock(sb);
@@ -1515,8 +1519,18 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
}
/* restore udba */
+ tmp &= AuOptMask_UDBA;
sbinfo->si_mntflags &= ~AuOptMask_UDBA;
- sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA);
+ sbinfo->si_mntflags |= tmp;
+ bend = au_sbend(sb);
+ for (bindex = 0; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ err = au_hnotify_reset_br(tmp, br, br->br_perm);
+ if (unlikely(err))
+ AuIOErr("hnotify failed on br %d, %d, ignored\n",
+ bindex, err);
+ /* go on even if err */
+ }
if (au_opt_test(tmp, UDBA_HNOTIFY)) {
struct inode *dir = sb->s_root->d_inode;
au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
@@ -1565,9 +1579,9 @@ int au_opts_remount(struct super_block *sb, struct au_opts *opts)
}
/* will be handled by the caller */
- if (!au_ftest_opts(opts->flags, REFRESH_DIR)
+ if (!au_ftest_opts(opts->flags, REFRESH)
&& (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
- au_fset_opts(opts->flags, REFRESH_DIR);
+ au_fset_opts(opts->flags, REFRESH);
AuDbg("status 0x%x\n", opts->flags);
return err;
diff --git a/ubuntu/aufs/opts.h b/ubuntu/aufs/opts.h
index 03ce3351c49..e788621447d 100644
--- a/ubuntu/aufs/opts.h
+++ b/ubuntu/aufs/opts.h
@@ -170,10 +170,9 @@ struct au_opt {
/* opts flags */
#define AuOpts_REMOUNT 1
-#define AuOpts_REFRESH_DIR (1 << 1)
-#define AuOpts_REFRESH_NONDIR (1 << 2)
-#define AuOpts_TRUNC_XIB (1 << 3)
-#define AuOpts_REFRESH_DYAOP (1 << 4)
+#define AuOpts_REFRESH (1 << 1)
+#define AuOpts_TRUNC_XIB (1 << 2)
+#define AuOpts_REFRESH_DYAOP (1 << 3)
#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
#define au_fset_opts(flags, name) \
do { (flags) |= AuOpts_##name; } while (0)
diff --git a/ubuntu/aufs/plink.c b/ubuntu/aufs/plink.c
index dd7eb1e49f9..d3995bcf5a5 100644
--- a/ubuntu/aufs/plink.c
+++ b/ubuntu/aufs/plink.c
@@ -67,10 +67,8 @@ int au_plink_maint(struct super_block *sb, int flags)
goto out;
if (au_ftest_lock(flags, NOPLMW)) {
- /*
- * todo: debug by lockdep, if there is no i_mutex lock in VFS,
- * we don't need to wait.
- */
+ /* if there is no i_mutex lock in VFS, we don't need to wait */
+ /* AuDebugOn(!lockdep_depth(current)); */
while (sbi->si_plink_maint_pid) {
si_read_unlock(sb);
/* gave up wake_up_bit() */
diff --git a/ubuntu/aufs/rdu.c b/ubuntu/aufs/rdu.c
index fedbc384a1a..627232894e0 100644
--- a/ubuntu/aufs/rdu.c
+++ b/ubuntu/aufs/rdu.c
@@ -162,14 +162,14 @@ static int au_rdu(struct file *file, struct aufs_rdu *rdu)
if (unlikely(err))
goto out;
#endif
- err = -ENOENT;
- if (unlikely(IS_DEADDIR(inode)))
- goto out_mtx;
arg.sb = inode->i_sb;
err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
if (unlikely(err))
goto out_mtx;
+ err = au_alive_dir(dentry);
+ if (unlikely(err))
+ goto out_si;
/* todo: reval? */
fi_read_lock(file);
@@ -215,6 +215,7 @@ static int au_rdu(struct file *file, struct aufs_rdu *rdu)
out_unlock:
fi_read_unlock(file);
+out_si:
si_read_unlock(arg.sb);
out_mtx:
mutex_unlock(&inode->i_mutex);
diff --git a/ubuntu/aufs/sbinfo.c b/ubuntu/aufs/sbinfo.c
index 1eefcb816b3..42783dcd873 100644
--- a/ubuntu/aufs/sbinfo.c
+++ b/ubuntu/aufs/sbinfo.c
@@ -87,7 +87,6 @@ int au_si_alloc(struct super_block *sb)
INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
atomic_long_set(&sbinfo->si_ninodes, 0);
-
atomic_long_set(&sbinfo->si_nfiles, 0);
sbinfo->si_bend = -1;
@@ -221,15 +220,26 @@ int si_write_lock(struct super_block *sb, int flags)
int aufs_read_lock(struct dentry *dentry, int flags)
{
int err;
+ struct super_block *sb;
+
+ sb = dentry->d_sb;
+ err = si_read_lock(sb, flags);
+ if (unlikely(err))
+ goto out;
+
+ if (au_ftest_lock(flags, DW))
+ di_write_lock_child(dentry);
+ else
+ di_read_lock_child(dentry, flags);
- err = si_read_lock(dentry->d_sb, flags);
- if (!err) {
- if (au_ftest_lock(flags, DW))
- di_write_lock_child(dentry);
- else
- di_read_lock_child(dentry, flags);
+ if (au_ftest_lock(flags, GEN)) {
+ err = au_digen_test(dentry, au_sigen(sb));
+ AuDebugOn(!err && au_dbrange_test(dentry));
+ if (unlikely(err))
+ aufs_read_unlock(dentry, flags);
}
+out:
return err;
}
@@ -257,10 +267,29 @@ void aufs_write_unlock(struct dentry *dentry)
int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
{
int err;
+ unsigned int sigen;
+ struct super_block *sb;
+
+ sb = d1->d_sb;
+ err = si_read_lock(sb, flags);
+ if (unlikely(err))
+ goto out;
- err = si_read_lock(d1->d_sb, flags);
- if (!err)
- di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
+ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
+
+ if (au_ftest_lock(flags, GEN)) {
+ sigen = au_sigen(sb);
+ err = au_digen_test(d1, sigen);
+ AuDebugOn(!err && au_dbrange_test(d1));
+ if (!err) {
+ err = au_digen_test(d2, sigen);
+ AuDebugOn(!err && au_dbrange_test(d2));
+ }
+ if (unlikely(err))
+ aufs_read_and_write_unlock2(d1, d2);
+ }
+
+out:
return err;
}
diff --git a/ubuntu/aufs/super.c b/ubuntu/aufs/super.c
index 7aba5f24309..008702ddecb 100644
--- a/ubuntu/aufs/super.c
+++ b/ubuntu/aufs/super.c
@@ -38,6 +38,7 @@ static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
c = au_cache_alloc_icntnr();
if (c) {
+ au_icntnr_init(c);
c->vfs_inode.i_version = 1; /* sigen(sb); */
c->iinfo.ii_hinode = NULL;
return &c->vfs_inode;
@@ -196,7 +197,7 @@ out:
/* seq_file will re-call me in case of too long string */
static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
{
- int err, n;
+ int err;
unsigned int mnt_flags, v;
struct super_block *sb;
struct au_sbinfo *sbinfo;
@@ -254,8 +255,8 @@ static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
- n = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
- AuUInt(RDCACHE, rdcache, n);
+ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
+ AuUInt(RDCACHE, rdcache, v);
AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
@@ -476,92 +477,84 @@ void au_iarray_free(struct inode **a, unsigned long long max)
/*
* refresh dentry and inode at remount time.
*/
-static int do_refresh(struct dentry *dentry, mode_t type,
- unsigned int dir_flags)
+/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */
+static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags,
+ struct dentry *parent)
{
int err;
- struct dentry *parent;
di_write_lock_child(dentry);
- parent = dget_parent(dentry);
di_read_lock_parent(parent, AuLock_IR);
-
- /* returns the number of positive dentries */
- err = au_refresh_hdentry(dentry, type);
- if (err >= 0) {
- struct inode *inode = dentry->d_inode;
- err = au_refresh_hinode(inode, dentry);
- if (!err && type == S_IFDIR)
- au_hn_reset(inode, dir_flags);
- }
- if (unlikely(err))
- pr_err("unrecoverable error %d, %.*s\n",
- err, AuDLNPair(dentry));
-
+ err = au_refresh_dentry(dentry, parent);
+ if (!err && dir_flags)
+ au_hn_reset(dentry->d_inode, dir_flags);
di_read_unlock(parent, AuLock_IR);
- dput(parent);
di_write_unlock(dentry);
return err;
}
-static int test_dir(struct dentry *dentry, void *arg __maybe_unused)
+static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
+ struct au_sbinfo *sbinfo,
+ const unsigned int dir_flags)
{
- return S_ISDIR(dentry->d_inode->i_mode);
+ int err;
+ struct dentry *parent;
+ struct inode *inode;
+
+ err = 0;
+ parent = dget_parent(dentry);
+ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) {
+ inode = dentry->d_inode;
+ if (inode) {
+ if (!S_ISDIR(inode->i_mode))
+ err = au_do_refresh(dentry, /*dir_flags*/0,
+ parent);
+ else {
+ err = au_do_refresh(dentry, dir_flags, parent);
+ if (unlikely(err))
+ au_fset_si(sbinfo, FAILED_REFRESH_DIR);
+ }
+ } else
+ err = au_do_refresh(dentry, /*dir_flags*/0, parent);
+ AuDbgDentry(dentry);
+ }
+ dput(parent);
+
+ AuTraceErr(err);
+ return err;
}
-/* gave up consolidating with refresh_nondir() */
-static int refresh_dir(struct dentry *root, unsigned int sigen)
+static int au_refresh_d(struct super_block *sb)
{
int err, i, j, ndentry, e;
+ unsigned int sigen;
struct au_dcsub_pages dpages;
struct au_dpage *dpage;
- struct dentry **dentries;
- struct inode *inode;
- const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1);
-
- err = 0;
- list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list)
- if (S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) {
- ii_write_lock_child(inode);
- e = au_refresh_hinode_self(inode, /*do_attr*/1);
- ii_write_unlock(inode);
- if (unlikely(e)) {
- AuDbg("e %d, i%lu\n", e, inode->i_ino);
- if (!err)
- err = e;
- /* go on even if err */
- }
- }
+ struct dentry **dentries, *d;
+ struct au_sbinfo *sbinfo;
+ struct dentry *root = sb->s_root;
+ const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1);
- e = au_dpages_init(&dpages, GFP_NOFS);
- if (unlikely(e)) {
- if (!err)
- err = e;
+ err = au_dpages_init(&dpages, GFP_NOFS);
+ if (unlikely(err))
goto out;
- }
- e = au_dcsub_pages(&dpages, root, test_dir, NULL);
- if (unlikely(e)) {
- if (!err)
- err = e;
+ err = au_dcsub_pages(&dpages, root, NULL, NULL);
+ if (unlikely(err))
goto out_dpages;
- }
- for (i = 0; !e && i < dpages.ndpage; i++) {
+ sigen = au_sigen(sb);
+ sbinfo = au_sbi(sb);
+ for (i = 0; i < dpages.ndpage; i++) {
dpage = dpages.dpages + i;
dentries = dpage->dentries;
ndentry = dpage->ndentry;
- for (j = 0; !e && j < ndentry; j++) {
- struct dentry *d;
-
+ for (j = 0; j < ndentry; j++) {
d = dentries[j];
- au_dbg_verify_dir_parent(d, sigen);
- if (au_digen(d) != sigen) {
- e = do_refresh(d, S_IFDIR, flags);
- if (unlikely(e && !err))
- err = e;
- /* break on err */
- }
+ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags);
+ if (unlikely(e && !err))
+ err = e;
+ /* go on even err */
}
}
@@ -571,113 +564,82 @@ out:
return err;
}
-static int test_nondir(struct dentry *dentry, void *arg __maybe_unused)
+static int au_refresh_i(struct super_block *sb)
{
- return !S_ISDIR(dentry->d_inode->i_mode);
-}
+ int err, e;
+ unsigned int sigen;
+ unsigned long long max, ull;
+ struct inode *inode, **array;
-static int refresh_nondir(struct dentry *root, unsigned int sigen,
- int do_dentry)
-{
- int err, i, j, ndentry, e;
- struct au_dcsub_pages dpages;
- struct au_dpage *dpage;
- struct dentry **dentries;
- struct inode *inode;
+ array = au_iarray_alloc(sb, &max);
+ err = PTR_ERR(array);
+ if (IS_ERR(array))
+ goto out;
err = 0;
- list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list)
- if (!S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) {
+ sigen = au_sigen(sb);
+ for (ull = 0; ull < max; ull++) {
+ inode = array[ull];
+ if (au_iigen(inode) != sigen) {
ii_write_lock_child(inode);
- e = au_refresh_hinode_self(inode, /*do_attr*/1);
+ e = au_refresh_hinode_self(inode);
ii_write_unlock(inode);
if (unlikely(e)) {
- AuDbg("e %d, i%lu\n", e, inode->i_ino);
+ pr_err("error %d, i%lu\n", e, inode->i_ino);
if (!err)
err = e;
/* go on even if err */
}
}
-
- if (!do_dentry)
- goto out;
-
- e = au_dpages_init(&dpages, GFP_NOFS);
- if (unlikely(e)) {
- if (!err)
- err = e;
- goto out;
- }
- e = au_dcsub_pages(&dpages, root, test_nondir, NULL);
- if (unlikely(e)) {
- if (!err)
- err = e;
- goto out_dpages;
}
- for (i = 0; i < dpages.ndpage; i++) {
- dpage = dpages.dpages + i;
- dentries = dpage->dentries;
- ndentry = dpage->ndentry;
- for (j = 0; j < ndentry; j++) {
- struct dentry *d;
+ au_iarray_free(array, max);
- d = dentries[j];
- au_dbg_verify_nondir_parent(d, sigen);
- inode = d->d_inode;
- if (inode && au_digen(d) != sigen) {
- e = do_refresh(d, inode->i_mode & S_IFMT,
- /*dir_flags*/0);
- if (unlikely(e && !err))
- err = e;
- /* go on even err */
- }
- }
- }
-
-out_dpages:
- au_dpages_free(&dpages);
out:
return err;
}
-static void au_remount_refresh(struct super_block *sb, unsigned int flags)
+static void au_remount_refresh(struct super_block *sb)
{
- int err;
- unsigned int sigen;
- struct au_sbinfo *sbinfo;
+ int err, e;
+ unsigned int udba;
+ aufs_bindex_t bindex, bend;
struct dentry *root;
struct inode *inode;
+ struct au_branch *br;
au_sigen_inc(sb);
- sigen = au_sigen(sb);
- sbinfo = au_sbi(sb);
- au_fclr_si(sbinfo, FAILED_REFRESH_DIRS);
+ au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR);
root = sb->s_root;
DiMustNoWaiters(root);
inode = root->d_inode;
IiMustNoWaiters(inode);
- au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
- di_write_unlock(root);
-
- err = refresh_dir(root, sigen);
- if (unlikely(err)) {
- au_fset_si(sbinfo, FAILED_REFRESH_DIRS);
- pr_warning("Refreshing directories failed, ignored (%d)\n",
- err);
- }
- if (au_ftest_opts(flags, REFRESH_NONDIR)) {
- err = refresh_nondir(root, sigen, !err);
+ udba = au_opt_udba(sb);
+ bend = au_sbend(sb);
+ for (bindex = 0; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ err = au_hnotify_reset_br(udba, br, br->br_perm);
if (unlikely(err))
- pr_warning("Refreshing non-directories failed, ignored"
- "(%d)\n", err);
+ AuIOErr("hnotify failed on br %d, %d, ignored\n",
+ bindex, err);
+ /* go on even if err */
}
+ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
+ di_write_unlock(root);
+ err = au_refresh_d(sb);
+ e = au_refresh_i(sb);
+ if (unlikely(e && !err))
+ err = e;
/* aufs_write_lock() calls ..._child() */
di_write_lock_child(root);
- au_cpup_attr_all(root->d_inode, /*force*/1);
+
+ au_cpup_attr_all(inode, /*force*/1);
+
+ if (unlikely(err))
+ AuIOErr("refresh failed, ignored, %d\n", err);
}
/* stop extra interpretation of errno in mount(8), and strange error messages */
@@ -742,9 +704,8 @@ static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
err = au_opts_remount(sb, &opts);
au_opts_free(&opts);
- if (au_ftest_opts(opts.flags, REFRESH_DIR)
- || au_ftest_opts(opts.flags, REFRESH_NONDIR))
- au_remount_refresh(sb, opts.flags);
+ if (au_ftest_opts(opts.flags, REFRESH))
+ au_remount_refresh(sb);
if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
mntflags = au_mntflags(sb);
@@ -932,7 +893,7 @@ static void aufs_kill_sb(struct super_block *sb)
sbinfo->si_wbr_create_ops->fin(sb);
if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE);
- au_remount_refresh(sb, /*flags*/0);
+ au_remount_refresh(sb);
}
if (au_opt_test(sbinfo->si_mntflags, PLINK))
au_plink_put(sb, /*verbose*/1);
diff --git a/ubuntu/aufs/super.h b/ubuntu/aufs/super.h
index 0cc087beadb..1930ce71a66 100644
--- a/ubuntu/aufs/super.h
+++ b/ubuntu/aufs/super.h
@@ -179,7 +179,7 @@ struct au_sbinfo {
* then try refreshing dirs at access time again.
* if it is false, refreshing dirs at access time is unnecesary
*/
-#define AuSi_FAILED_REFRESH_DIRS 1
+#define AuSi_FAILED_REFRESH_DIR 1
static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
unsigned int flag)
{
@@ -212,6 +212,7 @@ static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
#define AuLock_DIR (1 << 4) /* target is a dir */
#define AuLock_NOPLM (1 << 5) /* return err in plm mode */
#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */
+#define AuLock_GEN (1 << 7) /* test digen/iigen */
#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
#define au_fset_lock(flags, name) \
do { (flags) |= AuLock_##name; } while (0)
diff --git a/ubuntu/aufs/sysrq.c b/ubuntu/aufs/sysrq.c
index c18829b97eb..452fe3a25fc 100644
--- a/ubuntu/aufs/sysrq.c
+++ b/ubuntu/aufs/sysrq.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
/* #include <linux/sysrq.h> */
+#include <linux/writeback.h>
#include "aufs.h"
/* ---------------------------------------------------------------------- */
@@ -42,18 +43,45 @@ static void sysrq_sb(struct super_block *sb)
printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
printk(KERN_WARNING AUFS_NAME ": superblock\n");
au_dpri_sb(sb);
+
+#if 0
printk(KERN_WARNING AUFS_NAME ": root dentry\n");
au_dpri_dentry(sb->s_root);
printk(KERN_WARNING AUFS_NAME ": root inode\n");
au_dpri_inode(sb->s_root->d_inode);
+#endif
+
#if 0
- struct inode *i;
- printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
- spin_lock(&inode_lock);
- list_for_each_entry(i, &sb->s_inodes, i_sb_list)
- if (list_empty(&i->i_dentry))
- au_dpri_inode(i);
- spin_unlock(&inode_lock);
+ do {
+ int err, i, j, ndentry;
+ struct au_dcsub_pages dpages;
+ struct au_dpage *dpage;
+
+ err = au_dpages_init(&dpages, GFP_ATOMIC);
+ if (unlikely(err))
+ break;
+ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL);
+ if (!err)
+ for (i = 0; i < dpages.ndpage; i++) {
+ dpage = dpages.dpages + i;
+ ndentry = dpage->ndentry;
+ for (j = 0; j < ndentry; j++)
+ au_dpri_dentry(dpage->dentries[j]);
+ }
+ au_dpages_free(&dpages);
+ } while (0);
+#endif
+
+#if 1
+ {
+ struct inode *i;
+ printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
+ spin_lock(&inode_lock);
+ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
+ if (1 || list_empty(&i->i_dentry))
+ au_dpri_inode(i);
+ spin_unlock(&inode_lock);
+ }
#endif
printk(KERN_WARNING AUFS_NAME ": files\n");
lg_global_lock(files_lglock);
@@ -80,10 +108,12 @@ static void au_sysrq(int key __maybe_unused)
{
struct au_sbinfo *sbinfo;
+ lockdep_off();
spin_lock(&au_sbilist.spin);
list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
sysrq_sb(sbinfo->si_sb);
spin_unlock(&au_sbilist.spin);
+ lockdep_on();
}
static struct sysrq_key_op au_sysrq_op = {
diff --git a/ubuntu/aufs/vfsub.h b/ubuntu/aufs/vfsub.h
index 4b44827c428..9a9f2669b34 100644
--- a/ubuntu/aufs/vfsub.h
+++ b/ubuntu/aufs/vfsub.h
@@ -91,6 +91,13 @@ static inline void vfsub_drop_nlink(struct inode *inode)
drop_nlink(inode);
}
+static inline void vfsub_dead_dir(struct inode *inode)
+{
+ AuDebugOn(!S_ISDIR(inode->i_mode));
+ inode->i_flags |= S_DEAD;
+ clear_nlink(inode);
+}
+
/* ---------------------------------------------------------------------- */
int vfsub_update_h_iattr(struct path *h_path, int *did);
diff --git a/ubuntu/aufs/wbr_policy.c b/ubuntu/aufs/wbr_policy.c
index bb57ae520fc..9e4f1e48b4e 100644
--- a/ubuntu/aufs/wbr_policy.c
+++ b/ubuntu/aufs/wbr_policy.c
@@ -232,8 +232,7 @@ static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
if (unlikely(err))
goto out;
parent = dget_parent(dentry);
- err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/0, /*test*/NULL,
- /*arg*/NULL);
+ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
if (unlikely(err))
goto out_free;
diff --git a/ubuntu/aufs/whout.c b/ubuntu/aufs/whout.c
index 284b8cc7c35..bdc989bb9d2 100644
--- a/ubuntu/aufs/whout.c
+++ b/ubuntu/aufs/whout.c
@@ -123,6 +123,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
int i;
char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1],
*name, *p;
+ /* strict atomic_t is unnecessary here */
static unsigned short cnt;
struct qstr qs;
@@ -607,8 +608,8 @@ out:
if (wbr)
atomic_dec(&wbr->wbr_wh_running);
atomic_dec(&a->br->br_count);
- au_nwt_done(&au_sbi(a->sb)->si_nowait);
si_write_unlock(a->sb);
+ au_nwt_done(&au_sbi(a->sb)->si_nowait);
kfree(arg);
if (unlikely(err))
AuIOErr("err %d\n", err);
@@ -901,6 +902,7 @@ struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
}
whtmp->dir = NULL;
+ whtmp->br = NULL;
whtmp->wh_dentry = NULL;
/* no estimation for dir size */
rdhash = au_sbi(sb)->si_rdhash;
@@ -918,6 +920,8 @@ out:
void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
{
+ if (whtmp->br)
+ atomic_dec(&whtmp->br->br_count);
dput(whtmp->wh_dentry);
iput(whtmp->dir);
au_nhash_wh_free(&whtmp->whlist);
@@ -969,7 +973,6 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
h_tmp.dentry = wh_dentry;
h_tmp.mnt = br->br_mnt;
err = vfsub_rmdir(h_dir, &h_tmp);
- /* d_drop(h_dentry); */
}
if (!err) {
@@ -1029,10 +1032,9 @@ static void call_rmdir_whtmp(void *args)
out:
/* mutex_unlock(&a->dir->i_mutex); */
- atomic_dec(&a->br->br_count);
- au_nwt_done(&au_sbi(sb)->si_nowait);
- si_read_unlock(sb);
au_whtmp_rmdir_free(a);
+ si_read_unlock(sb);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
if (unlikely(err))
AuIOErr("err %d\n", err);
}
diff --git a/ubuntu/aufs/wkq.c b/ubuntu/aufs/wkq.c
index 9739d3a1377..c2a31f99211 100644
--- a/ubuntu/aufs/wkq.c
+++ b/ubuntu/aufs/wkq.c
@@ -160,6 +160,10 @@ int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
}
+/*
+ * Note: dget/dput() in func for aufs dentries are not supported. It will be a
+ * problem in a concurrent umounting.
+ */
int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
{
int err;
diff --git a/ubuntu/aufs/xino.c b/ubuntu/aufs/xino.c
index 84e745a1310..7c21a4aa00c 100644
--- a/ubuntu/aufs/xino.c
+++ b/ubuntu/aufs/xino.c
@@ -320,8 +320,8 @@ static void xino_do_trunc(void *_args)
pr_warning("err b%d, (%d)\n", bindex, err);
atomic_dec(&br->br_xino_running);
atomic_dec(&br->br_count);
- au_nwt_done(&au_sbi(sb)->si_nowait);
si_write_unlock(sb);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
kfree(args);
}
diff --git a/ubuntu/include/linux/aufs_type.h b/ubuntu/include/linux/aufs_type.h
index c9e2845a13c..6a67e6788e0 100644
--- a/ubuntu/include/linux/aufs_type.h
+++ b/ubuntu/include/linux/aufs_type.h
@@ -24,7 +24,7 @@
#include <linux/limits.h>
#include <linux/types.h>
-#define AUFS_VERSION "2.1-standalone.tree-37-rcN-20101122"
+#define AUFS_VERSION "2.1-standalone.tree-37-rcN-20101220"
/* todo? move this to linux-2.6.19/include/magic.h */
#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -73,11 +73,13 @@ typedef __s16 aufs_bindex_t;
#define AUFS_XINO_TRUNC_STEP 4 /* blocks */
#define AUFS_DIRWH_DEF 3
#define AUFS_RDCACHE_DEF 10 /* seconds */
+#define AUFS_RDCACHE_MAX 3600 /* seconds */
#define AUFS_RDBLK_DEF 512 /* bytes */
#define AUFS_RDHASH_DEF 32
#define AUFS_WKQ_NAME AUFS_NAME "d"
#define AUFS_WKQ_PRE_NAME AUFS_WKQ_NAME "_pre"
-#define AUFS_MFS_SECOND_DEF 30 /* seconds */
+#define AUFS_MFS_DEF_SEC 30 /* seconds */
+#define AUFS_MFS_MAX_SEC 3600 /* seconds */
#define AUFS_PLINK_WARN 100 /* number of plinks */
/* pseudo-link maintenace under /proc */