From e49829fec103eb45d764e96d02fe0b6579fe1088 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20R=C4=99korajski?= Date: Tue, 26 Oct 2010 11:02:43 +0000 Subject: [PATCH] - unofficial update, see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02921.html Changed files: kernel-aufs2.patch -> 1.11 --- kernel-aufs2.patch | 1835 +++++++++++++++++++++++++++++--------------- 1 file changed, 1234 insertions(+), 601 deletions(-) diff --git a/kernel-aufs2.patch b/kernel-aufs2.patch index 4d1fb18a..0755b37e 100644 --- a/kernel-aufs2.patch +++ b/kernel-aufs2.patch @@ -1,4 +1,4 @@ -aufs2 kbuild patch for linux-2.6. +aufs2.1 kbuild patch for linux-2.6.36 diff --git a/fs/Kconfig b/fs/Kconfig index 3d18530..8f582e1 100644 @@ -33,13 +33,13 @@ index 626b629..a841231 100644 header-y += auto_fs.h header-y += auto_fs4.h header-y += auxvec.h -aufs2 base patch for linux-2.6. +aufs2.1 base patch for linux-2.6.35 diff --git a/fs/namei.c b/fs/namei.c -index 17ea76b..56e8ece 100644 +index 868d0cb..6e92c81 100644 --- a/fs/namei.c +++ b/fs/namei.c -@@ -1168,7 +1168,7 @@ out: +@@ -1178,7 +1178,7 @@ out: * needs parent already locked. Doesn't follow mounts. * SMP-safe. */ @@ -48,7 +48,7 @@ index 17ea76b..56e8ece 100644 { int err; -@@ -1178,7 +1178,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) +@@ -1188,7 +1188,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) return __lookup_hash(&nd->last, nd->path.dentry, nd); } @@ -58,10 +58,10 @@ index 17ea76b..56e8ece 100644 { unsigned long hash; diff --git a/fs/splice.c b/fs/splice.c -index 8f1dfae..278c94f 100644 +index efdbfec..e01a51e 100644 --- a/fs/splice.c +++ b/fs/splice.c -@@ -1092,8 +1092,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); +@@ -1104,8 +1104,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); /* * Attempt to initiate a splice from pipe to file. */ @@ -72,7 +72,7 @@ index 8f1dfae..278c94f 100644 { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); -@@ -1120,9 +1120,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +@@ -1132,9 +1132,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, /* * Attempt to initiate a splice from a file to a pipe. */ @@ -114,8 +114,20 @@ index 997c3b4..be9a153 100644 + unsigned int flags); + #endif -aufs2 standalone patch for linux-2.6. +aufs2.1 standalone patch for linux-2.6.36 +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 56e8ece..ba75f28 100644 --- a/fs/namei.c @@ -378,9 +390,8 @@ index c53949f..0ae5b91 100644 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, 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-10-21 09:52:43.080290296 +0200 +--- /dev/null ++++ linux-2.6/Documentation/ABI/testing/debugfs-aufs 2010-10-24 11:11:14.000000000 +0200 @@ -0,0 +1,37 @@ +What: /debug/aufs/si_/ +Date: March 2009 @@ -419,9 +430,8 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Document + be created. + When the aufs mount option 'noxino' is specified, it + 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-10-21 09:52:43.080290296 +0200 +--- /dev/null ++++ linux-2.6/Documentation/ABI/testing/sysfs-aufs 2010-10-24 11:11:14.000000000 +0200 @@ -0,0 +1,24 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 @@ -447,9 +457,8 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentat + even if it is the default path. + When the aufs mount option 'noxino' is specified, it + 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-10-21 09:52:43.083624114 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/aufs.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -512,10 +521,9 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,1005 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/branch.c 2010-10-24 16:28:53.000000000 +0200 +@@ -0,0 +1,1020 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -839,11 +847,11 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + * a limit for rmdir/rename a dir + * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h + */ ++ h_dentry = path->dentry; + err = vfs_statfs(path, &kst); + if (unlikely(err)) + goto out; + err = -EINVAL; -+ h_dentry = path->dentry; + if (kst.f_namelen >= NAME_MAX) + err = au_br_init_wh(sb, br, perm, h_dentry); + else @@ -954,7 +962,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + + 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); @@ -1232,7 +1239,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + + root = sb->s_root; + inode = root->d_inode; -+ au_plink_maint_block(sb); + sbinfo = au_sbi(sb); + bend = sbinfo->si_bend; + @@ -1277,8 +1283,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + 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; @@ -1341,7 +1346,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c +{ +#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 +} + @@ -1360,8 +1365,15 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c +{ + 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; ++ struct list_head *list; ++#ifdef CONFIG_SMP ++ int cpu; ++#endif + const int step_bytes = 1024, /* memory allocation unit */ + step_files = step_bytes / sizeof(*a); + @@ -1373,10 +1385,21 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (unlikely(!a)) + goto out; + ++#ifdef CONFIG_SMP ++ cpu = smp_processor_id(); ++ file->f_sb_list_cpu = cpu; ++ list = per_cpu_ptr(sb->s_files, cpu); ++#else ++ list = &sb->s_files; ++#endif ++ + /* no need file_list_lock() since sbinfo is locked? defered? */ -+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ br_id = au_sbr_id(sb, bindex); ++ list_for_each_entry(file, list, 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); @@ -1387,16 +1410,17 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + 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); + @@ -1447,7 +1471,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + 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) @@ -1521,9 +1544,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c +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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/branch.h 2010-10-24 11:30:39.000000000 +0200 @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -1722,7 +1744,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + +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) @@ -1749,10 +1771,9 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,36 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/conf.mk 2010-10-24 11:31:04.000000000 +0200 +@@ -0,0 +1,37 @@ + +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} + @@ -1763,7 +1784,8 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk +endef + +AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ -+ HNOTIFY HFSNOTIFY \ ++ SBILIST \ ++ HNOTIFY HFSNOTIFY HINOTIFY \ + EXPORT INO_T_64 \ + RDU \ + SP_IATTR \ @@ -1789,9 +1811,8 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk +${obj}/sysfs.o: ${AuConfName} + +-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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/cpup.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,1059 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -2852,9 +2873,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + 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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/cpup.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -2937,9 +2957,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dbgaufs.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -3275,9 +3294,8 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + err = 0; + 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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dbgaufs.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -3331,9 +3349,8 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dcsub.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -3535,9 +3552,8 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c + + return path_is_under(path + 0, path + 1); +} -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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dcsub.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -3593,10 +3609,9 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,426 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/debug.c 2010-10-24 11:31:58.000000000 +0200 +@@ -0,0 +1,443 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -3628,9 +3643,11 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c +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) + +/* ---------------------------------------------------------------------- */ @@ -3790,8 +3807,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + && 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); @@ -3821,7 +3838,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + 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); @@ -3974,12 +3992,26 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + +void au_dbg_verify_kthread(void) +{ -+ if (current->flags & PF_WQ_WORKER) { ++ struct task_struct *tsk = current; ++ ++ if ((tsk->flags & PF_KTHREAD) ++ && !strncmp(tsk->comm, AUFS_WKQ_NAME "/", sizeof(AUFS_WKQ_NAME))) { + au_dbg_blocked(); -+ WARN_ON(1); ++ BUG(); + } +} + ++static void au_dbg_do_verify_wkq(void *args) ++{ ++ BUG_ON(current_fsuid()); ++ BUG_ON(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++} ++ ++void au_dbg_verify_wkq(void) ++{ ++ au_wkq_wait(au_dbg_do_verify_wkq, NULL); ++} ++ +/* ---------------------------------------------------------------------- */ + +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused) @@ -4023,10 +4055,9 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + + return 0; +} -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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,243 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/debug.h 2010-10-24 11:32:22.000000000 +0200 +@@ -0,0 +1,245 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -4166,6 +4197,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h +void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen); +void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); +void au_dbg_verify_kthread(void); ++void au_dbg_verify_wkq(void); + +int __init au_debug_init(void); +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); @@ -4231,6 +4263,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h + unsigned int sigen) +AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) +AuStubVoid(au_dbg_verify_kthread, void) ++AuStubVoid(au_dbg_verify_wkq, void) +AuStubInt0(__init au_debug_init, void) +AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo) + @@ -4256,7 +4289,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h +#ifdef CONFIG_HW_CONSOLE +#define au_dbg_blocked() do { \ + WARN_ON(1); \ -+ handle_sysrq('w', vc_cons[fg_console].d->port.tty); \ ++ handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \ +} while (0) +#else +AuStubVoid(au_dbg_blocked, void) @@ -4270,10 +4303,9 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,851 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/dentry.c 2010-10-24 11:32:50.000000000 +0200 +@@ -0,0 +1,860 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -4905,9 +4937,8 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + name = &dentry->d_name; + + /* -+ * Theoretically, REVAL test should be unnecessary in case of -+ * {FS,I}NOTIFY. -+ * But {fs,i}notify doesn't fire some necessary events, ++ * Theoretically, REVAL test should be unnecessary in case of INOTIFY. ++ * But inotify doesn't fire some necessary events, + * IN_ATTRIB for atime/nlink/pageio + * IN_DELETE for NFS dentry + * Let's do REVAL test too. @@ -5066,10 +5097,19 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + 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)); @@ -5093,23 +5133,24 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + + 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: + 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; +} + @@ -5125,9 +5166,8 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + .d_revalidate = aufs_d_revalidate, + .d_release = aufs_d_release +}; -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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dentry.h 2010-10-24 11:33:02.000000000 +0200 @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -5347,7 +5387,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h +#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) @@ -5360,10 +5400,9 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 -@@ -0,0 +1,395 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/dinfo.c 2010-10-24 11:33:24.000000000 +0200 +@@ -0,0 +1,397 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -5388,11 +5427,13 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c + +#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) @@ -5759,9 +5800,8 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c + return bindex; + return -1; +} -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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dir.c 2010-10-24 15:03:11.000000000 +0200 @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -5954,7 +5994,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + 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)) @@ -5973,8 +6013,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + struct au_fidir *fidir; + aufs_bindex_t bindex, bend; + -+ au_plink_maint_leave(file); + sb = file->f_dentry->d_sb; ++ au_plink_maint_leave(au_sbi(sb)); + finfo = au_fi(file); + fidir = finfo->fi_hdir; + if (fidir) { @@ -6401,9 +6441,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + .flush = aufs_flush_dir, + .fsync = aufs_fsync_dir +}; -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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dir.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -6543,9 +6582,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dynop.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2010 Junjiro R. Okajima @@ -6972,9 +7010,8 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c + for (i = 0; i < AuDyLast; i++) + WARN_ON(!list_empty(&dynop[i].head)); +} -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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/dynop.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 Junjiro R. Okajima @@ -7065,9 +7102,8 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.086957936 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/export.c 2010-10-24 11:34:10.000000000 +0200 @@ -0,0 +1,788 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -7812,7 +7848,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + 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); @@ -7857,9 +7893,8 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/file.c 2010-10-24 14:50:09.000000000 +0200 @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -8513,9 +8548,8 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + .error_remove_page = aufs_error_remove_page +#endif /* CONFIG_AUFS_DEBUG */ +}; -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/file.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -8755,10 +8789,9 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,167 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/finfo.c 2010-10-24 11:36:29.000000000 +0200 +@@ -0,0 +1,171 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -8791,7 +8824,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c + 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; +} + @@ -8893,13 +8926,17 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c + 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) @@ -8926,10 +8963,9 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c +out: + return err; +} -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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,886 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/f_op.c 2010-10-24 15:02:31.000000000 +0200 +@@ -0,0 +1,899 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -9010,6 +9046,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + struct au_finfo *finfo; + aufs_bindex_t bindex; + ++ au_plink_maint_leave(au_sbi(file->f_dentry->d_sb)); + finfo = au_fi(file); + bindex = finfo->fi_btop; + if (bindex >= 0) @@ -9050,7 +9087,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + + 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; @@ -9068,6 +9105,28 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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) +{ @@ -9075,15 +9134,12 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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)) @@ -9104,7 +9160,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: -+ si_read_unlock(sb); ++ si_read_unlock(inode->i_sb); + mutex_unlock(&inode->i_mutex); + return err; +} @@ -9151,7 +9207,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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; @@ -9176,15 +9232,13 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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; @@ -9204,7 +9258,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: -+ si_read_unlock(sb); ++ si_read_unlock(inode->i_sb); + mutex_unlock(&inode->i_mutex); + return err; +} @@ -9220,7 +9274,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + + 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; @@ -9252,15 +9306,11 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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; @@ -9280,7 +9330,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: -+ si_read_unlock(sb); ++ si_read_unlock(inode->i_sb); + mutex_unlock(&inode->i_mutex); + return err; +} @@ -9504,7 +9554,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + + 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; @@ -9633,14 +9683,16 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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); @@ -9670,8 +9722,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c +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); @@ -9688,15 +9741,11 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + 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))) @@ -9737,7 +9786,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); +out: -+ si_read_unlock(sb); ++ si_read_unlock(inode->sb); + mutex_unlock(&inode->i_mutex); + return err; +} @@ -9752,7 +9801,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + + 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; @@ -9816,10 +9865,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + .aio_splice_read = aufs_aio_splice_read +#endif +}; -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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,301 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/f_op_sp.c 2010-10-24 11:35:52.000000000 +0200 +@@ -0,0 +1,299 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -10066,8 +10114,6 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c + di_read_lock_child(dentry, AuLock_IR); + if (!err) + au_init_fop_sp(file); -+ else -+ au_finfo_fin(file); + +out: + return err; @@ -10121,9 +10167,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c + + return ret; +} -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/fstype.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -10622,10 +10667,9 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,216 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/hfsnotify.c 2010-10-24 11:37:18.000000000 +0200 +@@ -0,0 +1,230 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -10654,62 +10698,52 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE + | FS_CREATE | FS_EVENT_ON_CHILD); +static struct fsnotify_group *au_hfsn_group; -+static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); + -+static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++static void au_hfsn_free_mark(struct fsnotify_mark_entry *entry) +{ -+ struct au_hnotify *hn = container_of(mark, struct au_hnotify, -+ hn_mark); ++#if 0 ++ struct au_hnotify *hn = container_of(entry, struct au_hnotify, ++ hn_entry); ++ au_cache_free_hnotify(hn); ++#endif + AuDbg("here\n"); -+ hn->hn_mark_dead = 1; -+ smp_mb(); -+ wake_up_all(&au_hfsn_wq); +} + +static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode) +{ -+ struct fsnotify_mark *mark; ++ struct fsnotify_mark_entry *entry; + -+ hn->hn_mark_dead = 0; -+ mark = &hn->hn_mark; -+ fsnotify_init_mark(mark, au_hfsn_free_mark); -+ mark->mask = AuHfsnMask; -+ /* -+ * by udba rename or rmdir, aufs assign a new inode to the known -+ * h_inode, so specify 1 to allow dups. -+ */ -+ return fsnotify_add_mark(mark, au_hfsn_group, h_inode, /*mnt*/NULL, -+ /*allow_dups*/1); ++ entry = &hn->hn_entry; ++ fsnotify_init_mark(entry, au_hfsn_free_mark); ++ entry->mask = AuHfsnMask; ++ return fsnotify_add_mark(entry, au_hfsn_group, h_inode); +} + +static void au_hfsn_free(struct au_hnotify *hn) +{ -+ struct fsnotify_mark *mark; -+ -+ mark = &hn->hn_mark; -+ fsnotify_destroy_mark(mark); -+ fsnotify_put_mark(mark); ++ struct fsnotify_mark_entry *entry; + -+ /* TODO: bad approach */ -+ wait_event(au_hfsn_wq, hn->hn_mark_dead); ++ entry = &hn->hn_entry; ++ fsnotify_destroy_mark_by_entry(entry); ++ fsnotify_put_mark(entry); +} + +/* ---------------------------------------------------------------------- */ + +static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) +{ -+ struct fsnotify_mark *mark; ++ struct fsnotify_mark_entry *entry; + -+ mark = &hinode->hi_notify->hn_mark; -+ spin_lock(&mark->lock); ++ entry = &hinode->hi_notify->hn_entry; ++ spin_lock(&entry->lock); + if (do_set) { -+ AuDebugOn(mark->mask & AuHfsnMask); -+ mark->mask |= AuHfsnMask; ++ AuDebugOn(entry->mask & AuHfsnMask); ++ entry->mask |= AuHfsnMask; + } else { -+ AuDebugOn(!(mark->mask & AuHfsnMask)); -+ mark->mask &= ~AuHfsnMask; ++ AuDebugOn(!(entry->mask & AuHfsnMask)); ++ entry->mask &= ~AuHfsnMask; + } -+ spin_unlock(&mark->lock); ++ spin_unlock(&entry->lock); + /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ +} + @@ -10751,14 +10785,13 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +/* ---------------------------------------------------------------------- */ + +static int au_hfsn_handle_event(struct fsnotify_group *group, -+ struct fsnotify_mark *inode_mark, -+ struct fsnotify_mark *vfsmount_mark, + struct fsnotify_event *event) +{ + int err; + struct au_hnotify *hnotify; + struct inode *h_dir, *h_inode; + __u32 mask; ++ struct fsnotify_mark_entry *entry; + struct qstr h_child_qstr = { + .name = event->file_name, + .len = event->name_len @@ -10767,10 +10800,10 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE); + + err = 0; -+ /* if FS_UNMOUNT happens, there must be another bug */ ++ /* if IN_UNMOUNT happens, there must be another bug */ + mask = event->mask; + AuDebugOn(mask & FS_UNMOUNT); -+ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ if (mask & (IN_IGNORED | IN_UNMOUNT)) + goto out; + + h_dir = event->to_tell; @@ -10787,9 +10820,14 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + au_debug(0); +#endif + -+ AuDebugOn(!inode_mark); -+ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); -+ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); ++ spin_lock(&h_dir->i_lock); ++ entry = fsnotify_find_mark_entry(group, h_dir); ++ spin_unlock(&h_dir->i_lock); ++ if (entry) { ++ hnotify = container_of(entry, struct au_hnotify, hn_entry); ++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); ++ fsnotify_put_mark(entry); ++ } + +out: + return err; @@ -10798,13 +10836,24 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */ +/* it should be exported to modules */ +static bool au_hfsn_should_send_event(struct fsnotify_group *group, -+ struct inode *h_inode, -+ struct fsnotify_mark *inode_mark, -+ struct fsnotify_mark *vfsmount_mark, -+ __u32 mask, void *data, int data_type) ++ struct inode *h_inode, __u32 mask) +{ ++ struct fsnotify_mark_entry *entry; ++ bool send; ++ ++ spin_lock(&h_inode->i_lock); ++ entry = fsnotify_find_mark_entry(group, h_inode); ++ spin_unlock(&h_inode->i_lock); ++ if (!entry) ++ return false; ++ + mask = (mask & ~FS_EVENT_ON_CHILD); -+ return inode_mark->mask & mask; ++ send = (entry->mask & mask); ++ ++ /* find took a reference */ ++ fsnotify_put_mark(entry); ++ ++ return send; +} + +static struct fsnotify_ops au_hfsn_ops = { @@ -10817,12 +10866,21 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +static int __init au_hfsn_init(void) +{ + int err; ++ unsigned int gn; ++ const unsigned int gn_max = 10; ++ ++ gn = 0; ++ for (gn = 0; gn < gn_max; gn++) { ++ au_hfsn_group = fsnotify_obtain_group(gn, AuHfsnMask, ++ &au_hfsn_ops); ++ if (au_hfsn_group != ERR_PTR(-EEXIST)) ++ break; ++ } + + err = 0; -+ au_hfsn_group = fsnotify_alloc_group(&au_hfsn_ops); + if (IS_ERR(au_hfsn_group)) { ++ pr_err("fsnotify_obtain_group() failed %u times\n", gn_max); + err = PTR_ERR(au_hfsn_group); -+ pr_err("fsnotify_alloc_group() failed, %d\n", err); + } + + AuTraceErr(err); @@ -10842,9 +10900,8 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + .fin = au_hfsn_fin, + .init = au_hfsn_init +}; -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/hfsplus.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Junjiro R. Okajima @@ -10904,10 +10961,243 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c + au_sbr_put(dentry->d_sb, bindex); + } +} -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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,663 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/hinotify.c 2010-10-24 11:11:14.000000000 +0200 +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (C) 2005-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 ++ */ ++ ++/* ++ * inotify for the lower directories (deprecated) ++ */ ++ ++#include "aufs.h" ++ ++static const __u32 AuHinMask = (IN_MOVE | IN_DELETE | IN_CREATE); ++static struct inotify_handle *au_hin_handle; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_hin_alloc(struct au_hnotify *hn, struct inode *h_inode) ++{ ++ int err; ++ s32 wd; ++ struct inotify_watch *watch; ++ ++ err = -EEXIST; ++ wd = inotify_find_watch(au_hin_handle, h_inode, &watch); ++ if (wd >= 0) { ++ put_inotify_watch(watch); ++ goto out; ++ } ++ ++ err = 0; ++ inotify_init_watch(&hn->hn_watch); ++ wd = inotify_add_watch(au_hin_handle, &hn->hn_watch, h_inode, ++ AuHinMask); ++ if (unlikely(wd < 0)) { ++ err = wd; ++ put_inotify_watch(&hn->hn_watch); ++ } ++ ++out: ++ return err; ++} ++ ++static void au_hin_free(struct au_hnotify *hn) ++{ ++ int err; ++ ++ err = 0; ++ if (atomic_read(&hn->hn_watch.count)) ++ err = inotify_rm_watch(au_hin_handle, &hn->hn_watch); ++ if (unlikely(err)) ++ /* it means the watch is already removed */ ++ pr_warning("failed inotify_rm_watch() %d\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hin_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct inode *h_inode; ++ struct inotify_watch *watch; ++ ++ h_inode = hinode->hi_inode; ++ IMustLock(h_inode); ++ ++ /* todo: try inotify_find_update_watch()? */ ++ watch = &hinode->hi_notify->hn_watch; ++ mutex_lock(&h_inode->inotify_mutex); ++ /* mutex_lock(&watch->ih->mutex); */ ++ if (do_set) { ++ AuDebugOn(watch->mask & AuHinMask); ++ watch->mask |= AuHinMask; ++ } else { ++ AuDebugOn(!(watch->mask & AuHinMask)); ++ watch->mask &= ~AuHinMask; ++ } ++ /* mutex_unlock(&watch->ih->mutex); */ ++ mutex_unlock(&h_inode->inotify_mutex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef AuDbgHnotify ++static char *in_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) if (mask & flag) \ ++ return #flag; ++ test_ret(IN_ACCESS); ++ test_ret(IN_MODIFY); ++ test_ret(IN_ATTRIB); ++ test_ret(IN_CLOSE_WRITE); ++ test_ret(IN_CLOSE_NOWRITE); ++ test_ret(IN_OPEN); ++ test_ret(IN_MOVED_FROM); ++ test_ret(IN_MOVED_TO); ++ test_ret(IN_CREATE); ++ test_ret(IN_DELETE); ++ test_ret(IN_DELETE_SELF); ++ test_ret(IN_MOVE_SELF); ++ test_ret(IN_UNMOUNT); ++ test_ret(IN_Q_OVERFLOW); ++ test_ret(IN_IGNORED); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++static u32 au_hin_conv_mask(u32 mask) ++{ ++ u32 conv; ++ ++ conv = 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(CLOSE_WRITE); ++ do_conv(CLOSE_NOWRITE); ++ do_conv(OPEN); ++ do_conv(MOVED_FROM); ++ do_conv(MOVED_TO); ++ do_conv(CREATE); ++ do_conv(DELETE); ++ do_conv(DELETE_SELF); ++ do_conv(MOVE_SELF); ++ do_conv(UNMOUNT); ++ do_conv(Q_OVERFLOW); ++#undef do_conv ++#define do_conv(flag) do { \ ++ conv |= (mask & IN_ ## flag) ? FS_IN_ ## flag : 0; \ ++ } while (0) ++ do_conv(IGNORED); ++ /* do_conv(ISDIR); */ ++ /* do_conv(ONESHOT); */ ++#undef do_conv ++ ++ return conv; ++} ++ ++static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused, ++ u32 mask, u32 cookie __maybe_unused, ++ const char *h_child_name, struct inode *h_child_inode) ++{ ++ struct au_hnotify *hnotify; ++ struct qstr h_child_qstr = { ++ .name = h_child_name ++ }; ++ ++ /* if IN_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & IN_UNMOUNT); ++ if (mask & (IN_IGNORED | IN_UNMOUNT)) { ++ put_inotify_watch(watch); ++ return; ++ } ++ ++#ifdef AuDbgHnotify ++ au_debug(1); ++ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) { ++ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s," ++ " hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++ WARN_ON(1); ++ } ++ au_debug(0); ++#endif ++ ++ if (h_child_name) ++ h_child_qstr.len = strlen(h_child_name); ++ hnotify = container_of(watch, struct au_hnotify, hn_watch); ++ mask = au_hin_conv_mask(mask); ++ au_hnotify(watch->inode, hnotify, mask, &h_child_qstr, h_child_inode); ++} ++ ++static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused) ++{ ++ return; ++} ++ ++static struct inotify_operations aufs_inotify_ops = { ++ .handle_event = aufs_inotify, ++ .destroy_watch = aufs_inotify_destroy ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init au_hin_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_hin_handle = inotify_init(&aufs_inotify_ops); ++ if (IS_ERR(au_hin_handle)) ++ err = PTR_ERR(au_hin_handle); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_hin_fin(void) ++{ ++ inotify_destroy(au_hin_handle); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hin_ctl, ++ .alloc = au_hin_alloc, ++ .free = au_hin_free, ++ ++ .fin = au_hin_fin, ++ .init = au_hin_init ++}; +--- /dev/null ++++ linux-2.6/fs/aufs/hnotify.c 2010-10-24 11:37:32.000000000 +0200 +@@ -0,0 +1,662 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -11361,8 +11651,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + 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; @@ -11571,10 +11860,9 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + if (au_cachep[AuCache_HNOTIFY]) + au_hn_destroy_cache(); +} -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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,257 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/iinfo.c 2010-10-24 11:38:41.000000000 +0200 +@@ -0,0 +1,259 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -11737,8 +12025,10 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c +{ + 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); +} + @@ -11832,9 +12122,8 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c + kfree(iinfo->ii_hinode); + AuRwDestroy(&iinfo->ii_rwsem); +} -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/inode.c 2010-10-24 11:38:51.000000000 +0200 @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -11864,7 +12153,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c +{ + if (inode) { + AuDebugOn(!atomic_read(&inode->i_count)); -+ atomic_inc_return(&inode->i_count); ++ atomic_inc(&inode->i_count); + } + return inode; +} @@ -12279,10 +12568,9 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c + mask |= MAY_READ; /* force permission check */ + return au_test_h_perm(h_inode, mask); +} -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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,498 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/inode.h 2010-10-24 15:01:53.000000000 +0200 +@@ -0,0 +1,514 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -12320,9 +12608,9 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +struct au_hnotify { +#ifdef CONFIG_AUFS_HNOTIFY +#ifdef CONFIG_AUFS_HFSNOTIFY -+ /* never use fsnotify_add_vfsmount_mark() */ -+ struct fsnotify_mark hn_mark; -+ int hn_mark_dead; ++ struct fsnotify_mark_entry hn_entry; ++#else ++ struct inotify_watch hn_watch; +#endif + struct inode *hn_aufs_inode; /* no get/put */ +#endif @@ -12491,9 +12779,11 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +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 @@ -12503,9 +12793,23 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +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 */ + +/* ---------------------------------------------------------------------- */ + @@ -12588,7 +12892,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +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 +} + @@ -12722,7 +13026,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +int __init au_hnotify_init(void); +void au_hnotify_fin(void); + -+/* hfsnotify.c */ ++/* hinotify.c */ +extern const struct au_hnotify_op au_hnotify_op; + +static inline @@ -12781,10 +13085,9 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,155 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/ioctl.c 2010-10-24 11:39:20.000000000 +0200 +@@ -0,0 +1,150 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -12869,11 +13172,6 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c + 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); @@ -12940,10 +13238,9 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c +} +#endif +#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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,672 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/i_op_add.c 2010-10-24 11:38:14.000000000 +0200 +@@ -0,0 +1,676 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -13412,7 +13709,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + 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); + @@ -13511,6 +13811,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + di_write_unlock(a->parent); + dput(a->src_parent); + aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: + kfree(a); +out: + return err; @@ -13616,10 +13917,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c +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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,911 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/i_op.c 2010-10-24 13:50:56.000000000 +0200 +@@ -0,0 +1,919 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -13684,8 +13984,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + + if (!err) + err = devcgroup_inode_permission(h_inode, mask); -+ if (!err) ++ if (!err) { ++ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND); + err = security_inode_permission(h_inode, mask); ++ } + +#if 0 + if (!err) { @@ -13937,7 +14239,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + +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; @@ -13995,6 +14297,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + * 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); @@ -14112,7 +14415,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c +{ + 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; @@ -14126,8 +14429,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + 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; @@ -14232,7 +14536,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + + 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)); @@ -14308,6 +14615,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + } +out_si: + si_read_unlock(sb); ++out_kfree: + kfree(a); +out: + AuTraceErr(err); @@ -14351,7 +14659,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + 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); + @@ -14531,9 +14839,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + .getattr = aufs_getattr, + .truncate_range = aufs_truncate_range +}; -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-10-21 09:52:43.090291764 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/i_op_del.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -15007,10 +15314,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c + 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-10-21 09:52:43.090291764 +0200 -@@ -0,0 +1,977 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/i_op_ren.c 2010-10-24 11:38:32.000000000 +0200 +@@ -0,0 +1,980 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -15849,7 +16155,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c +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; + @@ -15877,15 +16183,18 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + } + + 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); @@ -15988,10 +16297,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + 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-10-21 09:52:43.083624114 +0200 -@@ -0,0 +1,173 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/Kconfig 2010-10-24 11:39:57.000000000 +0200 +@@ -0,0 +1,182 @@ +config AUFS_FS + tristate "Aufs (Advanced multi layered unification filesystem) support" + depends on EXPERIMENTAL @@ -16038,23 +16346,32 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig + 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 + If you want to modify files on branches directly, eg. bypassing aufs, + and want aufs to detect the changes of them fully, then enable this + option and use 'udba=notify' mount option. -+ Currently there is only one available configuration, "fsnotify". + It will have a negative impact to the performance. + See detail in aufs.5. + -+ +choice + prompt "method" if AUFS_HNOTIFY + default AUFS_HFSNOTIFY +config AUFS_HFSNOTIFY + bool "fsnotify" + select FSNOTIFY ++config AUFS_HINOTIFY ++ bool "inotify (DEPRECATED)" ++ depends on INOTIFY +endchoice + +config AUFS_EXPORT @@ -16165,9 +16482,8 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/loop.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -16232,9 +16548,8 @@ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c + + return ret; +} -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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/loop.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -16278,9 +16593,8 @@ diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/magic.mk 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,54 @@ + +# defined in ${srctree}/fs/fuse/inode.c @@ -16336,10 +16650,9 @@ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk +ifdef CONFIG_HFSPLUS_FS +ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +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-10-21 09:52:43.083624114 +0200 -@@ -0,0 +1,37 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/Makefile 2010-10-24 11:40:16.000000000 +0200 +@@ -0,0 +1,39 @@ + +include ${src}/magic.mk +ifeq (${CONFIG_AUFS_FS},m) @@ -16356,7 +16669,7 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile +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 \ @@ -16365,11 +16678,13 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile + 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_HNOTIFY) += hnotify.o +aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o +aufs-$(CONFIG_AUFS_EXPORT) += export.o +aufs-$(CONFIG_AUFS_POLL) += poll.o +aufs-$(CONFIG_AUFS_RDU) += rdu.o @@ -16377,10 +16692,9 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile +aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o +aufs-$(CONFIG_AUFS_DEBUG) += debug.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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,171 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/module.c 2010-10-24 11:40:26.000000000 +0200 +@@ -0,0 +1,182 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -16459,6 +16773,10 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + +int au_dir_roflags; + ++#ifdef CONFIG_AUFS_SBILIST ++struct au_splhead au_sbilist; ++#endif ++ +/* + * functions for module interface. + */ @@ -16499,15 +16817,19 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + + 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; @@ -16532,6 +16854,8 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + au_hnotify_fin(); +out_wkq: + au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); +out_sysaufs: + sysaufs_fin(); + au_dy_fin(); @@ -16546,16 +16870,16 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + au_sysrq_fin(); + au_hnotify_fin(); + au_wkq_fin(); ++ au_procfs_fin(); + sysaufs_fin(); + au_dy_fin(); +} + +module_init(aufs_init); +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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,82 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/module.h 2010-10-24 11:40:35.000000000 +0200 +@@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -16598,6 +16922,15 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h +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); + ++#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 */ @@ -16638,9 +16971,8 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/mtx.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Junjiro R. Okajima @@ -16690,10 +17022,9 @@ diff -urN /usr/share/empty/fs/aufs/mtx.h linux/fs/aufs/mtx.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,1571 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/opts.c 2010-10-24 11:40:51.000000000 +0200 +@@ -0,0 +1,1595 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -16717,6 +17048,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + */ + +#include ++#include +#include +#include /* a distribution requires */ +#include @@ -16782,8 +17114,14 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + {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 @@ -16906,16 +17244,30 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ +#ifdef CONFIG_AUFS_HFSNOTIFY + {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#else ++ {AuOpt_UDBA_HNOTIFY, "inotify"}, +#endif +#endif + {-1, NULL} +}; + ++static void au_warn_inotify(int val, char *str) ++{ ++#ifdef CONFIG_AUFS_HINOTIFY ++ if (val == AuOpt_UDBA_HNOTIFY ++ && !strcmp(str, "inotify")) ++ AuWarn1("udba=inotify is deprecated, use udba=notify\n"); ++#endif ++} ++ +static int noinline_for_stack udba_val(char *str) +{ ++ int val; + substring_t args[MAX_OPT_ARGS]; + -+ return match_token(str, udbalevel, args); ++ val = match_token(str, udbalevel, args); ++ au_warn_inotify(val, str); ++ return val; +} + +const char *au_optstr_udba(int udba) @@ -16988,7 +17340,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + 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); @@ -17618,7 +17970,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + 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; @@ -17768,7 +18121,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + 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; + } + @@ -17805,7 +18159,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + 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: @@ -17874,7 +18228,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + 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; @@ -18265,10 +18620,9 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +{ + return au_mntflags(sb) & AuOptMask_UDBA; +} -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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,198 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/opts.h 2010-10-24 11:41:02.000000000 +0200 +@@ -0,0 +1,207 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -18351,6 +18705,15 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h +} 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 */ @@ -18467,10 +18830,9 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,451 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/plink.c 2010-10-24 15:01:46.000000000 +0200 +@@ -0,0 +1,483 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -18496,53 +18858,102 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c +#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; @@ -18569,6 +18980,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + + 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(); @@ -18589,6 +19001,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + 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; @@ -18633,6 +19046,8 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + .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; @@ -18765,6 +19180,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + 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; @@ -18803,7 +19219,6 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + 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); @@ -18821,7 +19236,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c +} + +/* 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; @@ -18831,14 +19246,27 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + + 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) +{ @@ -18853,6 +19281,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + + 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 */ @@ -18887,44 +19316,8 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + 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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/poll.c 2010-10-24 11:41:22.000000000 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -18963,7 +19356,7 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c + 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; @@ -18982,10 +19375,181 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c + AuTraceErr((int)mask); + return mask; +} -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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,377 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/procfs.c 2010-10-24 11:11:14.000000000 +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 ++#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; ++} +--- /dev/null ++++ linux-2.6/fs/aufs/rdu.c 2010-10-24 11:42:00.000000000 +0200 +@@ -0,0 +1,380 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -19153,7 +19717,10 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c + 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; @@ -19363,10 +19930,9 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c + 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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,187 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/rwsem.h 2010-10-24 11:42:11.000000000 +0200 +@@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -19412,9 +19978,9 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h + 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) @@ -19434,6 +20000,8 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h +#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); @@ -19554,10 +20122,9 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,269 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/sbinfo.c 2010-10-24 11:42:17.000000000 +0200 +@@ -0,0 +1,311 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -19580,6 +20147,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + * superblock private data + */ + ++#include +#include "aufs.h" + +/* @@ -19588,18 +20156,15 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c +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, @@ -19618,6 +20183,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c +{ + int err; + struct au_sbinfo *sbinfo; ++ static struct lock_class_key aufs_si; + + err = -ENOMEM; + sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); @@ -19643,6 +20209,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + + 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); + @@ -19653,13 +20220,13 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + 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; @@ -19740,14 +20307,52 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + +/* ---------------------------------------------------------------------- */ + ++/* 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) @@ -19761,7 +20366,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + +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); +} + @@ -19771,10 +20376,14 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + 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) @@ -19827,9 +20436,8 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + spin_unlock(&sbinfo->au_si_pid.tree_lock); + AuDebugOn(1 != (long)p); +} -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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/spl.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -19897,10 +20505,9 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,852 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/super.c 2010-10-24 13:42:19.000000000 +0200 +@@ -0,0 +1,867 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -19924,6 +20531,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + */ + +#include ++#include +#include +#include +#include @@ -20026,11 +20634,13 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + 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", @@ -20039,7 +20649,8 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + 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; + } +} @@ -20151,7 +20762,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + + 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); @@ -20270,26 +20881,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + +/* ---------------------------------------------------------------------- */ + -+/* -+ * 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) +{ @@ -20299,7 +20890,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + if (!sbinfo) + return; + -+ aufs_umount_begin(sb); + dbgaufs_si_fin(sbinfo); + kobject_put(&sbinfo->si_kobj); +} @@ -20540,9 +21130,12 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + 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; + } + @@ -20563,7 +21156,10 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + 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); @@ -20580,8 +21176,9 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + } + + aufs_write_unlock(root); -+ mutex_unlock(&inode->i_mutex); + ++out_mtx: ++ mutex_unlock(&inode->i_mutex); +out_opts: + free_page((unsigned long)opts.opt); +out: @@ -20638,7 +21235,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + +out_iput: + iget_failed(inode); -+ iput(inode); +out: + return err; + @@ -20736,27 +21332,52 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + 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-10-21 09:52:43.093625591 +0200 -@@ -0,0 +1,465 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/super.h 2010-10-24 11:42:36.000000000 +0200 +@@ -0,0 +1,488 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -20878,7 +21499,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +#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 */ + @@ -20900,7 +21521,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + 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. @@ -20916,6 +21537,10 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +#endif +#endif + ++#ifdef CONFIG_AUFS_SBILIST ++ struct list_head si_list; ++#endif ++ + /* dirty, necessary for unmounting, sysfs and sysrq */ + struct super_block *si_sb; +}; @@ -20957,6 +21582,8 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +#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; } @@ -20975,11 +21602,13 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +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); @@ -21037,6 +21666,32 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +/* ---------------------------------------------------------------------- */ + ++#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) +{ + /* @@ -21133,19 +21788,14 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + 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) +{ @@ -21153,12 +21803,6 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + __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) +{ @@ -21222,9 +21866,8 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/sysaufs.c 2010-10-24 11:42:49.000000000 +0200 @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -21255,7 +21898,7 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c +#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 }, \ @@ -21284,10 +21927,10 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c +{ + 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); @@ -21302,8 +21945,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c +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) @@ -21315,15 +21958,15 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c + } 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; + } + @@ -21333,9 +21976,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c +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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/sysaufs.h 2010-10-24 11:43:00.000000000 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -21380,7 +22022,7 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h + +/* 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); @@ -21442,9 +22084,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/sysfs.c 2010-10-24 15:24:09.000000000 +0200 @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -21696,9 +22337,8 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + br->br_name, 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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/sysrq.c 2010-10-24 11:43:18.000000000 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -21738,7 +22378,6 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c + + plevel = au_plevel; + au_plevel = KERN_WARNING; -+ au_debug(1); + + sbinfo = au_sbi(sb); + /* since we define pr_fmt, call printk directly */ @@ -21752,20 +22391,24 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c +#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); +} + +/* ---------------------------------------------------------------------- */ @@ -21778,15 +22421,12 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c +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 = { @@ -21819,9 +22459,8 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} -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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/vdir.c 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,884 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -22707,9 +23346,8 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + /* smp_mb(); */ + return 0; +} -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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/vfsub.c 2010-10-24 12:39:12.000000000 +0200 @@ -0,0 +1,786 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -23497,9 +24135,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c + + 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-10-21 09:52:43.093625591 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/vfsub.h 2010-10-24 11:19:23.000000000 +0200 @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -23675,9 +24312,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.096959416 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/wbr_policy.c 2010-10-24 14:48:12.000000000 +0200 @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -24378,10 +25014,9 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c + .fin = au_wbr_create_fin_mfs + } +}; -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-10-21 09:52:43.096959416 +0200 -@@ -0,0 +1,1052 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/whout.c 2010-10-24 11:43:45.000000000 +0200 +@@ -0,0 +1,1059 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -25372,35 +26007,38 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +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); @@ -25409,6 +26047,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + +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); @@ -25420,23 +26059,25 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + 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); + au_whtmp_rmdir_free(args); + } +} -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-10-21 09:52:43.096959416 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/whout.h 2010-10-24 11:43:55.000000000 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -25498,7 +26139,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h +/* 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; +}; @@ -25525,10 +26166,9 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.096959416 +0200 -@@ -0,0 +1,226 @@ +--- /dev/null ++++ linux-2.6/fs/aufs/wkq.c 2010-10-24 11:44:06.000000000 +0200 +@@ -0,0 +1,223 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima + * @@ -25591,9 +26231,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c +{ + struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); + -+ AuDebugOn(current_fsuid()); -+ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); -+ + wkinfo->func(wkinfo->args); + if (au_ftest_wkq(wkinfo->flags, WAIT)) + complete(wkinfo->comp); @@ -25710,7 +26347,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + 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; @@ -25740,9 +26377,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + + err = 0; + for (i = 0; !err && i < ARRAY_SIZE(au_wkq); i++) { -+ BUILD_BUG_ON(!WQ_RESCUER); -+ au_wkq[i].wkq = alloc_workqueue(au_wkq[i].name, !WQ_RESCUER, -+ WQ_DFL_ACTIVE); ++ au_wkq[i].wkq = create_workqueue(au_wkq[i].name); + if (IS_ERR(au_wkq[i].wkq)) + err = PTR_ERR(au_wkq[i].wkq); + else if (!au_wkq[i].wkq) @@ -25750,14 +26385,15 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + if (unlikely(err)) + au_wkq[i].wkq = NULL; + } -+ if (unlikely(err)) ++ if (!err) ++ au_dbg_verify_wkq(); ++ else + au_wkq_fin(); + + 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-10-21 09:52:43.096959416 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/wkq.h 2010-10-24 11:44:14.000000000 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -25835,7 +26471,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h + +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); +} + @@ -25847,9 +26483,8 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h + +#endif /* __KERNEL__ */ +#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-10-21 09:52:43.096959416 +0200 +--- /dev/null ++++ linux-2.6/fs/aufs/xino.c 2010-10-24 11:44:28.000000000 +0200 @@ -0,0 +1,1263 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -26196,7 +26831,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + 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); @@ -26204,12 +26839,12 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return; /* success */ + + pr_err("wkq %d\n", wkq_err); -+ atomic_dec_return(&br->br_count); ++ atomic_dec(&br->br_count); + +out_args: + kfree(args); +out: -+ atomic_dec_return(&br->br_xino_running); ++ atomic_dec(&br->br_xino_running); +} + +/* ---------------------------------------------------------------------- */ @@ -27114,9 +27749,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +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-10-21 09:52:43.096959416 +0200 +--- /dev/null ++++ linux-2.6/include/linux/aufs_type.h 2010-10-24 15:14:43.000000000 +0200 @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2005-2010 Junjiro R. Okajima @@ -27147,7 +27781,7 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty +#include +#include + -+#define AUFS_VERSION "2-standalone.tree-36-rcN-20100823" ++#define AUFS_VERSION "2.1-standalone.tree-36-UNRELEASED-20101024" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') @@ -27203,6 +27837,11 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty +#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 + @@ -27229,9 +27868,6 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty + +/* ioctl */ +enum { -+ AuCtl_PLINK_MAINT, -+ AuCtl_PLINK_CLEAN, -+ + /* readdir in userspace */ + AuCtl_RDU, + AuCtl_RDU_INO, @@ -27309,11 +27945,8 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty +} __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) + +#endif /* __AUFS_TYPE_H__ */ - -- 2.44.0