-aufs2 kbuild patch for linux-2.6.35
+aufs2.1 kbuild patch for linux-2.6.35
diff --git a/fs/Kconfig b/fs/Kconfig
index 5f85b59..6ee7cf8 100644
header-y += auto_fs4.h
header-y += ax25.h
header-y += b1lli.h
-aufs2 base patch for linux-2.6.35
+aufs2.1 base patch for linux-2.6.35
diff --git a/fs/namei.c b/fs/namei.c
index 868d0cb..6e92c81 100644
+ unsigned int flags);
+
#endif
-aufs2 standalone patch for linux-2.6.35
+aufs2.1 standalone patch for linux-2.6.35
+diff --git a/fs/file_table.c b/fs/file_table.c
+index 5c7d10e..9031acf 100644
+--- a/fs/file_table.c
++++ b/fs/file_table.c
+@@ -34,6 +34,7 @@ struct files_stat_struct files_stat = {
+
+ /* public. Not pretty! */
+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
++EXPORT_SYMBOL(files_lock);
+
+ /* SLAB cache for file structures */
+ static struct kmem_cache *filp_cachep __read_mostly;
+@@ -346,6 +347,7 @@ void file_kill(struct file *file)
+ file_list_unlock();
+ }
+ }
++EXPORT_SYMBOL(file_kill);
+
+ int fs_may_remount_ro(struct super_block *sb)
+ {
+diff --git a/fs/inode.c b/fs/inode.c
+index 722860b..bfb0698 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -84,6 +84,7 @@ static struct hlist_head *inode_hashtable __read_mostly;
+ * the i_state of an inode while it is in use..
+ */
+ DEFINE_SPINLOCK(inode_lock);
++EXPORT_SYMBOL(inode_lock);
+
+ /*
+ * iprune_sem provides exclusion between the kswapd or try_to_free_pages
diff --git a/fs/namei.c b/fs/namei.c
index 6e92c81..334130e 100644
--- a/fs/namei.c
unsigned long prot)
diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Documentation/ABI/testing/debugfs-aufs
--- /usr/share/empty/Documentation/ABI/testing/debugfs-aufs 1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/ABI/testing/debugfs-aufs 2010-08-21 21:00:02.956499131 +0200
++++ linux/Documentation/ABI/testing/debugfs-aufs 2010-10-01 13:09:26.340878164 +0200
@@ -0,0 +1,37 @@
+What: /debug/aufs/si_<id>/
+Date: March 2009
+ will be empty. About XINO files, see the aufs manual.
diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentation/ABI/testing/sysfs-aufs
--- /usr/share/empty/Documentation/ABI/testing/sysfs-aufs 1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/ABI/testing/sysfs-aufs 2010-08-21 21:00:02.956499131 +0200
++++ linux/Documentation/ABI/testing/sysfs-aufs 2010-10-01 13:09:26.340878164 +0200
@@ -0,0 +1,24 @@
+What: /sys/fs/aufs/si_<id>/
+Date: March 2009
+ will be empty. About XINO files, see the aufs manual.
diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h
--- /usr/share/empty/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/aufs.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/aufs.h 2010-10-01 13:09:26.342878167 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
--- /usr/share/empty/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/branch.c 2010-08-21 21:00:02.972333781 +0200
-@@ -0,0 +1,1005 @@
++++ linux/fs/aufs/branch.c 2010-10-01 13:09:26.343878167 +0200
+@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+
+ kfree(add_branch->br_wbr);
+
-+ out_br:
++out_br:
+ kfree(add_branch);
-+ out:
++out:
+ return ERR_PTR(err);
+}
+
+ err = -EINVAL;
+ pr_err("write permission for readonly mount or inode, %s\n", path);
+
-+ out:
++out:
+ return err;
+}
+
+ (h_inode->i_mode & S_IALLUGO));
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb),
+ kst.f_namelen);
+
-+ out:
++out:
+ return err;
+}
+
+ mntget(add->path.mnt);
+ goto out; /* success */
+
-+ out_err:
++out_err:
+ br->br_mnt = NULL;
-+ out:
++out:
+ return err;
+}
+
+
+ root = sb->s_root;
+ root_inode = root->d_inode;
-+ au_plink_maint_block(sb);
+ bend = au_sbend(sb);
+ amount = bend + 1 - bindex;
+ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
+ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry)
+ au_xino_brid_set(sb, add_branch->br_id);
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out_dpages:
++out_dpages:
+ au_dpages_free(&dpages);
-+ out:
++out:
+ return err;
+}
+
+
+ root = sb->s_root;
+ inode = root->d_inode;
-+ au_plink_maint_block(sb);
+ sbinfo = au_sbi(sb);
+ bend = sbinfo->si_bend;
+
+ i = atomic_read(&br->br_count);
+ if (unlikely(i)) {
+ AuVerbose(verbose, "%d file(s) opened\n", i);
-+ if (!verbose)
-+ goto out;
++ goto out;
+ }
+
+ wbr = br->br_wbr;
+ au_xino_brid_set(sb, -1);
+ goto out; /* success */
+
-+ out_wh:
++out_wh:
+ /* revert */
+ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry);
+ if (rerr)
+ pr_warning("failed re-creating base whiteout, %s. (%d)\n",
+ del->pathname, rerr);
-+ out:
++out:
+ return err;
+}
+
+{
+#ifdef CONFIG_IMA
+ /* since it doesn't support mark_files_ro() */
-+ pr_warning("RW -> RO makes IMA to produce wrong message");
++ AuWarn1("RW -> RO makes IMA to produce wrong message");
+#endif
+}
+
+{
+ int err;
+ unsigned long n, ul, bytes, files;
-+ aufs_bindex_t bstart;
++ aufs_bindex_t br_id;
+ struct file *file, *hf, **a;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct au_hfile *hfile;
+ const int step_bytes = 1024, /* memory allocation unit */
+ step_files = step_bytes / sizeof(*a);
+
+ goto out;
+
+ /* no need file_list_lock() since sbinfo is locked? defered? */
++ br_id = au_sbr_id(sb, bindex);
+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
+ if (special_file(file->f_dentry->d_inode->i_mode))
+ continue;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
+
+ AuDbg("%.*s\n", AuDLNPair(file->f_dentry));
+ fi_read_lock(file);
+ goto out_free;
+ }
+
-+ bstart = au_fbstart(file);
-+ if (!S_ISREG(file->f_dentry->d_inode->i_mode)
++ hfile = &au_fi(file)->fi_htop;
++ hf = hfile->hf_file;
++ if (!S_ISREG(inode->i_mode)
+ || !(file->f_mode & FMODE_WRITE)
-+ || bstart != bindex) {
++ || hfile->hf_br->br_id != br_id
++ || !(hf->f_mode & FMODE_WRITE)) {
+ FiMustNoWaiters(file);
+ fi_read_unlock(file);
+ continue;
+ }
+
-+ hf = au_hf_top(file);
+ FiMustNoWaiters(file);
+ fi_read_unlock(file);
+
+ }
+ }
+
-+ out_free:
++out_free:
+ kfree(a);
-+ out:
++out:
+ return err;
+}
+
+ struct au_branch *br;
+
+ root = sb->s_root;
-+ au_plink_maint_block(sb);
+ bindex = au_find_dbindex(root, mod->h_root);
+ if (bindex < 0) {
+ if (remount)
+ br->br_perm = mod->perm;
+ }
+
-+ out:
++out:
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
--- /usr/share/empty/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/branch.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/branch.h 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+
+static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex)
+{
-+ atomic_dec_return(&au_sbr(sb, bindex)->br_count);
++ atomic_dec(&au_sbr(sb, bindex)->br_count);
+}
+
+static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex)
+#endif /* __AUFS_BRANCH_H__ */
diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk
--- /usr/share/empty/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/conf.mk 2010-08-21 21:00:02.972333781 +0200
-@@ -0,0 +1,36 @@
++++ linux/fs/aufs/conf.mk 2010-10-01 13:09:26.343878167 +0200
+@@ -0,0 +1,37 @@
+
+AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
+
+endef
+
+AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \
++ SBILIST \
+ HNOTIFY HFSNOTIFY HINOTIFY \
+ EXPORT INO_T_64 \
+ RDU \
+-include ${srctree}/${src}/conf_priv.mk
diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
--- /usr/share/empty/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/cpup.c 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/cpup.c 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,1059 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ else
+ free_page((unsigned long)buf);
+
-+ out:
++out:
+ return err;
+}
+
+ IMustLock(file[SRC].dentry->d_inode);
+ err = au_copy_file(file[DST].file, file[SRC].file, len);
+
-+ out_dst:
++out_dst:
+ fput(file[DST].file);
+ au_sbr_put(sb, file[DST].bindex);
-+ out_src:
++out_src:
+ fput(file[SRC].file);
+ au_sbr_put(sb, file[SRC].bindex);
-+ out:
++out:
+ return err;
+}
+
+ err = -EIO;
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ __putname(sym.k);
+
-+ out:
++out:
+ return err;
+}
+
+ err = -EIO;
+ }
+
-+ out:
++out:
+ dput(dst_parent);
+ return err;
+}
+ au_dtime_revert(&dt);
+ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry);
+
-+ out_wh:
++out_wh:
+ dput(wh_dentry);
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+ break;
+ }
+
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+ err = au_cpup_dirs(dentry, bdst);
+ di_downgrade_lock(parent, AuLock_IR);
+
-+ out:
++out:
+ dput(parent);
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
--- /usr/share/empty/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/cpup.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/cpup.h 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_CPUP_H__ */
diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
--- /usr/share/empty/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dbgaufs.c 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/dbgaufs.c 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ err = 0;
+ }
+
-+ out:
++out:
+ return err;
+
+}
+ err = -ENOENT;
+ si_read_unlock(sb);
+
-+ out:
++out:
+ return err;
+}
+
+ if (!err)
+ goto out; /* success */
+
-+ out_dir:
++out_dir:
+ dbgaufs_si_fin(sbinfo);
-+ out:
++out:
+ return err;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h
--- /usr/share/empty/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dbgaufs.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/dbgaufs.h 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __DBGAUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
--- /usr/share/empty/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dcsub.c 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/dcsub.c 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ dpages->ndpage = 1;
+ return 0; /* success */
+
-+ out_dpages:
++out_dpages:
+ kfree(dpages->dpages);
-+ out:
++out:
+ return err;
+}
+
+ dpage->dentries[dpage->ndentry++] = dget(dentry);
+ return 0; /* success */
+
-+ out:
++out:
+ return err;
+}
+
+
+ err = 0;
+ spin_lock(&dcache_lock);
-+ repeat:
++repeat:
+ next = this_parent->d_subdirs.next;
-+ resume:
++resume:
+ if (this_parent->d_sb == sb
+ && !IS_ROOT(this_parent)
+ && atomic_read(&this_parent->d_count)
+ this_parent = this_parent->d_parent; /* dcache_lock is locked */
+ goto resume;
+ }
-+ out:
++out:
+ spin_unlock(&dcache_lock);
+ return err;
+}
+ }
+ }
+
-+ out:
++out:
+ spin_unlock(&dcache_lock);
+
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
--- /usr/share/empty/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dcsub.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/dcsub.h 2010-10-01 13:09:26.343878167 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_DCSUB_H__ */
diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
--- /usr/share/empty/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/debug.c 2010-08-21 21:00:02.972333781 +0200
-@@ -0,0 +1,440 @@
++++ linux/fs/aufs/debug.c 2010-10-01 13:09:26.344878166 +0200
+@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+char *au_plevel = KERN_DEBUG;
-+#define dpri(fmt, ...) do { \
-+ if (au_debug_test()) \
-+ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \
++#define dpri(fmt, ...) do { \
++ if ((au_plevel \
++ && strcmp(au_plevel, KERN_DEBUG)) \
++ || au_debug_test()) \
++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+ && file->f_dentry
+ && au_test_aufs(file->f_dentry->d_sb)
+ && au_fi(file))
-+ snprintf(a, sizeof(a), ", mmapped %d",
-+ !!au_fi(file)->fi_hvmop);
++ snprintf(a, sizeof(a), ", gen %d, mmapped %d",
++ au_figen(file), !!au_fi(file)->fi_hvmop);
+ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n",
+ bindex, file->f_mode, file->f_flags, (long)file_count(file),
+ file->f_version, file->f_pos, a);
+ if (!fidir)
+ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file);
+ else
-+ for (bindex = finfo->fi_btop; bindex <= fidir->fd_bbot;
++ for (bindex = finfo->fi_btop;
++ bindex >= 0 && bindex <= fidir->fd_bbot;
+ bindex++) {
+ hfile = fidir->fd_hfile + bindex;
+ do_pri_file(bindex, hfile ? hfile->hf_file : NULL);
+ atomic_read(&sb->s_active), !!br->br_xino.xi_file);
+ return 0;
+
-+ out:
++out:
+ dpri("s%d: err %ld\n", bindex, PTR_ERR(br));
+ return -1;
+}
+}
diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
--- /usr/share/empty/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/debug.h 2010-08-21 21:00:02.972333781 +0200
++++ linux/fs/aufs/debug.h 2010-10-01 13:09:26.444878166 +0200
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+/* #include <linux/kernel.h> */
+#include <linux/delay.h>
+/* #include <linux/kd.h> */
-+/* #include <linux/vt_kern.h> */
++#include <linux/vt_kern.h>
+#include <linux/sysrq.h>
+#include <linux/aufs_type.h>
+
+#endif /* __AUFS_DEBUG_H__ */
diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
--- /usr/share/empty/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,850 @@
++++ linux/fs/aufs/dentry.c 2010-10-01 13:09:26.444878166 +0200
+@@ -0,0 +1,860 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ if (!allow_neg)
+ return NULL; /* success */
+
-+ real_lookup:
++real_lookup:
+ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd);
+ if (IS_ERR(h_dentry))
+ goto out;
+ }
+ goto out;
+
-+ out_neg:
++out_neg:
+ dput(h_dentry);
+ h_dentry = NULL;
-+ out:
++out:
+ return h_dentry;
+}
+
+ /* both of real entry and whiteout found */
+ err = -EIO;
+
-+ out_parent:
++out_parent:
+ dput(parent);
+ kfree(whname.name);
-+ out:
++out:
+ return err;
+}
+
+ au_set_dbend(dentry, bindex);
+ au_set_h_dptr(dentry, bindex, h_dentry);
+
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+ err = au_busy_or_stale();
+ dput(h_d);
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart)
+ d_drop(dentry);
+
-+ out_dgen:
++out_dgen:
+ au_update_digen(dentry);
-+ out:
++out:
+ dput(parent);
+ AuTraceErr(npositive);
+ return npositive;
+ else if (!valid)
+ err = -EINVAL;
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ struct super_block *sb;
+ struct inode *inode;
+
-+ err = -EINVAL;
++ valid = 1;
+ sb = dentry->d_sb;
+ inode = dentry->d_inode;
-+ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW);
++ /*
++ * todo: very ugly
++ * i_mutex of parent dir may be held,
++ * but we should not return 'invalid' due to busy.
++ */
++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
++ if (unlikely(err)) {
++ valid = err;
++ goto out;
++ }
+ sigen = au_sigen(sb);
+ if (au_digen(dentry) != sigen) {
+ AuDebugOn(IS_ROOT(dentry));
+
+ if (bstart >= 0
+ && au_test_higen(inode, au_h_iptr(inode, bstart)))
-+ goto out;
++ 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 */
+ err = -EIO;
-+ goto out;
++ goto out_inval;
+
-+ out_dgrade:
++out_dgrade:
+ di_downgrade_lock(dentry, AuLock_IR);
-+ out:
++out_inval:
+ aufs_read_unlock(dentry, AuLock_IR);
+ AuTraceErr(err);
+ valid = !err;
++out:
+ if (!valid)
-+ AuDbg("%.*s invalid\n", AuDLNPair(dentry));
++ AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid);
+ return valid;
+}
+
+};
diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
--- /usr/share/empty/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.h 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/dentry.h 2010-10-01 13:09:26.444878167 +0200
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#ifdef CONFIG_AUFS_HNOTIFY
+static inline void au_digen_dec(struct dentry *d)
+{
-+ atomic_dec_return(&au_di(d)->di_generation);
++ atomic_dec(&au_di(d)->di_generation);
+}
+
+static inline void au_hn_di_reinit(struct dentry *dentry)
+#endif /* __AUFS_DENTRY_H__ */
diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
--- /usr/share/empty/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dinfo.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,395 @@
++++ linux/fs/aufs/dinfo.c 2010-10-01 13:09:26.444878167 +0200
+@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+
+#include "aufs.h"
+
-+void au_di_init_once(void *_di)
++void au_di_init_once(void *_dinfo)
+{
-+ struct au_dinfo *di = _di;
++ struct au_dinfo *dinfo = _dinfo;
++ static struct lock_class_key aufs_di;
+
-+ au_rw_init(&di->di_rwsem);
++ au_rw_init(&dinfo->di_rwsem);
++ au_rw_class(&dinfo->di_rwsem, &aufs_di);
+}
+
+int au_di_init(struct dentry *dentry)
+ dentry->d_op = &aufs_dop;
+ return 0; /* success */
+
-+ out_dinfo:
++out_dinfo:
+ au_cache_free_dinfo(dinfo);
-+ out:
++out:
+ return -ENOMEM;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
--- /usr/share/empty/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dir.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,638 @@
++++ linux/fs/aufs/dir.c 2010-10-01 13:09:26.444878167 +0200
+@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ /* file->f_ra = h_file->f_ra; */
+ err = 0;
+
-+ out:
++out:
+ return err;
+}
+
+ err = -ENOMEM;
+ sb = file->f_dentry->d_sb;
+ si_read_lock(sb, AuLock_FLUSH);
-+ fidir = au_fidir_alloc(inode->i_sb);
++ fidir = au_fidir_alloc(sb);
+ if (fidir) {
+ err = au_do_open(file, do_open_dir, fidir);
+ if (unlikely(err))
+ struct au_fidir *fidir;
+ aufs_bindex_t bindex, bend;
+
-+ au_plink_maint_leave(file);
+ sb = file->f_dentry->d_sb;
+ finfo = au_fi(file);
+ fidir = finfo->fi_hdir;
+ if (fidir) {
++ /* remove me from sb->s_files */
++ file_kill(file);
++
+ vdir_cache = fidir->fd_vdir_cache; /* lock-free */
+ if (vdir_cache)
+ au_vdir_free(vdir_cache);
+ }
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ return err;
+ }
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
++out:
+ si_read_unlock(sb);
+ return err;
+}
+ (arg->whlist, name, namelen, ino, d_type, arg->bindex,
+ au_ftest_testempty(arg->flags, SHWH));
+
-+ out:
++out:
+ /* smp_mb(); */
+ AuTraceErr(arg->err);
+ return arg->err;
+ err = arg->err;
+ } while (!err && au_ftest_testempty(arg->flags, CALLED));
+
-+ out_put:
++out_put:
+ fput(h_file);
+ au_sbr_put(dentry->d_sb, arg->bindex);
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out_whlist:
++out_whlist:
+ au_nhash_wh_free(&whlist);
-+ out:
++out:
+ return err;
+}
+
+};
diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
--- /usr/share/empty/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dir.h 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/dir.h 2010-10-01 13:09:26.444878167 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_DIR_H__ */
diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
--- /usr/share/empty/fs/aufs/dynop.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dynop.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/dynop.c 2010-10-01 13:09:26.444878167 +0200
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2010 Junjiro R. Okajima
+
+#ifdef CONFIG_AUFS_DEBUG
+#define DyDbgDeclare(cnt) unsigned int cnt = 0
-+#define DyDbgInc(cnt) cnt++
++#define DyDbgInc(cnt) do { cnt++; } while (0)
+#else
+#define DyDbgDeclare(cnt) do {} while (0)
+#define DyDbgInc(cnt) do {} while (0)
+}
diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
--- /usr/share/empty/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dynop.h 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/dynop.h 2010-10-01 13:09:26.444878167 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Junjiro R. Okajima
+#endif /* __AUFS_DYNOP_H__ */
diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
--- /usr/share/empty/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/export.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/export.c 2010-10-01 13:09:26.444878167 +0200
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ AuIOErr("xigen error (%zd)\n", sz);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ fput(sbinfo->si_xigen);
+ sbinfo->si_xigen = file;
+
-+ out:
++out:
+ return err;
+}
+
+ dentry = ERR_PTR(-ESTALE);
+ }
+
-+ out_iput:
++out_iput:
+ iput(inode);
-+ out:
++out:
+ return dentry;
+}
+
+ si_read_unlock(sb);
+ bindex = -1;
+
-+ out:
++out:
+ return bindex;
+}
+
+ dentry = ERR_PTR(-ENOENT);
+ }
+
-+ out_name:
++out_name:
+ __putname(arg.name);
-+ out_file:
++out_file:
+ fput(file);
-+ out:
++out:
+ if (unlikely(nsi_lock
+ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
+ if (!IS_ERR(dentry)) {
+ dentry = au_lkup_by_ino(&path, ino, nsi_lock);
+ path_put(&path);
+
-+ out:
++out:
+ AuTraceErrPtr(dentry);
+ return dentry;
+}
+ if (n != 1)
+ p[strlen(p)] = '/';
+
-+ out:
++out:
+ AuTraceErrPtr(p);
+ return p;
+}
+ else
+ dentry = dget(path.dentry);
+
-+ out_path:
++out_path:
+ path_put(&path);
-+ out_relock:
++out_relock:
+ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
+ if (!IS_ERR(dentry)) {
+ dput(dentry);
+ dentry = ERR_PTR(-ESTALE);
+ }
-+ out_pathname:
++out_pathname:
+ free_page((unsigned long)pathname);
-+ out_h_parent:
++out_h_parent:
+ dput(h_parent);
-+ out:
++out:
+ /* au_br_put(br); */
+ AuTraceErrPtr(dentry);
+ return dentry;
+ /* todo?: make it ESTALE */
+ goto out_unlock;
+
-+ accept:
++accept:
+ if (dentry->d_inode->i_generation == fh[Fh_igen])
+ goto out_unlock; /* success */
+
+ dput(dentry);
+ dentry = ERR_PTR(-ESTALE);
-+ out_unlock:
++out_unlock:
+ si_read_unlock(sb);
-+ out:
++out:
+ AuTraceErrPtr(dentry);
+ return dentry;
+}
+ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
+ dir_ino, fh, fh_len);
+
-+ out:
++out:
+ AuTraceErrPtr(parent);
+ return parent;
+}
+ else
+ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
+
-+ out_dput:
++out_dput:
+ dput(h_parent);
-+ out_unlock:
++out_unlock:
+ di_read_unlock(parent, !AuLock_IR);
+ dput(parent);
+ aufs_read_unlock(dentry, AuLock_IR);
-+ out:
++out:
+ if (unlikely(err < 0))
+ err = 255;
+ return err;
+ int (*f)(struct inode *inode);
+
+ sb = inode->i_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ ii_write_lock_child(inode);
+ bindex = au_ibstart(inode);
+ AuDebugOn(bindex < 0);
+}
diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
--- /usr/share/empty/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/file.c 2010-10-01 13:09:26.467878166 +0200
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ fsnotify_open(h_dentry);
+ goto out; /* success */
+
-+ out_br:
++out_br:
+ atomic_dec(&br->br_count);
-+ out:
++out:
+ return h_file;
+}
+
+ au_finfo_fin(file);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /* todo: necessary? */
+ /* file->f_ra = h_file->f_ra; */
+
-+ out:
++out:
+ if (h_file_tmp)
+ fput(h_file_tmp);
+ return err;
+ au_unpin(pin);
+ goto out_unlock;
+
-+ out_dgrade:
++out_dgrade:
+ di_downgrade_lock(parent, AuLock_IR);
-+ out_unlock:
++out_unlock:
+ di_read_unlock(parent, AuLock_IR);
-+ out_dput:
++out_dput:
+ dput(parent);
-+ out:
++out:
+ return err;
+}
+
+ *need_reopen = 0;
+ }
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(parent, AuLock_IR);
-+ out_parent:
++out_parent:
+ dput(parent);
-+ out:
++out:
+ return err;
+}
+
+ au_set_h_fptr(file, bindex, NULL);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ fi_write_unlock(file);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+};
diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
--- /usr/share/empty/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.h 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/file.h 2010-10-01 13:09:26.467878166 +0200
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+
+static inline int au_fidir_sz(int nent)
+{
-+ AuDebugOn(nent < 0);
-+ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
++ AuDebugOn(nent < 0);
++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent;
+}
+
+struct au_finfo {
+#endif /* __AUFS_FILE_H__ */
diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
--- /usr/share/empty/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/finfo.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,167 @@
++++ linux/fs/aufs/finfo.c 2010-10-01 13:09:26.467878166 +0200
+@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ allow_write_access(hf->hf_file);
+ fput(hf->hf_file);
+ hf->hf_file = NULL;
-+ atomic_dec_return(&hf->hf_br->br_count);
++ atomic_dec(&hf->hf_br->br_count);
+ hf->hf_br = NULL;
+}
+
+ au_cache_free_finfo(finfo);
+}
+
-+void au_fi_init_once(void *_fi)
++void au_fi_init_once(void *_finfo)
+{
-+ struct au_finfo *fi = _fi;
++ struct au_finfo *finfo = _finfo;
++ static struct lock_class_key aufs_fi, aufs_fi_vm, aufs_fi_mmap;
+
-+ au_rw_init(&fi->fi_rwsem);
-+ mutex_init(&fi->fi_vm_mtx);
-+ mutex_init(&fi->fi_mmap);
++ au_rw_init(&finfo->fi_rwsem);
++ au_rw_class(&finfo->fi_rwsem, &aufs_fi);
++ mutex_init(&finfo->fi_vm_mtx);
++ lockdep_set_class(&finfo->fi_vm_mtx, &aufs_fi_vm);
++ mutex_init(&finfo->fi_mmap);
++ lockdep_set_class(&finfo->fi_mmap, &aufs_fi_mmap);
+}
+
+int au_finfo_init(struct file *file, struct au_fidir *fidir)
+}
diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
--- /usr/share/empty/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/f_op.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,886 @@
++++ linux/fs/aufs/f_op.c 2010-10-01 13:09:26.445878166 +0200
+@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+
+ finfo = au_fi(file);
+ bindex = finfo->fi_btop;
-+ if (bindex >= 0)
++ if (bindex >= 0) {
++ /* remove me from sb->s_files */
++ file_kill(file);
+ au_set_h_fptr(file, bindex, NULL);
++ }
+
+ au_finfo_fin(file);
+ return 0;
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+ if (unlikely(err))
+ goto out;
+
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
-+ out:
++out:
+ si_read_unlock(sb);
+ return err;
+}
+
++/*
++ * todo: very ugly
++ * it locks both of i_mutex and si_rwsem for read in safe.
++ * if the plink maintenance mode continues forever (that is the problem),
++ * may loop forever.
++ */
++static void au_mtx_and_read_lock(struct inode *inode)
++{
++ int err;
++ struct super_block *sb = inode->i_sb;
++
++ while (1) {
++ mutex_lock(&inode->i_mutex);
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err)
++ break;
++ mutex_unlock(&inode->i_mutex);
++ si_read_lock(sb, AuLock_NOPLMW);
++ si_read_unlock(sb);
++ }
++}
++
+static ssize_t aufs_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct au_pin pin;
+ struct dentry *dentry;
+ struct inode *inode;
-+ struct super_block *sb;
+ struct file *h_file;
+ char __user *buf = (char __user *)ubuf;
+
+ dentry = file->f_dentry;
-+ sb = dentry->d_sb;
+ inode = dentry->d_inode;
-+ mutex_lock(&inode->i_mutex);
-+ si_read_lock(sb, AuLock_FLUSH);
++ au_mtx_and_read_lock(inode);
+
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
-+ si_read_unlock(sb);
++out:
++ si_read_unlock(inode->i_sb);
+ mutex_unlock(&inode->i_mutex);
+ return err;
+}
+ /* currently there is no such fs */
+ WARN_ON_ONCE(1);
+
-+ out:
++out:
+ return err;
+}
+
+ file = kio->ki_filp;
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+ if (unlikely(err))
+ goto out;
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
+
-+ out:
++out:
+ si_read_unlock(sb);
+ return err;
+}
+ struct au_pin pin;
+ struct dentry *dentry;
+ struct inode *inode;
-+ struct super_block *sb;
+ struct file *file, *h_file;
+
+ file = kio->ki_filp;
+ dentry = file->f_dentry;
-+ sb = dentry->d_sb;
+ inode = dentry->d_inode;
-+ mutex_lock(&inode->i_mutex);
-+ si_read_lock(sb, AuLock_FLUSH);
++ au_mtx_and_read_lock(inode);
++
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
+ goto out;
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
-+ si_read_unlock(sb);
++out:
++ si_read_unlock(inode->i_sb);
+ mutex_unlock(&inode->i_mutex);
+ return err;
+}
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+ if (unlikely(err))
+ goto out;
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
+
-+ out:
++out:
+ si_read_unlock(sb);
+ return err;
+}
+ struct au_pin pin;
+ struct dentry *dentry;
+ struct inode *inode;
-+ struct super_block *sb;
+ struct file *h_file;
+
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
-+ mutex_lock(&inode->i_mutex);
-+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
-+
++ au_mtx_and_read_lock(inode);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
+ goto out;
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
-+ si_read_unlock(sb);
++out:
++ si_read_unlock(inode->i_sb);
+ mutex_unlock(&inode->i_mutex);
+ return err;
+}
+ h_vmop = ERR_PTR(-EIO);
+ }
+
-+ out:
++out:
+ return h_vmop;
+}
+
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, !AuLock_FLUSH);
++ si_read_lock(sb, AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
+ goto out;
+ /* update without lock, I don't think it a problem */
+ fsstack_copy_attr_atime(file->f_dentry->d_inode, h_dentry->d_inode);
+
-+ out_unlock:
++out_unlock:
+ au_fi_mmap_unlock(file);
+ fput(args.h_file);
-+ out:
++out:
+ return err;
+}
+
+ IMustLock(inode);
+
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out;
+
+ err = 0; /* -EBADF; */ /* posix? */
+ if (unlikely(!(file->f_mode & FMODE_WRITE)))
-+ goto out;
++ goto out_si;
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
-+ goto out;
++ goto out_si;
+
+ err = au_ready_to_write(file, -1, &pin);
+ di_downgrade_lock(dentry, AuLock_IR);
+ mutex_unlock(h_mtx);
+ }
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
++out_si:
+ si_read_unlock(sb);
++out:
+ if (inode != file->f_mapping->host) {
+ mutex_unlock(&inode->i_mutex);
+ mutex_lock(&file->f_mapping->host->i_mutex);
+ struct dentry *dentry;
+ struct inode *inode;
+ struct file *file, *h_file;
-+ struct super_block *sb;
+
+ file = kio->ki_filp;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
-+ mutex_lock(&inode->i_mutex);
-+
-+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ au_mtx_and_read_lock(inode);
+
+ err = 0; /* -EBADF; */ /* posix? */
+ if (unlikely(!(file->f_mode & FMODE_WRITE)))
+ mutex_unlock(h_mtx);
+ }
+
-+ out_unlock:
++out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
-+ out:
-+ si_read_unlock(sb);
++out:
++ si_read_unlock(inode->sb);
+ mutex_unlock(&inode->i_mutex);
+ return err;
+}
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+ if (unlikely(err))
+ goto out;
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
+
-+ out:
++out:
+ si_read_unlock(sb);
+ return err;
+}
+};
diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
--- /usr/share/empty/fs/aufs/f_op_sp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/f_op_sp.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/f_op_sp.c 2010-10-01 13:09:26.445878166 +0200
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+/* ---------------------------------------------------------------------- */
+
+/* currently, support only FIFO */
-+enum {AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW,
-+ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */
-+ AuSp_Last};
++enum {
++ AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW,
++ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */
++ AuSp_Last
++};
+static int aufs_open_sp(struct inode *inode, struct file *file);
+static struct au_sp_fop {
+ int done;
+ au_unpin(&pin);
+ }
+
-+ out:
++out:
+ di_downgrade_lock(dentry, AuLock_IR);
+ return err;
+}
+ di_read_lock_child(dentry, AuLock_IR);
+ if (!err)
+ au_init_fop_sp(file);
-+ else
-+ au_finfo_fin(file);
+
-+ out:
++out:
+ return err;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
--- /usr/share/empty/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/fstype.h 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/fstype.h 2010-10-01 13:09:26.467878166 +0200
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_FSTYPE_H__ */
diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
--- /usr/share/empty/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hfsnotify.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/hfsnotify.c 2010-10-01 13:09:26.467878166 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+};
diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c
--- /usr/share/empty/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hfsplus.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/hfsplus.c 2010-10-01 13:09:26.467878166 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Junjiro R. Okajima
+}
diff -urN /usr/share/empty/fs/aufs/hinotify.c linux/fs/aufs/hinotify.c
--- /usr/share/empty/fs/aufs/hinotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hinotify.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,227 @@
++++ linux/fs/aufs/hinotify.c 2010-10-01 13:09:26.467878166 +0200
+@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ u32 conv;
+
+ conv = 0;
-+#define do_conv(flag) conv |= (mask & IN_ ## flag) ? FS_ ## flag : 0
++#define do_conv(flag) do { \
++ conv |= (mask & IN_ ## flag) ? FS_ ## flag : 0; \
++ } while (0)
+ do_conv(ACCESS);
+ do_conv(MODIFY);
+ do_conv(ATTRIB);
+ do_conv(UNMOUNT);
+ do_conv(Q_OVERFLOW);
+#undef do_conv
-+#define do_conv(flag) conv |= (mask & IN_ ## flag) ? FS_IN_ ## flag : 0
++#define do_conv(flag) do { \
++ conv |= (mask & IN_ ## flag) ? FS_IN_ ## flag : 0; \
++ } while (0)
+ do_conv(IGNORED);
+ /* do_conv(ISDIR); */
+ /* do_conv(ONESHOT); */
+};
diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
--- /usr/share/empty/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hnotify.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,663 @@
++++ linux/fs/aufs/hnotify.c 2010-10-01 13:09:26.467878166 +0200
+@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+
+ /* children inode number will be broken */
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ }
+ }
+
-+ out_dpages:
++out_dpages:
+ au_dpages_free(&dpages);
+
+ /* discard children */
+ dentry_unhash(dentry);
+ dput(dentry);
-+ out:
++out:
+ return err;
+}
+
+ dput(d);
+ }
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+
+ ii_write_lock_child(inode);
+
-+ out:
++out:
+ return inode;
+}
+
+ AuDebugOn(!sb);
+ sbinfo = au_sbi(sb);
+ AuDebugOn(!sbinfo);
-+ /* big aufs lock */
-+ si_noflush_write_lock(sb);
++ si_write_lock(sb, !AuLock_FLUSH | AuLock_NOPLMW);
+
+ ii_read_lock_parent(a->dir);
+ bfound = -1;
+ err = hn_job(&args);
+ ii_write_unlock(a->dir);
+
-+ out:
++out:
+ au_nwt_done(&sbinfo->si_nowait);
+ si_write_unlock(sb);
+
+}
diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
--- /usr/share/empty/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/iinfo.c 2010-08-21 21:00:02.980020464 +0200
-@@ -0,0 +1,257 @@
++++ linux/fs/aufs/iinfo.c 2010-10-01 13:09:26.468878166 +0200
+@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+{
+ struct au_icntnr *c = _c;
+ struct au_iinfo *iinfo = &c->iinfo;
++ static struct lock_class_key aufs_ii;
+
+ au_rw_init(&iinfo->ii_rwsem);
++ au_rw_class(&iinfo->ii_rwsem, &aufs_ii);
+ inode_init_once(&c->vfs_inode);
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
--- /usr/share/empty/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/inode.c 2010-08-21 21:00:02.980020464 +0200
++++ linux/fs/aufs/inode.c 2010-10-01 13:09:26.469878166 +0200
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+{
+ if (inode) {
+ AuDebugOn(!atomic_read(&inode->i_count));
-+ atomic_inc_return(&inode->i_count);
++ atomic_inc(&inode->i_count);
+ }
+ return inode;
+}
+ if (do_attr)
+ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
+
-+ out:
++out:
+ return err;
+}
+
+ err = e;
+ au_refresh_hinode_attr(inode, update && isdir);
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ }
+ au_cpup_attr_all(inode, /*force*/1);
+
-+ out:
++out:
+ return err;
+}
+
+
+ if (unlikely(err))
+ ii_write_unlock(inode);
-+ out:
++out:
+ return err;
+}
+
+ goto out;
+ }
+
-+ out:
++out:
+ if (mtx)
+ mutex_unlock(mtx);
+ return err;
+ if (!S_ISDIR(h_inode->i_mode))
+ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
+
-+ new_ino:
++new_ino:
+ if (mtx)
+ mutex_lock(mtx);
+ err = au_xino_read(sb, bstart, h_ino, &ino);
+ goto new_ino;
+ }
+
-+ out_iput:
++out_iput:
+ iput(inode);
-+ out_err:
++out_err:
+ inode = ERR_PTR(err);
-+ out:
++out:
+ if (mtx)
+ mutex_unlock(mtx);
+ return inode;
+}
diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
--- /usr/share/empty/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/inode.h 2010-08-21 21:00:02.980020464 +0200
-@@ -0,0 +1,498 @@
++++ linux/fs/aufs/inode.h 2010-10-01 13:09:26.469878166 +0200
+@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+void au_iinfo_fin(struct inode *inode);
+int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
+
++#ifdef CONFIG_PROC_FS
+/* plink.c */
-+void au_plink_maint_block(struct super_block *sb);
-+void au_plink_maint_leave(struct file *file);
++int au_plink_maint(struct super_block *sb, int flags);
++void au_plink_maint_leave(struct au_sbinfo *sbinfo);
++int au_plink_maint_enter(struct super_block *sb);
+#ifdef CONFIG_AUFS_DEBUG
+void au_plink_list(struct super_block *sb);
+#else
+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
+void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
+ struct dentry *h_dentry);
-+void au_plink_put(struct super_block *sb);
++void au_plink_put(struct super_block *sb, int verbose);
++void au_plink_clean(struct super_block *sb, int verbose);
+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id);
-+long au_plink_ioctl(struct file *file, unsigned int cmd);
++#else
++AuStubInt0(au_plink_maint, struct super_block *sb, int flags);
++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo);
++AuStubInt0(au_plink_maint_enter, struct super_block *sb);
++AuStubVoid(au_plink_list, struct super_block *sb);
++AuStubInt0(au_plink_test, struct inode *inode);
++AuStub(struct dentry *, au_plink_lkup, return NULL,
++ struct inode *inode, aufs_bindex_t bindex);
++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++AuStubVoid(au_plink_put, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose);
++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
++#endif /* CONFIG_PROC_FS */
+
+/* ---------------------------------------------------------------------- */
+
+static inline void au_iigen_dec(struct inode *inode)
+{
+#ifdef CONFIG_AUFS_HNOTIFY
-+ atomic_dec_return(&au_ii(inode)->ii_generation);
++ atomic_dec(&au_ii(inode)->ii_generation);
+#endif
+}
+
+#endif /* __AUFS_INODE_H__ */
diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
--- /usr/share/empty/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/ioctl.c 2010-08-21 21:00:02.980020464 +0200
-@@ -0,0 +1,155 @@
++++ linux/fs/aufs/ioctl.c 2010-10-01 13:09:26.469878166 +0200
+@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ err = fd;
+ goto out; /* success */
+
-+ out_fd:
++out_fd:
+ put_unused_fd(fd);
-+ out:
++out:
+ return err;
+}
+
+ long err;
+
+ switch (cmd) {
-+ case AUFS_CTL_PLINK_MAINT:
-+ case AUFS_CTL_PLINK_CLEAN:
-+ err = au_plink_ioctl(file, cmd);
-+ break;
-+
+ case AUFS_CTL_RDU:
+ case AUFS_CTL_RDU_INO:
+ err = au_rdu_ioctl(file, cmd, arg);
+#endif
diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
--- /usr/share/empty/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_add.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,672 @@
++++ linux/fs/aufs/i_op_add.c 2010-10-01 13:09:26.468878166 +0200
+@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ } else
+ dput(wh);
+
-+ out:
++out:
+ return err;
+}
+
+ if (unlikely(h_parent != h_dentry->d_parent))
+ err = -EIO;
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+
+ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
+
-+ out_unpin:
++out_unpin:
+ if (IS_ERR(wh_dentry))
+ au_unpin(pin);
-+ out:
++out:
+ return wh_dentry;
+}
+
+ au_unpin(&pin);
+ dput(wh_dentry);
+
-+ out:
++out:
+ if (unlikely(err)) {
+ au_update_dbstart(dentry);
+ d_drop(dentry);
+ au_h_open_post(src_dentry, a->bsrc, h_file);
+ au_unpin(&a->pin);
+
-+ out:
++out:
+ di_read_unlock(a->src_parent, AuLock_IR);
+ return err;
+}
+ goto out;
+
+ a->parent = dentry->d_parent; /* dir inode is locked */
-+ aufs_read_and_write_lock2(dentry, src_dentry, /*AuLock_FLUSH*/0);
++ err = aufs_read_and_write_lock2(dentry, src_dentry, AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_kfree;
++
+ a->src_parent = dget_parent(src_dentry);
+ wr_dir_args.force_btgt = au_dbstart(src_dentry);
+
+ d_drop(dentry);
+ goto out_unpin; /* success */
+
-+ out_revert:
++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:
++out_dt:
+ d_drop(dentry);
+ au_dtime_revert(&dt);
-+ out_unpin:
++out_unpin:
+ au_unpin(&a->pin);
-+ out_wh:
++out_wh:
+ dput(wh_dentry);
-+ out_unlock:
++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);
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out_dir:
++out_dir:
+ AuLabel(revert dir);
+ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
+ if (rerr) {
+ }
+ d_drop(dentry);
+ au_dtime_revert(&a->dt);
-+ out_unlock:
++out_unlock:
+ au_unpin(&a->pin);
+ dput(wh_dentry);
-+ out_free:
++out_free:
+ if (unlikely(err)) {
+ au_update_dbstart(dentry);
+ d_drop(dentry);
+ di_write_unlock(parent);
+ aufs_read_unlock(dentry, AuLock_DW);
+ kfree(a);
-+ out:
++out:
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
--- /usr/share/empty/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op.c 2010-08-21 21:00:02.975972487 +0200
-@@ -0,0 +1,916 @@
++++ linux/fs/aufs/i_op.c 2010-10-01 13:09:26.468878166 +0200
+@@ -0,0 +1,922 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ }
+#endif
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out:
++out:
+ ii_read_unlock(inode);
+ si_read_unlock(sb);
+ return err;
+ if (unlikely(IS_ERR(ret) && inode))
+ ii_write_unlock(inode);
+
-+ out_unlock:
++out_unlock:
+ di_write_unlock(dentry);
-+ out:
++out:
+ si_read_unlock(sb);
+ return ret;
+}
+ /* copyup the new parent into the branch we process */
+ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
+
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+
+void au_unpin(struct au_pin *p)
+{
-+ if (au_ftest_pin(p->flags, MNT_WRITE))
++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE))
+ mnt_drop_write(p->h_mnt);
+ if (!p->hdir)
+ return;
+ * and h_parent can be NULL.
+ */
+ if (unlikely(!p->hdir || !h_dir || !h_parent)) {
++ err = -EBUSY;
+ if (!au_ftest_pin(p->flags, DI_LOCKED))
+ di_read_unlock(p->parent, AuLock_IR);
+ dput(p->parent);
+ }
+ goto out; /* success */
+
-+ out_unpin:
++out_unpin:
+ au_unpin(p);
-+ out_err:
++out_err:
+ pr_err("err %d\n", err);
+ err = au_busy_or_stale();
-+ out:
++out:
+ return err;
+}
+
+{
+ int err;
+ loff_t sz;
-+ aufs_bindex_t bstart;
++ aufs_bindex_t bstart, ibstart;
+ struct dentry *hi_wh, *parent;
+ struct inode *inode;
+ struct file *h_file;
+ if (S_ISDIR(inode->i_mode))
+ au_fset_wrdir(wr_dir_args.flags, ISDIR);
+ /* plink or hi_wh() case */
-+ if (bstart != au_ibstart(inode))
-+ wr_dir_args.force_btgt = au_ibstart(inode);
++ ibstart = au_ibstart(inode);
++ if (bstart != ibstart)
++ wr_dir_args.force_btgt = ibstart;
+ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
+ if (unlikely(err < 0))
+ goto out;
+ else
+ a->h_path.dentry = hi_wh; /* do not dget here */
+
-+ out_unlock:
++out_unlock:
+ mutex_unlock(&a->h_inode->i_mutex);
+ au_h_open_post(dentry, bstart, h_file);
+ a->h_inode = a->h_path.dentry->d_inode;
+ }
+
+ au_unpin(&a->pin);
-+ out_parent:
++out_parent:
+ if (parent) {
+ di_write_unlock(parent);
+ dput(parent);
+ }
-+ out:
++out:
+ return err;
+}
+
+
+ file = NULL;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_kfree;
++
+ if (ia->ia_valid & ATTR_FILE) {
+ /* currently ftruncate(2) only */
+ AuDebugOn(!S_ISREG(inode->i_mode));
+ if (!err)
+ au_cpup_attr_changeable(inode);
+
-+ out_unlock:
++out_unlock:
+ mutex_unlock(&a->h_inode->i_mutex);
+ au_unpin(&a->pin);
-+ out_dentry:
++out_dentry:
+ di_write_unlock(dentry);
+ if (file) {
+ fi_write_unlock(file);
+ ia->ia_file = file;
+ ia->ia_valid |= ATTR_FILE;
+ }
-+ out_si:
++out_si:
+ si_read_unlock(sb);
++out_kfree:
+ kfree(a);
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ err = 0;
+ sb = dentry->d_sb;
+ inode = dentry->d_inode;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ mnt_flags = au_mntflags(sb);
+ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
+
+ }
+ goto out;
+
-+ out_fill:
++out_fill:
+ generic_fillattr(inode, st);
-+ out:
++out:
+ di_read_unlock(dentry, AuLock_IR);
+ si_read_unlock(sb);
+ return err;
+ }
+ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz);
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ __putname(buf.k);
+
-+ out:
++out:
+ path_put(&nd->path);
+ AuTraceErr(err);
+ return ERR_PTR(err);
+};
diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
--- /usr/share/empty/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_del.c 2010-08-21 21:00:02.975972487 +0200
++++ linux/fs/aufs/i_op_del.c 2010-10-01 13:09:26.468878166 +0200
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ AuDbg("need_wh %d\n", need_wh);
+ err = need_wh;
+
-+ out:
++out:
+ return err;
+}
+
+ err = 0;
+ dput(h_latest);
+
-+ out:
++out:
+ return err;
+}
+
+ /* returns with the parent is locked and wh_dentry is dget-ed */
+ goto out; /* success */
+
-+ out_unpin:
++out_unpin:
+ au_unpin(pin);
-+ out:
++out:
+ return wh_dentry;
+}
+
+ err = 0;
+ }
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ err = rerr;
+ }
+
-+ out_unlock:
++out_unlock:
+ au_unpin(&pin);
+ dput(wh_dentry);
+ dput(h_path.dentry);
-+ out:
++out:
+ di_write_unlock(parent);
+ aufs_read_unlock(dentry, AuLock_DW);
+ return err;
+ err = rerr;
+ }
+
-+ out_unpin:
++out_unpin:
+ au_unpin(&pin);
+ dput(wh_dentry);
+ dput(h_dentry);
-+ out_args:
++out_args:
+ di_write_unlock(parent);
+ if (args)
+ au_whtmp_rmdir_free(args);
-+ out_unlock:
++out_unlock:
+ aufs_read_unlock(dentry, AuLock_DW);
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
--- /usr/share/empty/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_ren.c 2010-08-21 21:00:02.980020464 +0200
-@@ -0,0 +1,977 @@
++++ linux/fs/aufs/i_op_ren.c 2010-10-01 13:09:26.468878166 +0200
+@@ -0,0 +1,980 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ err = 0;
+ goto out_success;
+
-+ out_diropq:
++out_diropq:
+ if (au_ftest_ren(a->flags, DIROPQ))
+ au_ren_rev_diropq(err, a);
-+ out_rename:
++out_rename:
+ if (!au_ftest_ren(a->flags, CPUP))
+ au_ren_rev_rename(err, a);
+ else
+ au_ren_rev_cpup(err, a);
-+ out_whtmp:
++out_whtmp:
+ if (a->thargs)
+ au_ren_rev_whtmp(err, a);
-+ out_whdst:
++out_whdst:
+ dput(a->dst_wh_dentry);
+ a->dst_wh_dentry = NULL;
-+ out_whsrc:
++out_whsrc:
+ if (a->src_wh_dentry)
+ au_ren_rev_whsrc(err, a);
+ au_ren_rev_drop(a);
-+ out_success:
++out_success:
+ dput(a->src_wh_dentry);
+ dput(a->dst_wh_dentry);
-+ out_thargs:
++out_thargs:
+ if (a->thargs) {
+ dput(a->h_dst);
+ au_whtmp_rmdir_free(a->thargs);
+ a->thargs = NULL;
+ }
-+ out:
++out:
+ return err;
+}
+
+
+ err = au_test_empty_lower(dentry);
+
-+ out:
++out:
+ if (err == -ENOTEMPTY) {
+ AuWarn1("renaming dir who has child(ren) on multiple branches,"
+ " is not supported\n");
+ a->whlist.nh_num = 0;
+ }
+ }
-+ out:
++out:
+ return err;
+}
+
+ err = 0;
+ }
+
-+ out:
++out:
+ if (unlikely(err == -ENOENT || err == -EEXIST))
+ err = -EIO;
+ AuTraceErr(err);
+
+ err = au_busy_or_stale();
+
-+ out_unlock:
++out_unlock:
+ au_ren_unlock(a);
-+ out:
++out:
+ return err;
+}
+
+int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
+ struct inode *_dst_dir, struct dentry *_dst_dentry)
+{
-+ int err;
++ int err, flags;
+ /* reduce stack space */
+ struct au_ren_args *a;
+
+ }
+
+ err = -ENOTDIR;
++ flags = AuLock_FLUSH | AuLock_NOPLM;
+ 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)))
+ goto out_free;
-+ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
-+ AuLock_DIR | AuLock_FLUSH);
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ AuLock_DIR | flags);
+ } else
-+ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
-+ AuLock_FLUSH);
++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ flags);
++ if (unlikely(err))
++ goto out_free;
+
+ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
+ di_write_lock_parent(a->dst_parent);
+
+ goto out_hdir; /* success */
+
-+ out_dt:
++out_dt:
+ au_ren_rev_dt(err, a);
-+ out_hdir:
++out_hdir:
+ au_ren_unlock(a);
-+ out_children:
++out_children:
+ au_nhash_wh_free(&a->whlist);
-+ out_unlock:
++out_unlock:
+ if (unlikely(err && au_ftest_ren(a->flags, ISDIR))) {
+ au_update_dbstart(a->dst_dentry);
+ d_drop(a->dst_dentry);
+ else
+ di_write_unlock2(a->src_parent, a->dst_parent);
+ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
-+ out_free:
++out_free:
+ iput(a->dst_inode);
+ if (a->thargs)
+ au_whtmp_rmdir_free(a->thargs);
+ kfree(a);
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig
--- /usr/share/empty/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/Kconfig 2010-08-21 21:00:02.972333781 +0200
-@@ -0,0 +1,175 @@
++++ linux/fs/aufs/Kconfig 2010-10-01 13:09:26.342878167 +0200
+@@ -0,0 +1,182 @@
+config AUFS_FS
+ tristate "Aufs (Advanced multi layered unification filesystem) support"
+ depends on EXPERIMENTAL
+ resources and has a minor impact to performance.
+endchoice
+
++config AUFS_SBILIST
++ bool
++ depends on AUFS_MAGIC_SYSRQ || PROC_FS
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq or /proc, enabled automatically.
++
+config AUFS_HNOTIFY
+ bool "Detect direct branch access (bypassing aufs)"
+ help
+ It will have a negative impact to the performance.
+ See detail in aufs.5.
+
-+
+choice
+ prompt "method" if AUFS_HNOTIFY
+ default AUFS_HFSNOTIFY
+endif
diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c
--- /usr/share/empty/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/loop.c 2010-08-21 21:00:02.980020464 +0200
++++ linux/fs/aufs/loop.c 2010-10-01 13:09:26.469878166 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+}
diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h
--- /usr/share/empty/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/loop.h 2010-08-21 21:00:02.980020464 +0200
++++ linux/fs/aufs/loop.h 2010-10-01 13:09:26.469878166 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_LOOP_H__ */
diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk
--- /usr/share/empty/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/magic.mk 2010-08-21 21:00:02.982333916 +0200
++++ linux/fs/aufs/magic.mk 2010-10-01 13:09:26.469878166 +0200
@@ -0,0 +1,54 @@
+
+# defined in ${srctree}/fs/fuse/inode.c
+endif
diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
--- /usr/share/empty/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/Makefile 2010-08-21 21:00:02.972333781 +0200
-@@ -0,0 +1,38 @@
++++ linux/fs/aufs/Makefile 2010-10-01 13:09:26.342878167 +0200
+@@ -0,0 +1,39 @@
+
+include ${src}/magic.mk
+ifeq (${CONFIG_AUFS_FS},m)
+obj-$(CONFIG_AUFS_FS) += aufs.o
+aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
+ wkq.o vfsub.o dcsub.o \
-+ cpup.o whout.o plink.o wbr_policy.o \
++ cpup.o whout.o wbr_policy.o \
+ dinfo.o dentry.o \
+ dynop.o \
+ finfo.o file.o f_op.o \
+ ioctl.o
+
+# all are boolean
++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
+aufs-$(CONFIG_SYSFS) += sysfs.o
+aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
+aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
+aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
--- /usr/share/empty/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,171 @@
++++ linux/fs/aufs/module.c 2010-10-01 13:09:26.469878166 +0200
+@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+
+int au_dir_roflags;
+
++#ifdef CONFIG_AUFS_SBILIST
++struct au_splhead au_sbilist;
++#endif
++
+/*
+ * functions for module interface.
+ */
+
+ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
+
++ au_sbilist_init();
+ sysaufs_brs_init();
+ au_debug_init();
+ au_dy_init();
+ err = sysaufs_init();
+ if (unlikely(err))
+ goto out;
-+ err = au_wkq_init();
++ err = au_procfs_init();
+ if (unlikely(err))
+ goto out_sysaufs;
++ err = au_wkq_init();
++ if (unlikely(err))
++ goto out_procfs;
+ err = au_hnotify_init();
+ if (unlikely(err))
+ goto out_wkq;
+ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
+ goto out; /* success */
+
-+ out_cache:
++out_cache:
+ au_cache_fin();
-+ out_sysrq:
++out_sysrq:
+ au_sysrq_fin();
-+ out_hin:
++out_hin:
+ au_hnotify_fin();
-+ out_wkq:
++out_wkq:
+ au_wkq_fin();
-+ out_sysaufs:
++out_procfs:
++ au_procfs_fin();
++out_sysaufs:
+ sysaufs_fin();
+ au_dy_fin();
-+ out:
++out:
+ return err;
+}
+
+ au_sysrq_fin();
+ au_hnotify_fin();
+ au_wkq_fin();
++ au_procfs_fin();
+ sysaufs_fin();
+ au_dy_fin();
+}
+module_exit(aufs_exit);
diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
--- /usr/share/empty/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.h 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,82 @@
++++ linux/fs/aufs/module.h 2010-10-01 13:09:26.469878166 +0200
+@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
+int au_seq_path(struct seq_file *seq, struct path *path);
+
-+/* ---------------------------------------------------------------------- */
-+
-+/* kmem cache */
++#ifdef CONFIG_PROC_FS
++/* procfs.c */
++int __init au_procfs_init(void);
++void au_procfs_fin(void);
++#else
++AuStubInt0(au_procfs_init, void);
++AuStubVoid(au_procfs_fin, void);
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++/* kmem cache */
+enum {
+ AuCache_DINFO,
+ AuCache_ICNTNR,
+#endif /* __AUFS_MODULE_H__ */
diff -urN /usr/share/empty/fs/aufs/mtx.h linux/fs/aufs/mtx.h
--- /usr/share/empty/fs/aufs/mtx.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/mtx.h 2010-08-21 21:00:02.982333916 +0200
++++ linux/fs/aufs/mtx.h 2010-10-01 13:09:26.469878166 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Junjiro R. Okajima
+#endif /* __AUFS_MTX_H__ */
diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
--- /usr/share/empty/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/opts.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,1585 @@
++++ linux/fs/aufs/opts.c 2010-10-01 13:09:26.470878166 +0200
+@@ -0,0 +1,1595 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ */
+
+#include <linux/file.h>
++#include <linux/jiffies.h>
+#include <linux/namei.h>
+#include <linux/types.h> /* a distribution requires */
+#include <linux/parser.h>
+ {Opt_trunc_xib, "trunc_xib"},
+ {Opt_notrunc_xib, "notrunc_xib"},
+
++#ifdef CONFIG_PROC_FS
+ {Opt_plink, "plink"},
++#else
++ {Opt_ignore_silent, "plink"},
++#endif
++
+ {Opt_noplink, "noplink"},
++
+#ifdef CONFIG_AUFS_DEBUG
+ {Opt_list_plink, "list_plink"},
+#endif
+ int n, err;
+
+ err = 0;
-+ if (!match_int(arg, &n) && 0 <= n)
++ if (!match_int(arg, &n) && 0 <= n && n <= MAX_SEC_IN_JIFFIES)
+ create->mfs_second = n;
+ else {
+ pr_err("bad integer in %s\n", str);
+ pr_err("lookup failed %s (%d)\n", add->pathname, err);
+ err = -EINVAL;
+
-+ out:
++out:
+ return err;
+}
+
+ del->h_path.dentry = dget(au_h_dptr(root, bindex));
+ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
+
-+ out:
++out:
+ aufs_read_unlock(root, !AuLock_IR);
+ return err;
+}
+ mod->h_root = dget(path.dentry);
+ path_put(&path);
+
-+ out:
++out:
+ return err;
+}
+
+ mod->path, mod->perm, args[1].from);
+ mod->h_root = dget(au_h_dptr(root, bindex));
+
-+ out:
++out:
+ aufs_read_unlock(root, !AuLock_IR);
+ return err;
+}
+ xino->file = file;
+ xino->path = args[0].from;
+
-+ out:
++out:
+ return err;
+}
+
+ err = -EINVAL;
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ break;
+
+ case Opt_rdcache:
-+ if (unlikely(match_int(&a->args[0], &opt->rdcache)))
++ if (unlikely(match_int(&a->args[0], &opt->rdcache)
++ || opt->rdcache > MAX_SEC_IN_JIFFIES))
+ break;
+ err = 0;
+ opt->type = token;
+ if (unlikely(err))
+ au_opts_free(opts);
+
-+ out:
++out:
+ return err;
+}
+
+ case AuWbrCreate_MFSV:
+ case AuWbrCreate_PMFS:
+ case AuWbrCreate_PMFSV:
-+ sbinfo->si_wbr_mfs.mfs_expire = create->mfs_second * HZ;
++ sbinfo->si_wbr_mfs.mfs_expire
++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
+ break;
+ }
+
+ break;
+ case Opt_noplink:
+ if (au_opt_test(sbinfo->si_mntflags, PLINK))
-+ au_plink_put(sb);
++ au_plink_put(sb, /*verbose*/1);
+ au_opt_clr(sbinfo->si_mntflags, PLINK);
+ break;
+ case Opt_list_plink:
+ break;
+
+ case Opt_rdcache:
-+ sbinfo->si_rdcache = opt->rdcache * HZ;
++ sbinfo->si_rdcache
++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
+ break;
+ case Opt_rdblk:
+ sbinfo->si_rdblk = opt->rdblk;
+ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
--- /usr/share/empty/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/opts.h 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,198 @@
++++ linux/fs/aufs/opts.h 2010-10-01 13:09:26.470878166 +0200
+@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+} while (0)
+#define au_opt_clr(flags, name) { ((flags) &= ~AuOpt_##name); }
+
++static inline unsigned int au_opts_plink(unsigned int mntflags)
++{
++#ifdef CONFIG_PROC_FS
++ return mntflags;
++#else
++ return mntflags & ~AuOpt_PLINK;
++#endif
++}
++
+/* ---------------------------------------------------------------------- */
+
+/* policies to select one among multiple writable branches */
+#endif /* __AUFS_OPTS_H__ */
diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
--- /usr/share/empty/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/plink.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,451 @@
++++ linux/fs/aufs/plink.c 2010-10-01 13:09:26.470878166 +0200
+@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+#include "aufs.h"
+
+/*
++ * the pseudo-link maintenance mode.
+ * during a user process maintains the pseudo-links,
+ * prohibit adding a new plink and branch manipulation.
++ *
++ * Flags
++ * NOPLM:
++ * For entry functions which will handle plink, and i_mutex is already held
++ * in VFS.
++ * They cannot wait and should return an error at once.
++ * Callers has to check the error.
++ * NOPLMW:
++ * For entry functions which will handle plink, but i_mutex is not held
++ * in VFS.
++ * They can wait the plink maintenance mode to finish.
++ *
++ * They behave like F_SETLK and F_SETLKW.
++ * If the caller never handle plink, then both flags are unnecessary.
+ */
-+void au_plink_maint_block(struct super_block *sb)
++
++int au_plink_maint(struct super_block *sb, int flags)
+{
-+ struct au_sbinfo *sbi = au_sbi(sb);
++ int err;
++ pid_t pid, ppid;
++ struct au_sbinfo *sbi;
+
+ SiMustAnyLock(sb);
+
-+ /* gave up wake_up_bit() */
-+ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint);
++ err = 0;
++ if (!au_opt_test(au_mntflags(sb), PLINK))
++ goto out;
++
++ sbi = au_sbi(sb);
++ pid = sbi->si_plink_maint_pid;
++ if (!pid || pid == current->pid)
++ goto out;
++
++ /* todo: it highly depends upon /sbin/mount.aufs */
++ rcu_read_lock();
++ ppid = task_pid_vnr(rcu_dereference(current->real_parent));
++ rcu_read_unlock();
++ if (pid == ppid)
++ 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.
++ */
++ while (sbi->si_plink_maint_pid) {
++ si_read_unlock(sb);
++ /* gave up wake_up_bit() */
++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid);
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&sbi->si_nowait);
++ si_noflush_read_lock(sb);
++ }
++ } else if (au_ftest_lock(flags, NOPLM)) {
++ AuDbg("ppid %d, pid %d\n", ppid, pid);
++ err = -EAGAIN;
++ }
++
++out:
++ return err;
+}
+
-+void au_plink_maint_leave(struct file *file)
++void au_plink_maint_leave(struct au_sbinfo *sbinfo)
+{
-+ struct au_sbinfo *sbinfo;
+ int iam;
+
-+ AuDebugOn(atomic_long_read(&file->f_count));
-+
-+ sbinfo = au_sbi(file->f_dentry->d_sb);
+ spin_lock(&sbinfo->si_plink_maint_lock);
-+ iam = (sbinfo->si_plink_maint == file);
++ iam = (sbinfo->si_plink_maint_pid == current->pid);
+ if (iam)
-+ sbinfo->si_plink_maint = NULL;
++ sbinfo->si_plink_maint_pid = 0;
+ spin_unlock(&sbinfo->si_plink_maint_lock);
+ if (iam)
+ wake_up_all(&sbinfo->si_plink_wq);
+}
+
-+static int au_plink_maint_enter(struct file *file)
++int au_plink_maint_enter(struct super_block *sb)
+{
+ int err;
-+ struct super_block *sb;
+ struct au_sbinfo *sbinfo;
+
+ err = 0;
-+ sb = file->f_dentry->d_sb;
+ sbinfo = au_sbi(sb);
+ /* make sure i am the only one in this fs */
-+ si_write_lock(sb);
-+ /* spin_lock(&sbinfo->si_plink_maint_lock); */
-+ if (!sbinfo->si_plink_maint)
-+ sbinfo->si_plink_maint = file;
-+ else
-+ err = -EBUSY;
-+ /* spin_unlock(&sbinfo->si_plink_maint_lock); */
++ si_write_lock(sb, AuLock_FLUSH);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ if (!sbinfo->si_plink_maint_pid)
++ sbinfo->si_plink_maint_pid = current->pid;
++ else
++ err = -EBUSY;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ }
+ si_write_unlock(sb);
+
+ return err;
+
+ sbinfo = au_sbi(sb);
+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+ plink_list = &sbinfo->si_plink.head;
+ rcu_read_lock();
+ sbinfo = au_sbi(inode->i_sb);
+ AuRwMustAnyLock(&sbinfo->si_rwsem);
+ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK));
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
+
+ found = 0;
+ plink_list = &sbinfo->si_plink.head;
+ .name = a
+ };
+
++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM));
++
+ br = au_sbr(inode->i_sb, bindex);
+ h_parent = br->br_wbr->wbr_plink;
+ h_dir = h_parent->d_inode;
+ struct inode *h_dir;
+
+ h_dir = h_parent->d_inode;
-+ again:
++again:
+ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL);
+ err = PTR_ERR(h_path.dentry);
+ if (IS_ERR(h_path.dentry))
+ err = vfsub_link(h_dentry, h_dir, &h_path);
+ dput(h_path.dentry);
+
-+ out:
++out:
+ return err;
+}
+
+ sb = inode->i_sb;
+ sbinfo = au_sbi(sb);
+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+ cnt = 0;
+ found = 0;
+ cnt++;
+ WARN_ONCE(cnt > AUFS_PLINK_WARN,
+ "unexpectedly many pseudo links, %d\n", cnt);
-+ au_plink_maint_block(sb);
+ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
+ } else {
+ do_put_plink(tmp, 0);
+}
+
+/* free all plinks */
-+void au_plink_put(struct super_block *sb)
++void au_plink_put(struct super_block *sb, int verbose)
+{
+ struct au_sbinfo *sbinfo;
+ struct list_head *plink_list;
+
+ sbinfo = au_sbi(sb);
+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+ plink_list = &sbinfo->si_plink.head;
+ /* no spin_lock since sbinfo is write-locked */
++ WARN(verbose && !list_empty(plink_list), "pseudo-link is not flushed");
+ list_for_each_entry_safe(plink, tmp, plink_list, list)
+ do_put_plink(plink, 0);
+ INIT_LIST_HEAD(plink_list);
+}
+
++void au_plink_clean(struct super_block *sb, int verbose)
++{
++ struct dentry *root;
++
++ root = sb->s_root;
++ aufs_write_lock(root);
++ if (au_opt_test(au_mntflags(sb), PLINK))
++ au_plink_put(sb, verbose);
++ aufs_write_unlock(root);
++}
++
+/* free the plinks on a branch specified by @br_id */
+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
+{
+
+ sbinfo = au_sbi(sb);
+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM));
+
+ plink_list = &sbinfo->si_plink.head;
+ /* no spin_lock since sbinfo is write-locked */
+ iput(inode);
+ }
+}
-+
-+/* ---------------------------------------------------------------------- */
-+
-+long au_plink_ioctl(struct file *file, unsigned int cmd)
-+{
-+ long err;
-+ struct super_block *sb;
-+
-+ err = -EACCES;
-+ if (!capable(CAP_SYS_ADMIN))
-+ goto out;
-+
-+ err = 0;
-+ sb = file->f_dentry->d_sb;
-+ switch (cmd) {
-+ case AUFS_CTL_PLINK_MAINT:
-+ /*
-+ * pseudo-link maintenance mode,
-+ * cleared by aufs_release_dir()
-+ */
-+ err = au_plink_maint_enter(file);
-+ break;
-+ case AUFS_CTL_PLINK_CLEAN:
-+ aufs_write_lock(sb->s_root);
-+ if (au_opt_test(au_mntflags(sb), PLINK))
-+ au_plink_put(sb);
-+ aufs_write_unlock(sb->s_root);
-+ break;
-+ default:
-+ /* err = -ENOTTY; */
-+ err = -EINVAL;
-+ }
-+ out:
-+ return err;
-+}
diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c
--- /usr/share/empty/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/poll.c 2010-08-21 21:00:02.982333916 +0200
++++ linux/fs/aufs/poll.c 2010-10-01 13:09:26.488878162 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ mask = POLLERR /* | POLLIN | POLLOUT */;
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
+ if (unlikely(err))
+ goto out;
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
+
-+ out:
++out:
+ si_read_unlock(sb);
+ AuTraceErr((int)mask);
+ return mask;
+}
+diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c
+--- /usr/share/empty/fs/aufs/procfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/fs/aufs/procfs.c 2010-10-01 13:09:26.488878162 +0200
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2010 Junjiro R. Okajima
++ *
++ * This program, aufs is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * procfs interfaces
++ */
++
++#include <linux/proc_fs.h>
++#include "aufs.h"
++
++static int au_procfs_plm_release(struct inode *inode, struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo) {
++ au_plink_maint_leave(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++ }
++
++ return 0;
++}
++
++static void au_procfs_plm_write_clean(struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = file->private_data;
++ if (sbinfo)
++ au_plink_clean(sbinfo->si_sb, /*verbose*/0);
++}
++
++static int au_procfs_plm_write_si(struct file *file, unsigned long id)
++{
++ int err;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = -EBUSY;
++ if (unlikely(file->private_data))
++ goto out;
++
++ sb = NULL;
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
++ if (id == sysaufs_si_id(sbinfo)) {
++ kobject_get(&sbinfo->si_kobj);
++ sb = sbinfo->si_sb;
++ break;
++ }
++ spin_unlock(&au_sbilist.spin);
++
++ err = -EINVAL;
++ if (unlikely(!sb))
++ goto out;
++
++ err = au_plink_maint_enter(sb);
++ if (!err)
++ /* keep kobject_get() */
++ file->private_data = sbinfo;
++ else
++ kobject_put(&sbinfo->si_kobj);
++out:
++ return err;
++}
++
++/*
++ * Accept a valid "si=xxxx" only.
++ * Once it is accepted successfully, accept "clean" too.
++ */
++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ unsigned long id;
++ /* last newline is allowed */
++ char buf[3 + sizeof(unsigned long) * 2 + 1];
++
++ err = -EACCES;
++ if (unlikely(!capable(CAP_SYS_ADMIN)))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(count > sizeof(buf)))
++ goto out;
++
++ err = copy_from_user(buf, ubuf, count);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ goto out;
++ }
++ buf[count] = 0;
++
++ err = -EINVAL;
++ if (!strcmp("clean", buf)) {
++ au_procfs_plm_write_clean(file);
++ goto out_success;
++ } else if (unlikely(strncmp("si=", buf, 3)))
++ goto out;
++
++ err = strict_strtoul(buf + 3, 16, &id);
++ if (unlikely(err))
++ goto out;
++
++ err = au_procfs_plm_write_si(file, id);
++ if (unlikely(err))
++ goto out;
++
++out_success:
++ err = count; /* success */
++out:
++ return err;
++}
++
++static const struct file_operations au_procfs_plm_fop = {
++ .write = au_procfs_plm_write,
++ .release = au_procfs_plm_release,
++ .owner = THIS_MODULE
++};
++
++/* ---------------------------------------------------------------------- */
++
++static struct proc_dir_entry *au_procfs_dir;
++
++void au_procfs_fin(void)
++{
++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir);
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++}
++
++int __init au_procfs_init(void)
++{
++ int err;
++ struct proc_dir_entry *entry;
++
++ err = -ENOMEM;
++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL);
++ if (unlikely(!au_procfs_dir))
++ goto out;
++
++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR,
++ au_procfs_dir, &au_procfs_plm_fop);
++ if (unlikely(!entry))
++ goto out_dir;
++
++ err = 0;
++ goto out; /* success */
++
++
++out_dir:
++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL);
++out:
++ return err;
++}
diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
--- /usr/share/empty/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/rdu.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,377 @@
++++ linux/fs/aufs/rdu.c 2010-10-01 13:09:26.489878162 +0200
+@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ rdu->tail = arg->ent;
+ }
+
-+ out:
++out:
+ /* AuTraceErr(err); */
+ return err;
+}
+ && !au_ftest_rdu(cookie->flags, FULL));
+ cookie->h_pos = h_file->f_pos;
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ goto out_mtx;
+
+ arg.sb = inode->i_sb;
-+ si_read_lock(arg.sb, AuLock_FLUSH);
++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ /* todo: reval? */
+ fi_read_lock(file);
+
+ err = -EAGAIN;
+ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
+ ii_read_unlock(inode);
+
-+ out_unlock:
++out_unlock:
+ fi_read_unlock(file);
+ si_read_unlock(arg.sb);
-+ out_mtx:
++out_mtx:
+ mutex_unlock(&inode->i_mutex);
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ err = -EINVAL;
+ }
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ err = -EINVAL;
+ }
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+#endif
diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h
--- /usr/share/empty/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/rwsem.h 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,187 @@
++++ linux/fs/aufs/rwsem.h 2010-10-01 13:09:26.489878162 +0200
+@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ smp_mb(); /* atomic set */ \
+} while (0)
+
-+#define AuDbgRcntInc(rw) atomic_inc_return(&(rw)->rcnt)
++#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt)
+#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
-+#define AuDbgWcntInc(rw) WARN_ON(atomic_inc_return(&(rw)->wcnt) > 1)
++#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt)
+#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
+#else
+#define AuDbgCntInit(rw) do {} while (0)
+#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \
+ || atomic_read(&(rw)->wcnt))
+
++#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key)
++
+static inline void au_rw_init(struct au_rwsem *rw)
+{
+ AuDbgCntInit(rw);
+#endif /* __AUFS_RWSEM_H__ */
diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
--- /usr/share/empty/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sbinfo.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,269 @@
++++ linux/fs/aufs/sbinfo.c 2010-10-01 13:09:26.489878162 +0200
+@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ * superblock private data
+ */
+
++#include <linux/jiffies.h>
+#include "aufs.h"
+
+/*
+void au_si_free(struct kobject *kobj)
+{
+ struct au_sbinfo *sbinfo;
-+ struct super_block *sb;
+ char *locked __maybe_unused; /* debug only */
+
+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+ AuDebugOn(!list_empty(&sbinfo->si_plink.head));
-+ AuDebugOn(sbinfo->si_plink_maint);
++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
+
-+ sb = sbinfo->si_sb;
-+ si_write_lock(sb);
-+ au_xino_clr(sb);
++ au_rw_write_lock(&sbinfo->si_rwsem);
+ au_br_free(sbinfo);
-+ si_write_unlock(sb);
++ au_rw_write_unlock(&sbinfo->si_rwsem);
+
+ AuDebugOn(radix_tree_gang_lookup
+ (&sbinfo->au_si_pid.tree, (void **)&locked,
+{
+ int err;
+ struct au_sbinfo *sbinfo;
++ static struct lock_class_key aufs_si;
+
+ err = -ENOMEM;
+ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS);
+
+ au_nwt_init(&sbinfo->si_nowait);
+ au_rw_init_wlock(&sbinfo->si_rwsem);
++ au_rw_class(&sbinfo->si_rwsem, &aufs_si);
+ spin_lock_init(&sbinfo->au_si_pid.tree_lock);
+ INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
+
+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup;
+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create;
+
-+ sbinfo->si_mntflags = AuOpt_Def;
++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def);
+
+ mutex_init(&sbinfo->si_xib_mtx);
+ sbinfo->si_xino_brid = -1;
+ /* leave si_xib_last_pindex and si_xib_next_bit */
+
-+ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ;
++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC);
+ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
+ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
+ sbinfo->si_dirwh = AUFS_DIRWH_DEF;
+ au_debug_sbinfo_init(sbinfo);
+ return 0; /* success */
+
-+ out_br:
++out_br:
+ kfree(sbinfo->si_branch);
-+ out_pidmap:
++out_pidmap:
+ kfree(sbinfo->au_si_pid.bitmap);
-+ out_sbinfo:
++out_sbinfo:
+ kfree(sbinfo);
-+ out:
++out:
+ return err;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
++/* it is ok that new 'nwt' tasks are appended while we are sleeping */
++int si_read_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ err = 0;
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_read_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_read_unlock(sb);
++
++ return err;
++}
++
++int si_write_lock(struct super_block *sb, int flags)
++{
++ int err;
++
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++
++ si_noflush_write_lock(sb);
++ err = au_plink_maint(sb, flags);
++ if (unlikely(err))
++ si_write_unlock(sb);
++
++ return err;
++}
++
+/* dentry and super_block lock. call at entry point */
-+void aufs_read_lock(struct dentry *dentry, int flags)
++int aufs_read_lock(struct dentry *dentry, int flags)
+{
-+ si_read_lock(dentry->d_sb, flags);
-+ if (au_ftest_lock(flags, DW))
-+ di_write_lock_child(dentry);
-+ else
-+ di_read_lock_child(dentry, flags);
++ int err;
++
++ 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);
++ }
++
++ return err;
+}
+
+void aufs_read_unlock(struct dentry *dentry, int flags)
+
+void aufs_write_lock(struct dentry *dentry)
+{
-+ si_write_lock(dentry->d_sb);
++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW);
+ di_write_lock_child(dentry);
+}
+
+ si_write_unlock(dentry->d_sb);
+}
+
-+void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
+{
-+ si_read_lock(d1->d_sb, flags);
-+ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
++ int err;
++
++ err = si_read_lock(d1->d_sb, flags);
++ if (!err)
++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
++ return err;
+}
+
+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2)
+}
diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
--- /usr/share/empty/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/spl.h 2010-08-21 21:00:02.982333916 +0200
++++ linux/fs/aufs/spl.h 2010-10-01 13:09:26.489878162 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_SPL_H__ */
diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
--- /usr/share/empty/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/super.c 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,848 @@
++++ linux/fs/aufs/super.c 2010-10-01 13:09:26.489878162 +0200
+@@ -0,0 +1,863 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ */
+
+#include <linux/buffer_head.h>
++#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+ inode = ERR_PTR(err);
+ }
+
-+ out:
++out:
+ /* never return NULL */
+ AuDebugOn(!inode);
+ AuTraceErrPtr(inode);
+ break;
+ case AuWbrCreate_MFSV:
+ seq_printf(m, /*pat*/"mfs:%lu",
-+ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
+ break;
+ case AuWbrCreate_PMFSV:
+ seq_printf(m, /*pat*/"pmfs:%lu",
-+ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
+ break;
+ case AuWbrCreate_MFSRR:
+ seq_printf(m, /*pat*/"mfsrr:%llu",
+ case AuWbrCreate_MFSRRV:
+ seq_printf(m, /*pat*/"mfsrr:%llu:%lu",
+ sbinfo->si_wbr_mfs.mfsrr_watermark,
-+ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire)
++ / MSEC_PER_SEC);
+ break;
+ }
+}
+ seq_puts(seq, ",xino=");
+ err = au_xino_path(seq, f);
+
-+ out:
++out:
+ return err;
+#endif
+}
+
+ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
+
-+ n = sbinfo->si_rdcache / HZ;
++ n = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
+ AuUInt(RDCACHE, rdcache, n);
+
+ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
+ AuBool(WARN_PERM, warn_perm);
+ AuBool(VERBOSE, verbose);
+
-+ out:
++out:
+ /* be sure to print "br:" last */
+ if (!sysaufs_brs) {
+ seq_puts(m, ",br:");
+ buf->f_files = files;
+ buf->f_ffree = ffree;
+
-+ out:
++out:
+ return err;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
-+/*
-+ * this IS NOT for super_operations.
-+ * I guess it will be reverted someday.
-+ */
-+static void aufs_umount_begin(struct super_block *sb)
-+{
-+ struct au_sbinfo *sbinfo;
-+
-+ sbinfo = au_sbi(sb);
-+ if (!sbinfo)
-+ return;
-+
-+ si_write_lock(sb);
-+ if (au_opt_test(au_mntflags(sb), PLINK))
-+ au_plink_put(sb);
-+ if (sbinfo->si_wbr_create_ops->fin)
-+ sbinfo->si_wbr_create_ops->fin(sb);
-+ si_write_unlock(sb);
-+}
-+
+/* final actions when unmounting a file system */
+static void aufs_put_super(struct super_block *sb)
+{
+ if (!sbinfo)
+ return;
+
-+ aufs_umount_begin(sb);
+ dbgaufs_si_fin(sbinfo);
+ kobject_put(&sbinfo->si_kobj);
+}
+ }
+ }
+
-+ out_dpages:
++out_dpages:
+ au_dpages_free(&dpages);
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out_dpages:
++out_dpages:
+ au_dpages_free(&dpages);
-+ out:
++out:
+ return err;
+}
+
+ err = 0;
+ root = sb->s_root;
+ if (!data || !*data) {
-+ aufs_write_lock(root);
-+ err = au_opts_verify(sb, *flags, /*pending*/0);
-+ aufs_write_unlock(root);
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (!err) {
++ di_write_lock_child(root);
++ err = au_opts_verify(sb, *flags, /*pending*/0);
++ aufs_write_unlock(root);
++ }
+ goto out;
+ }
+
+ sbinfo = au_sbi(sb);
+ inode = root->d_inode;
+ mutex_lock(&inode->i_mutex);
-+ aufs_write_lock(root);
++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++ if (unlikely(err))
++ goto out_mtx;
++ di_write_lock_child(root);
+
+ /* au_opts_remount() may return an error */
+ err = au_opts_remount(sb, &opts);
+ }
+
+ aufs_write_unlock(root);
-+ mutex_unlock(&inode->i_mutex);
+
-+ out_opts:
++out_mtx:
++ mutex_unlock(&inode->i_mutex);
++out_opts:
+ free_page((unsigned long)opts.opt);
-+ out:
++out:
+ err = cvt_err(err);
+ AuTraceErr(err);
+ return err;
+ dput(root);
+ goto out; /* do not iput */
+
-+ out_iput:
++out_iput:
+ iget_failed(inode);
-+ iput(inode);
-+ out:
++out:
+ return err;
+
+}
+ if (!err)
+ goto out_opts; /* success */
+
-+ out_root:
++out_root:
+ dput(root);
+ sb->s_root = NULL;
-+ out_info:
++out_info:
+ kobject_put(&au_sbi(sb)->si_kobj);
+ sb->s_fs_info = NULL;
-+ out_opts:
++out_opts:
+ free_page((unsigned long)opts.opt);
-+ out:
++out:
+ AuTraceErr(err);
+ err = cvt_err(err);
+ AuTraceErr(err);
+ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt);
+ if (!err) {
+ sb = mnt->mnt_sb;
-+ si_write_lock(sb);
++ si_write_lock(sb, !AuLock_FLUSH);
+ sysaufs_brs_add(sb, 0);
+ si_write_unlock(sb);
++ au_sbilist_add(sb);
+ }
+ return err;
+}
+
++static void aufs_kill_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo) {
++ au_sbilist_del(sb);
++ aufs_write_lock(sb->s_root);
++ if (sbinfo->si_wbr_create_ops->fin)
++ 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);
++ }
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb, /*verbose*/1);
++ au_xino_clr(sb);
++ aufs_write_unlock(sb->s_root);
++
++ au_plink_maint_leave(sbinfo);
++ au_nwt_flush(&sbinfo->si_nowait);
++ }
++ generic_shutdown_super(sb);
++}
++
+struct file_system_type aufs_fs_type = {
+ .name = AUFS_FSTYPE,
+ .fs_flags =
+ FS_RENAME_DOES_D_MOVE /* a race between rename and others */
+ | FS_REVAL_DOT, /* for NFS branch and udba */
+ .get_sb = aufs_get_sb,
-+ .kill_sb = generic_shutdown_super,
++ .kill_sb = aufs_kill_sb,
+ /* no need to __module_get() and module_put(). */
+ .owner = THIS_MODULE,
+};
diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
--- /usr/share/empty/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/super.h 2010-08-21 21:00:02.982333916 +0200
-@@ -0,0 +1,465 @@
++++ linux/fs/aufs/super.h 2010-10-01 13:09:26.489878162 +0200
+@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+#endif
+
+ /* vdir parameters */
-+ unsigned long si_rdcache; /* max cache time in HZ */
++ unsigned long si_rdcache; /* max cache time in jiffies */
+ unsigned int si_rdblk; /* deblk size */
+ unsigned int si_rdhash; /* hash size */
+
+ struct au_splhead si_plink;
+ wait_queue_head_t si_plink_wq;
+ spinlock_t si_plink_maint_lock;
-+ struct file *si_plink_maint;
++ pid_t si_plink_maint_pid;
+
+ /*
+ * sysfs and lifetime management.
+#endif
+#endif
+
++#ifdef CONFIG_AUFS_SBILIST
++ struct list_head si_list;
++#endif
++
+ /* dirty, necessary for unmounting, sysfs and sysrq */
+ struct super_block *si_sb;
+};
+#define AuLock_IW (1 << 2) /* write-lock inode */
+#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */
+#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 au_ftest_lock(flags, name) ((flags) & AuLock_##name)
+#define au_fset_lock(flags, name) { (flags) |= AuLock_##name; }
+#define au_fclr_lock(flags, name) { (flags) &= ~AuLock_##name; }
+unsigned int au_sigen_inc(struct super_block *sb);
+aufs_bindex_t au_new_br_id(struct super_block *sb);
+
-+void aufs_read_lock(struct dentry *dentry, int flags);
++int si_read_lock(struct super_block *sb, int flags);
++int si_write_lock(struct super_block *sb, int flags);
++int aufs_read_lock(struct dentry *dentry, int flags);
+void aufs_read_unlock(struct dentry *dentry, int flags);
+void aufs_write_lock(struct dentry *dentry);
+void aufs_write_unlock(struct dentry *dentry);
-+void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir);
++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags);
+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
+
+int si_pid_test_slow(struct super_block *sb);
+
+/* ---------------------------------------------------------------------- */
+
++#ifdef CONFIG_AUFS_SBILIST
++/* module.c */
++extern struct au_splhead au_sbilist;
++
++static inline void au_sbilist_init(void)
++{
++ au_spl_init(&au_sbilist);
++}
++
++static inline void au_sbilist_add(struct super_block *sb)
++{
++ au_spl_add(&au_sbi(sb)->si_list, &au_sbilist);
++}
++
++static inline void au_sbilist_del(struct super_block *sb)
++{
++ au_spl_del(&au_sbi(sb)->si_list, &au_sbilist);
++}
++#else
++AuStubVoid(au_sbilist_init, void)
++AuStubVoid(au_sbilist_add, struct super_block*)
++AuStubVoid(au_sbilist_del, struct super_block*)
++#endif
++
++/* ---------------------------------------------------------------------- */
++
+static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
+{
+ /*
+ return locked;
+}
+
-+static inline void si_read_lock(struct super_block *sb, int flags)
-+{
-+ if (au_ftest_lock(flags, FLUSH))
-+ au_nwt_flush(&au_sbi(sb)->si_nowait);
-+ si_noflush_read_lock(sb);
-+}
-+
++#if 0 /* unused */
+static inline int si_read_trylock(struct super_block *sb, int flags)
+{
+ if (au_ftest_lock(flags, FLUSH))
+ au_nwt_flush(&au_sbi(sb)->si_nowait);
+ return si_noflush_read_trylock(sb);
+}
++#endif
+
+static inline void si_read_unlock(struct super_block *sb)
+{
+ __si_read_unlock(sb);
+}
+
-+static inline void si_write_lock(struct super_block *sb)
-+{
-+ au_nwt_flush(&au_sbi(sb)->si_nowait);
-+ si_noflush_write_lock(sb);
-+}
-+
+#if 0 /* unused */
+static inline int si_write_trylock(struct super_block *sb, int flags)
+{
+#endif /* __AUFS_SUPER_H__ */
diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c
--- /usr/share/empty/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sysaufs.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/sysaufs.c 2010-10-01 13:09:26.489878162 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#include "aufs.h"
+
+unsigned long sysaufs_si_mask;
-+struct kset *sysaufs_ket;
++struct kset *sysaufs_kset;
+
+#define AuSiAttr(_name) { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+{
+ int err;
+
-+ sbinfo->si_kobj.kset = sysaufs_ket;
++ sbinfo->si_kobj.kset = sysaufs_kset;
+ /* cf. sysaufs_name() */
+ err = kobject_init_and_add
-+ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_ket->kobj*/NULL,
++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL,
+ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo));
+
+ dbgaufs_si_null(sbinfo);
+void sysaufs_fin(void)
+{
+ dbgaufs_fin();
-+ sysfs_remove_group(&sysaufs_ket->kobj, sysaufs_attr_group);
-+ kset_unregister(sysaufs_ket);
++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group);
++ kset_unregister(sysaufs_kset);
+}
+
+int __init sysaufs_init(void)
+ } while (!sysaufs_si_mask);
+
+ err = -EINVAL;
-+ sysaufs_ket = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
-+ if (unlikely(!sysaufs_ket))
++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
++ if (unlikely(!sysaufs_kset))
+ goto out;
-+ err = PTR_ERR(sysaufs_ket);
-+ if (IS_ERR(sysaufs_ket))
++ err = PTR_ERR(sysaufs_kset);
++ if (IS_ERR(sysaufs_kset))
+ goto out;
-+ err = sysfs_create_group(&sysaufs_ket->kobj, sysaufs_attr_group);
++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group);
+ if (unlikely(err)) {
-+ kset_unregister(sysaufs_ket);
++ kset_unregister(sysaufs_kset);
+ goto out;
+ }
+
+ err = dbgaufs_init();
+ if (unlikely(err))
+ sysaufs_fin();
-+ out:
++out:
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h
--- /usr/share/empty/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sysaufs.h 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/sysaufs.h 2010-10-01 13:09:26.489878162 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+
+/* sysaufs.c */
+extern unsigned long sysaufs_si_mask;
-+extern struct kset *sysaufs_ket;
++extern struct kset *sysaufs_kset;
+extern struct attribute *sysaufs_si_attrs[];
+int sysaufs_si_init(struct au_sbinfo *sbinfo);
+int __init sysaufs_init(void);
+#endif /* __SYSAUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
--- /usr/share/empty/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sysfs.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/sysfs.c 2010-10-01 13:09:26.490878165 +0200
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ }
+ BUG();
+
-+ out_seq:
++out_seq:
+ if (!err) {
+ err = seq->count;
+ /* sysfs limit */
+ err = -EFBIG;
+ }
+ kfree(seq);
-+ out_unlock:
++out_unlock:
+ si_read_unlock(sb);
-+ out:
++out:
+ return err;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c
--- /usr/share/empty/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sysrq.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/sysrq.c 2010-10-01 13:09:26.490878165 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+
+ plevel = au_plevel;
+ au_plevel = KERN_WARNING;
-+ au_debug(1);
+
+ sbinfo = au_sbi(sb);
+ /* since we define pr_fmt, call printk directly */
+#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);
+#endif
+ printk(KERN_WARNING AUFS_NAME ": files\n");
++ file_list_lock();
+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
+ umode_t mode;
+ mode = file->f_dentry->d_inode->i_mode;
+ if (!special_file(mode) || au_special_file(mode))
+ au_dpri_file(file);
+ }
++ file_list_unlock();
++ printk(KERN_WARNING AUFS_NAME ": done\n");
+
+ au_plevel = plevel;
-+ au_debug(0);
+}
+
+/* ---------------------------------------------------------------------- */
+static void au_sysrq(int key __maybe_unused,
+ struct tty_struct *tty __maybe_unused)
+{
-+ struct kobject *kobj;
+ struct au_sbinfo *sbinfo;
+
-+ /* spin_lock(&sysaufs_ket->list_lock); */
-+ list_for_each_entry(kobj, &sysaufs_ket->list, entry) {
-+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ spin_lock(&au_sbilist.spin);
++ list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
+ sysrq_sb(sbinfo->si_sb);
-+ }
-+ /* spin_unlock(&sysaufs_ket->list_lock); */
++ spin_unlock(&au_sbilist.spin);
+}
+
+static struct sysrq_key_op au_sysrq_op = {
+}
diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
--- /usr/share/empty/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vdir.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/vdir.c 2010-10-01 13:09:26.490878165 +0200
@@ -0,0 +1,884 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
+ /* smp_mb(); */
+
-+ out:
++out:
+ return err;
+}
+
+ err = set_deblk_end(&p, &deblk_end);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ err = append_deblk(vdir);
+ /* smp_mb(); */
+
-+ out:
++out:
+ return err;
+}
+
+
+ kfree(vdir->vd_deblk);
+
-+ out_free:
++out_free:
+ au_cache_free_vdir(vdir);
-+ out:
++out:
+ vdir = ERR_PTR(err);
+ return vdir;
+}
+ }
+ }
+
-+ out:
++out:
+ if (!arg->err)
+ arg->vdir->vd_jiffy = jiffies;
+ /* smp_mb(); */
+
+ __putname(o);
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+#else
+
+ au_nhash_wh_free(&arg->whlist);
+
-+ out_delist:
++out_delist:
+ au_nhash_de_free(&arg->delist);
-+ out:
++out:
+ return err;
+}
+
+ } else if (allocated)
+ au_vdir_free(allocated);
+
-+ out:
++out:
+ return err;
+}
+
+ /* smp_mb(); */
+ return 0; /* success */
+
-+ out:
++out:
+ rerr = reinit_vdir(tgt);
+ BUG_ON(rerr);
+ return err;
+ } else if (allocated)
+ au_vdir_free(allocated);
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out:
++out:
+ /* smp_mb(); */
+ AuTraceErr(!valid);
+ return valid;
+}
diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
--- /usr/share/empty/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vfsub.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/vfsub.c 2010-10-01 13:09:26.490878165 +0200
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ goto out;
+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+
-+ out:
++out:
+ return file;
+}
+
+ if (path.dentry->d_inode)
+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
+
-+ out:
++out:
+ AuTraceErrPtr(path.dentry);
+ return path.dentry;
+}
+ if (path.dentry->d_inode)
+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
+
-+ out:
++out:
+ AuTraceErrPtr(path.dentry);
+ return path.dentry;
+}
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ if (!err)
+ err = do_truncate(h_path->dentry, length, attr, h_file);
+
-+ out_inode:
++out_inode:
+ if (!h_file)
+ put_write_access(h_inode);
-+ out_mnt:
++out_mnt:
+ if (!h_file)
+ mnt_drop_write(h_path->mnt);
-+ out:
++out:
+ return err;
+}
+
+}
diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
--- /usr/share/empty/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vfsub.h 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/vfsub.h 2010-10-01 13:09:26.490878165 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+#endif /* __AUFS_VFSUB_H__ */
diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
--- /usr/share/empty/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wbr_policy.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/wbr_policy.c 2010-10-01 13:09:26.491878167 +0200
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ dput(opq_dentry);
+ au_fset_cpdown(a->flags, DIROPQ);
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ dput(h_path.dentry);
+
-+ out:
++out:
+ return err;
+}
+
+ goto out; /* success */
+
+ /* revert */
-+ out_opq:
++out_opq:
+ if (au_ftest_cpdown(args->flags, DIROPQ)) {
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+ rerr = au_diropq_remove(dentry, bdst);
+ goto out;
+ }
+ }
-+ out_dir:
++out_dir:
+ if (au_ftest_cpdown(args->flags, MADE_DIR)) {
+ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
+ if (unlikely(rerr)) {
+ err = -EIO;
+ }
+ }
-+ out_put:
++out_put:
+ au_set_h_dptr(dentry, bdst, NULL);
+ if (au_dbend(dentry) == bdst)
+ au_update_dbend(dentry);
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+ err = au_wbr_nonopq(dentry, err);
+ }
+
-+ out:
++out:
+ AuDbg("b%d\n", err);
+ return err;
+}
+ if (err >= 0)
+ err = au_wbr_nonopq(dentry, err);
+
-+ out:
++out:
+ AuDbg("%d\n", err);
+ return err;
+}
+ if (err >= 0)
+ err = au_wbr_nonopq(dentry, err);
+
-+ out:
++out:
+ AuDbg("b%d\n", err);
+ return err;
+}
+ if (err >= 0)
+ err = au_wbr_nonopq(dentry, err);
+
-+ out_parent:
++out_parent:
+ dput(parent);
-+ out:
++out:
+ AuDbg("b%d\n", err);
+ return err;
+}
+};
diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
--- /usr/share/empty/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/whout.c 2010-08-21 21:00:02.986708041 +0200
-@@ -0,0 +1,1052 @@
++++ linux/fs/aufs/whout.c 2010-10-01 13:09:26.491878167 +0200
+@@ -0,0 +1,1059 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n",
+ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode);
+
-+ out_wh:
++out_wh:
+ dput(wh_dentry);
-+ out:
++out:
+ return err;
+}
+
+ AuDbg("%.*s\n", AuLNPair(&qs));
+ BUG();
+
-+ out_name:
++out_name:
+ if (name != defname)
+ kfree(name);
-+ out:
++out:
+ AuTraceErrPtr(dentry);
+ return dentry;
+}
+ AuTraceErr(err);
+ dput(h_path.dentry);
+
-+ out:
++out:
+ AuTraceErr(err);
+ return err;
+}
+ goto out;
+ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
+
-+ out:
++out:
+ return err;
+}
+
+ goto out;
+ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ goto out; /* success */
+
-+ out_err:
++out_err:
+ pr_err("an error(%d) on the writable branch %.*s(%s)\n",
+ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
-+ out:
++out:
+ for (i = 0; i < AuBrWh_Last; i++)
+ dput(base[i].dentry);
+ return err;
+ au_hn_imtx_unlock(hdir);
+ di_read_unlock(a->sb->s_root, AuLock_IR);
+
-+ out:
++out:
+ if (wbr)
+ atomic_dec(&wbr->wbr_wh_running);
+ atomic_dec(&a->br->br_count);
+ do_dec = 0;
+ }
+
-+ out:
++out:
+ if (do_dec)
+ atomic_dec(&br->br_wbr->wbr_wh_running);
+}
+ /* return this error in this context */
+ err = vfsub_create(h_dir, &h_path, WH_MASK);
+
-+ out:
++out:
+ wbr_wh_read_unlock(wbr);
+ return err;
+}
+ dput(opq_dentry);
+ opq_dentry = ERR_PTR(err);
+
-+ out:
++out:
+ return opq_dentry;
+}
+
+ }
+ __putname(wh_name.name);
+
-+ out:
++out:
+ return err;
+}
+
+ whtmp = ERR_PTR(err);
+ }
+
-+ out:
++out:
+ return whtmp;
+}
+
+static void call_rmdir_whtmp(void *args)
+{
+ int err;
++ aufs_bindex_t bindex;
+ struct au_whtmp_rmdir *a = args;
+ struct super_block *sb;
+ struct dentry *h_parent;
+ struct inode *h_dir;
-+ struct au_branch *br;
+ struct au_hinode *hdir;
+
+ /* rmdir by nfsd may cause deadlock with this i_mutex */
+ /* mutex_lock(&a->dir->i_mutex); */
++ err = -EROFS;
+ sb = a->dir->i_sb;
-+ si_noflush_read_lock(sb);
-+ err = au_test_ro(sb, a->bindex, NULL);
-+ if (unlikely(err))
++ si_read_lock(sb, !AuLock_FLUSH);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(sb, a->br->br_id);
++ if (unlikely(bindex < 0))
+ goto out;
+
+ err = -EIO;
-+ br = au_sbr(sb, a->bindex);
+ ii_write_lock_parent(a->dir);
+ h_parent = dget_parent(a->wh_dentry);
+ h_dir = h_parent->d_inode;
-+ hdir = au_hi(a->dir, a->bindex);
++ hdir = au_hi(a->dir, bindex);
+ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
-+ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, br);
++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent,
++ a->br);
+ if (!err) {
-+ err = mnt_want_write(br->br_mnt);
++ err = mnt_want_write(a->br->br_mnt);
+ if (!err) {
-+ err = au_whtmp_rmdir(a->dir, a->bindex, a->wh_dentry,
++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry,
+ &a->whlist);
-+ mnt_drop_write(br->br_mnt);
++ mnt_drop_write(a->br->br_mnt);
+ }
+ }
+ au_hn_imtx_unlock(hdir);
+ dput(h_parent);
+ ii_write_unlock(a->dir);
+
-+ out:
++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);
+ struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
+{
+ int wkq_err;
++ struct super_block *sb;
+
+ IMustLock(dir);
+
+ /* all post-process will be done in do_rmdir_whtmp(). */
++ sb = dir->i_sb;
+ args->dir = au_igrab(dir);
-+ args->bindex = bindex;
++ args->br = au_sbr(sb, bindex);
++ atomic_inc(&args->br->br_count);
+ args->wh_dentry = dget(wh_dentry);
-+ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb);
++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb);
+ if (unlikely(wkq_err)) {
+ pr_warning("rmdir error %.*s (%d), ignored\n",
+ AuDLNPair(wh_dentry), wkq_err);
+}
diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h
--- /usr/share/empty/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/whout.h 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/whout.h 2010-10-01 13:09:26.491878167 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+/* real rmdir for the whiteout-ed dir */
+struct au_whtmp_rmdir {
+ struct inode *dir;
-+ aufs_bindex_t bindex;
++ struct au_branch *br;
+ struct dentry *wh_dentry;
+ struct au_nhash whlist;
+};
+#endif /* __AUFS_WHOUT_H__ */
diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
--- /usr/share/empty/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wkq.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/wkq.c 2010-10-01 13:09:26.491878167 +0200
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ au_wkq_run(wkinfo, !AuWkq_WAIT);
+ } else {
+ err = -ENOMEM;
-+ atomic_dec(&au_sbi(sb)->si_nowait.nw_len);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
+ }
+
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
--- /usr/share/empty/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wkq.h 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/wkq.h 2010-10-01 13:09:26.491878167 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+
+static inline void au_nwt_done(struct au_nowait_tasks *nwt)
+{
-+ if (!atomic_dec_return(&nwt->nw_len))
++ if (atomic_dec_and_test(&nwt->nw_len))
+ wake_up_all(&nwt->nw_wq);
+}
+
+#endif /* __AUFS_WKQ_H__ */
diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
--- /usr/share/empty/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/xino.c 2010-08-21 21:00:02.986708041 +0200
++++ linux/fs/aufs/xino.c 2010-10-01 13:09:26.491878167 +0200
@@ -0,0 +1,1263 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ }
+ goto out_dput; /* success */
+
-+ out_fput:
++out_fput:
+ fput(file);
+ file = ERR_PTR(err);
-+ out_dput:
++out_dput:
+ dput(path.dentry);
-+ out:
++out:
+ return file;
+}
+
+ get_file(new_xino);
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ goto out_args;
+ }
+
-+ atomic_inc_return(&br->br_count);
++ atomic_inc(&br->br_count);
+ args->sb = sb;
+ args->br = br;
+ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb);
+ return; /* success */
+
+ pr_err("wkq %d\n", wkq_err);
-+ atomic_dec_return(&br->br_count);
++ atomic_dec(&br->br_count);
+
-+ out_args:
++out_args:
+ kfree(args);
-+ out:
-+ atomic_dec_return(&br->br_xino_running);
++out:
++ atomic_dec(&br->br_xino_running);
+}
+
+/* ---------------------------------------------------------------------- */
+ return 0; /* success */
+ }
+
-+ out:
++out:
+ AuIOErr1("write failed (%zd)\n", sz);
+ err = sz;
+ if (sz >= 0)
+ }
+ BUG();
+
-+ out:
++out:
+ set_bit(free_bit, p);
+ sbinfo->si_xib_next_bit++;
+ pindex = sbinfo->si_xib_last_pindex;
+ ino = xib_calc_ino(pindex, free_bit);
+ AuDbg("i%lu\n", (unsigned long)ino);
+ return ino;
-+ out_err:
++out_err:
+ mutex_unlock(&sbinfo->si_xib_mtx);
+ AuDbg("i0\n");
+ return 0;
+ }
+ return file; /* success */
+
-+ out:
++out:
+ fput(file);
+ file = ERR_PTR(err);
+ return file;
+ br->br_xino.xi_file = NULL;
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ }
+ }
+
-+ out:
++out:
+ return err;
+}
+
+ AuDbg("b%d\n", bindex);
+ free_page((unsigned long)page);
+
-+ out:
++out:
+ return err;
+}
+
+ err = 0;
+ goto out; /* success */
+
-+ out_free:
++out_free:
+ free_page((unsigned long)sbinfo->si_xib_buf);
+ sbinfo->si_xib_buf = NULL;
+ if (err >= 0)
+ err = -EIO;
-+ out_unset:
++out_unset:
+ fput(sbinfo->si_xib);
+ sbinfo->si_xib = NULL;
+ sbinfo->si_xread = NULL;
+ sbinfo->si_xwrite = NULL;
-+ out:
++out:
+ return err;
+}
+
+ br->br_xino.xi_file = p->new;
+ }
+
-+ out_pair:
++out_pair:
+ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++)
+ if (p->new)
+ fput(p->new);
+ else
+ break;
+ kfree(fpair);
-+ out:
++out:
+ return err;
+}
+
+ /* reset all */
+ AuIOErr("failed creating xino(%d).\n", err);
+
-+ out:
++out:
+ dput(parent);
+ return err;
+}
+ au_xino_brid_set(sb, -1);
+ }
+
-+ out:
++out:
+ return file;
+}
+
+ sizeof(Deleted) - 1));
+#undef Deleted
+
-+ out:
++out:
+ return err;
+}
diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_type.h
--- /usr/share/empty/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/aufs_type.h 2010-08-21 21:00:02.989917215 +0200
-@@ -0,0 +1,198 @@
++++ linux/include/linux/aufs_type.h 2010-10-01 13:09:26.492878168 +0200
+@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2005-2010 Junjiro R. Okajima
+ *
+#define __AUFS_TYPE_H__
+
+#include <linux/ioctl.h>
-+/* for those who didn't "make headers_install" */
-+#ifdef __KERNEL__
+#include <linux/kernel.h>
-+#endif
+#include <linux/limits.h>
+#include <linux/types.h>
+
-+#define AUFS_VERSION "2-standalone.tree-35-20100816"
++#define AUFS_VERSION "2.1-standalone.tree-35-20100920"
+
+/* todo? move this to linux-2.6.19/include/magic.h */
+#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
+#define AUFS_MFS_SECOND_DEF 30 /* seconds */
+#define AUFS_PLINK_WARN 100 /* number of plinks */
+
++/* pseudo-link maintenace under /proc */
++#define AUFS_PLINK_MAINT_NAME "plink_maint"
++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME
++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME
++
+#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */
+#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME
+
+
+/* ioctl */
+enum {
-+ AuCtl_PLINK_MAINT,
-+ AuCtl_PLINK_CLEAN,
-+
+ /* readdir in userspace */
+ AuCtl_RDU,
+ AuCtl_RDU_INO,
+} __aligned(8);
+
+#define AuCtlType 'A'
-+#define AUFS_CTL_PLINK_MAINT _IO(AuCtlType, AuCtl_PLINK_MAINT)
-+#define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN)
+#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
+#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
+#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD)