]> git.pld-linux.org Git - packages/kernel.git/blobdiff - kernel-aufs3.patch
- rel 3
[packages/kernel.git] / kernel-aufs3.patch
index 3b2e1e21e5232c186c1cfd79c583947e42a7ce90..b84ccd4f4568423aeab8f586d5c5f64b9144a984 100644 (file)
@@ -1,10 +1,10 @@
-aufs3.0 kbuild patch
+aufs3.4 kbuild patch
 
 diff --git a/fs/Kconfig b/fs/Kconfig
-index 19891aa..b660b64 100644
+index f95ae3a..6d8a9a5 100644
 --- a/fs/Kconfig
 +++ b/fs/Kconfig
-@@ -208,6 +208,7 @@ source "fs/pstore/Kconfig"
+@@ -220,6 +220,7 @@ source "fs/pstore/Kconfig"
  source "fs/sysv/Kconfig"
  source "fs/ufs/Kconfig"
  source "fs/exofs/Kconfig"
@@ -13,19 +13,19 @@ index 19891aa..b660b64 100644
  endif # MISC_FILESYSTEMS
  
 diff --git a/fs/Makefile b/fs/Makefile
-index fb68c2b..c031a85 100644
+index 2fb9779..abefac5 100644
 --- a/fs/Makefile
 +++ b/fs/Makefile
-@@ -124,3 +124,4 @@ obj-$(CONFIG_GFS2_FS)           += gfs2/
- obj-$(CONFIG_EXOFS_FS)          += exofs/
+@@ -125,3 +125,4 @@ obj-$(CONFIG_GFS2_FS)           += gfs2/
+ obj-y                         += exofs/ # Multiple modules
  obj-$(CONFIG_CEPH_FS)         += ceph/
  obj-$(CONFIG_PSTORE)          += pstore/
 +obj-$(CONFIG_AUFS_FS)           += aufs/
 diff --git a/include/linux/Kbuild b/include/linux/Kbuild
-index 01f6362..8b3b9f1 100644
+index 3c9b616..8704efa 100644
 --- a/include/linux/Kbuild
 +++ b/include/linux/Kbuild
-@@ -65,6 +65,7 @@ header-y += atmppp.h
+@@ -66,6 +66,7 @@ header-y += atmppp.h
  header-y += atmsap.h
  header-y += atmsvc.h
  header-y += audit.h
@@ -33,13 +33,13 @@ index 01f6362..8b3b9f1 100644
  header-y += auto_fs.h
  header-y += auto_fs4.h
  header-y += auxvec.h
-aufs3.0 base patch
+aufs3.4 base patch
 
 diff --git a/fs/namei.c b/fs/namei.c
-index 14ab8d3..eb4aef1 100644
+index c427919..7ff959b 100644
 --- a/fs/namei.c
 +++ b/fs/namei.c
-@@ -1697,7 +1697,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
+@@ -1831,7 +1831,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
   * needs parent already locked. Doesn't follow mounts.
   * SMP-safe.
   */
@@ -49,10 +49,10 @@ index 14ab8d3..eb4aef1 100644
        return __lookup_hash(&nd->last, nd->path.dentry, nd);
  }
 diff --git a/fs/splice.c b/fs/splice.c
-index aa866d3..19afec6 100644
+index f847684..f871233 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
-@@ -1085,8 +1085,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
+@@ -1084,8 +1084,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
  /*
   * Attempt to initiate a splice from pipe to file.
   */
@@ -63,7 +63,7 @@ index aa866d3..19afec6 100644
  {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
                                loff_t *, size_t, unsigned int);
-@@ -1113,9 +1113,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+@@ -1112,9 +1112,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.
   */
@@ -77,10 +77,10 @@ index aa866d3..19afec6 100644
        ssize_t (*splice_read)(struct file *, loff_t *,
                               struct pipe_inode_info *, size_t, unsigned int);
 diff --git a/include/linux/namei.h b/include/linux/namei.h
-index eba45ea..21ed6c9 100644
+index ffc0213..ef35a31 100644
 --- a/include/linux/namei.h
 +++ b/include/linux/namei.h
-@@ -82,6 +82,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+@@ -85,6 +85,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
  extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
                int (*open)(struct inode *, struct file *));
  
@@ -89,27 +89,27 @@ index eba45ea..21ed6c9 100644
  
  extern int follow_down_one(struct path *);
 diff --git a/include/linux/splice.h b/include/linux/splice.h
-index 997c3b4..be9a153 100644
+index 26e5b61..3ffef2f 100644
 --- a/include/linux/splice.h
 +++ b/include/linux/splice.h
-@@ -89,4 +89,10 @@ extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *);
- extern void splice_shrink_spd(struct pipe_inode_info *,
-                               struct splice_pipe_desc *);
+@@ -91,4 +91,10 @@ extern void splice_shrink_spd(struct pipe_inode_info *,
+ extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
  
+ extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
++
 +extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
 +                         loff_t *ppos, size_t len, unsigned int flags);
 +extern long do_splice_to(struct file *in, loff_t *ppos,
 +                       struct pipe_inode_info *pipe, size_t len,
 +                       unsigned int flags);
-+
  #endif
-aufs3.0 standalone patch
+aufs3.4 standalone patch
 
 diff --git a/fs/file_table.c b/fs/file_table.c
-index 01e4c1e..0e800e2 100644
+index 70f2a0f..146a3d7 100644
 --- a/fs/file_table.c
 +++ b/fs/file_table.c
-@@ -443,6 +443,8 @@ void file_sb_list_del(struct file *file)
+@@ -442,6 +442,8 @@ void file_sb_list_del(struct file *file)
        }
  }
  
@@ -119,30 +119,22 @@ index 01e4c1e..0e800e2 100644
  
  /*
 diff --git a/fs/inode.c b/fs/inode.c
-index 43566d1..4291eae 100644
+index 9f4f5fe..bb0f3ba 100644
 --- a/fs/inode.c
 +++ b/fs/inode.c
-@@ -69,6 +69,7 @@ static DEFINE_SPINLOCK(inode_lru_lock);
+@@ -56,6 +56,7 @@ static struct hlist_head *inode_hashtable __read_mostly;
+ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);
  
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock);
- __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock);
 +EXPORT_SYMBOL(inode_sb_list_lock);
  
  /*
-  * iprune_sem provides exclusion between the icache shrinking and the
+  * Empty aops. Can be used for the cases where the user does not
 diff --git a/fs/namei.c b/fs/namei.c
-index eb4aef1..66d04c6 100644
+index 7ff959b..b170167 100644
 --- a/fs/namei.c
 +++ b/fs/namei.c
-@@ -365,6 +365,7 @@ int deny_write_access(struct file * file)
-       return 0;
- }
-+EXPORT_SYMBOL(deny_write_access);
- /**
-  * path_get - get a reference to a path
-@@ -1701,6 +1702,7 @@ struct dentry *lookup_hash(struct nameidata *nd)
+@@ -1835,6 +1835,7 @@ struct dentry *lookup_hash(struct nameidata *nd)
  {
        return __lookup_hash(&nd->last, nd->path.dentry, nd);
  }
@@ -151,19 +143,19 @@ index eb4aef1..66d04c6 100644
  /**
   * lookup_one_len - filesystem helper to lookup single pathname component
 diff --git a/fs/namespace.c b/fs/namespace.c
-index fe59bd1..7d3843f 100644
+index e608199..38fcc2e 100644
 --- a/fs/namespace.c
 +++ b/fs/namespace.c
-@@ -1508,6 +1508,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
+@@ -1339,6 +1339,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
        }
        return 0;
  }
 +EXPORT_SYMBOL(iterate_mounts);
  
- static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
+ static void cleanup_group_ids(struct mount *mnt, struct mount *end)
  {
 diff --git a/fs/notify/group.c b/fs/notify/group.c
-index d309f38..f0e9568 100644
+index 63fc294..6f4adca 100644
 --- a/fs/notify/group.c
 +++ b/fs/notify/group.c
 @@ -22,6 +22,7 @@
@@ -188,7 +180,7 @@ index d309f38..f0e9568 100644
  }
 +EXPORT_SYMBOL(fsnotify_alloc_group);
 diff --git a/fs/notify/mark.c b/fs/notify/mark.c
-index 252ab1f..2199b9b 100644
+index f104d56..54f36db 100644
 --- a/fs/notify/mark.c
 +++ b/fs/notify/mark.c
 @@ -112,6 +112,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
@@ -199,7 +191,7 @@ index 252ab1f..2199b9b 100644
  
  /*
   * Any time a mark is getting freed we end up here.
-@@ -189,6 +190,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
+@@ -191,6 +192,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
        if (unlikely(atomic_dec_and_test(&group->num_marks)))
                fsnotify_final_destroy_group(group);
  }
@@ -207,7 +199,7 @@ index 252ab1f..2199b9b 100644
  
  void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
  {
-@@ -276,6 +278,7 @@ err:
+@@ -278,6 +280,7 @@ err:
  
        return ret;
  }
@@ -215,7 +207,7 @@ index 252ab1f..2199b9b 100644
  
  /*
   * clear any marks in a group in which mark->flags & flags is true
-@@ -331,6 +334,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
+@@ -333,6 +336,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
        atomic_set(&mark->refcnt, 1);
        mark->free_mark = free_mark;
  }
@@ -224,7 +216,7 @@ index 252ab1f..2199b9b 100644
  static int fsnotify_mark_destroy(void *ignored)
  {
 diff --git a/fs/open.c b/fs/open.c
-index b52cf01..c1b341c 100644
+index 5720854..ec59242 100644
 --- a/fs/open.c
 +++ b/fs/open.c
 @@ -60,6 +60,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
@@ -236,10 +228,10 @@ index b52cf01..c1b341c 100644
  static long do_sys_truncate(const char __user *pathname, loff_t length)
  {
 diff --git a/fs/splice.c b/fs/splice.c
-index 19afec6..11f07f8 100644
+index f871233..70f5481 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
-@@ -1109,6 +1109,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+@@ -1108,6 +1108,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
  
        return splice_write(pipe, out, ppos, len, flags);
  }
@@ -247,7 +239,7 @@ index 19afec6..11f07f8 100644
  
  /*
   * Attempt to initiate a splice from a file to a pipe.
-@@ -1135,6 +1136,7 @@ long do_splice_to(struct file *in, loff_t *ppos,
+@@ -1134,6 +1135,7 @@ long do_splice_to(struct file *in, loff_t *ppos,
  
        return splice_read(in, ppos, pipe, len, flags);
  }
@@ -256,20 +248,27 @@ index 19afec6..11f07f8 100644
  /**
   * splice_direct_to_actor - splices data directly between two non-pipes
 diff --git a/security/commoncap.c b/security/commoncap.c
-index a93b3b7..024282c 100644
+index 71a166a..5d63aac 100644
 --- a/security/commoncap.c
 +++ b/security/commoncap.c
-@@ -978,4 +978,4 @@ int cap_file_mmap(struct file *file, uns
+@@ -972,3 +972,4 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
        }
        return ret;
  }
--
 +EXPORT_SYMBOL(cap_file_mmap);
 diff --git a/security/device_cgroup.c b/security/device_cgroup.c
-index 1be6826..215278c 100644
+index c43a332..0c37289 100644
 --- a/security/device_cgroup.c
 +++ b/security/device_cgroup.c
-@@ -508,6 +508,7 @@ found:
+@@ -7,6 +7,7 @@
+ #include <linux/device_cgroup.h>
+ #include <linux/cgroup.h>
+ #include <linux/ctype.h>
++#include <linux/export.h>
+ #include <linux/list.h>
+ #include <linux/uaccess.h>
+ #include <linux/seq_file.h>
+@@ -499,6 +500,7 @@ found:
  
        return -EPERM;
  }
@@ -278,10 +277,10 @@ index 1be6826..215278c 100644
  int devcgroup_inode_mknod(int mode, dev_t dev)
  {
 diff --git a/security/security.c b/security/security.c
-index 4ba6d4c..9f64bb8 100644
+index bf619ff..60b996a 100644
 --- a/security/security.c
 +++ b/security/security.c
-@@ -373,6 +373,7 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry)
+@@ -380,6 +380,7 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry)
                return 0;
        return security_ops->path_rmdir(dir, dentry);
  }
@@ -289,7 +288,7 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_path_unlink(struct path *dir, struct dentry *dentry)
  {
-@@ -389,6 +390,7 @@ int security_path_symlink(struct path *dir, struct dentry *dentry,
+@@ -396,6 +397,7 @@ int security_path_symlink(struct path *dir, struct dentry *dentry,
                return 0;
        return security_ops->path_symlink(dir, dentry, old_name);
  }
@@ -297,7 +296,7 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_path_link(struct dentry *old_dentry, struct path *new_dir,
                       struct dentry *new_dentry)
-@@ -397,6 +399,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+@@ -404,6 +406,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
                return 0;
        return security_ops->path_link(old_dentry, new_dir, new_dentry);
  }
@@ -305,23 +304,23 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
                         struct path *new_dir, struct dentry *new_dentry)
-@@ -415,6 +418,7 @@ int security_path_truncate(struct path *path)
+@@ -422,6 +425,7 @@ int security_path_truncate(struct path *path)
                return 0;
        return security_ops->path_truncate(path);
  }
 +EXPORT_SYMBOL(security_path_truncate);
  
- int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
-                       mode_t mode)
-@@ -423,6 +427,7 @@ int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ int security_path_chmod(struct path *path, umode_t mode)
+ {
+@@ -429,6 +433,7 @@ int security_path_chmod(struct path *path, umode_t mode)
                return 0;
-       return security_ops->path_chmod(dentry, mnt, mode);
+       return security_ops->path_chmod(path, mode);
  }
 +EXPORT_SYMBOL(security_path_chmod);
  
  int security_path_chown(struct path *path, uid_t uid, gid_t gid)
  {
-@@ -430,6 +435,7 @@ int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+@@ -436,6 +441,7 @@ int security_path_chown(struct path *path, uid_t uid, gid_t gid)
                return 0;
        return security_ops->path_chown(path, uid, gid);
  }
@@ -329,7 +328,7 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_path_chroot(struct path *path)
  {
-@@ -506,6 +512,7 @@ int security_inode_readlink(struct dentry *dentry)
+@@ -512,6 +518,7 @@ int security_inode_readlink(struct dentry *dentry)
                return 0;
        return security_ops->inode_readlink(dentry);
  }
@@ -337,15 +336,15 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
  {
-@@ -520,6 +527,7 @@ int security_inode_permission(struct inode *inode, int mask)
+@@ -526,6 +533,7 @@ int security_inode_permission(struct inode *inode, int mask)
                return 0;
-       return security_ops->inode_permission(inode, mask, 0);
+       return security_ops->inode_permission(inode, mask);
  }
 +EXPORT_SYMBOL(security_inode_permission);
  
- int security_inode_exec_permission(struct inode *inode, unsigned int flags)
+ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
  {
-@@ -626,6 +634,7 @@ int security_file_permission(struct file *file, int mask)
+@@ -641,6 +649,7 @@ int security_file_permission(struct file *file, int mask)
  
        return fsnotify_perm(file, mask);
  }
@@ -353,7 +352,7 @@ index 4ba6d4c..9f64bb8 100644
  
  int security_file_alloc(struct file *file)
  {
-@@ -653,6 +662,7 @@ int security_file_mmap(struct file *file, unsigned long reqprot,
+@@ -668,6 +677,7 @@ int security_file_mmap(struct file *file, unsigned long reqprot,
                return ret;
        return ima_file_mmap(file, prot);
  }
@@ -363,7 +362,7 @@ index 4ba6d4c..9f64bb8 100644
                            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       2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/ABI/testing/debugfs-aufs       2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,37 @@
 +What:         /debug/aufs/si_<id>/
 +Date:         March 2009
@@ -404,7 +403,7 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Document
 +              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 2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/ABI/testing/sysfs-aufs 2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,24 @@
 +What:         /sys/fs/aufs/si_<id>/
 +Date:         March 2009
@@ -432,7 +431,7 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentat
 +              will be empty. About XINO files, see the aufs manual.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt linux/Documentation/filesystems/aufs/design/01intro.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/01intro.txt    2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/01intro.txt    2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,162 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -598,7 +597,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt lin
 +about it. But currently I have implemented it in kernel space.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt linux/Documentation/filesystems/aufs/design/02struct.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt        1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/02struct.txt   2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/02struct.txt   2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,226 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -828,7 +827,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li
 +dir, aufs reverts it after copy-up.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt linux/Documentation/filesystems/aufs/design/03lookup.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt        1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/03lookup.txt   2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/03lookup.txt   2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,106 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -938,7 +937,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt li
 +   by over-mounting something (or another method).
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt linux/Documentation/filesystems/aufs/design/04branch.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt        1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/04branch.txt   2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/04branch.txt   2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,76 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1018,7 +1017,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt li
 +    same named entry on the upper branch.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt linux/Documentation/filesystems/aufs/design/05wbr_policy.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt    1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt       2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt       2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,65 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1087,7 +1086,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.tx
 +  copyup policy.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linux/Documentation/filesystems/aufs/design/06mmap.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/06mmap.txt     2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/06mmap.txt     2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,47 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1138,7 +1137,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linu
 +switching the approach.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt linux/Documentation/filesystems/aufs/design/07export.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt        1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/07export.txt   2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/07export.txt   2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,59 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1201,7 +1200,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt li
 +  lookup_one_len(), vfs_getattr(), encode_fh() and others.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linux/Documentation/filesystems/aufs/design/08shwh.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/08shwh.txt     2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/08shwh.txt     2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,53 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1258,7 +1257,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linu
 +initramfs will use it to replace the old one at the next boot.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt linux/Documentation/filesystems/aufs/design/10dynop.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/10dynop.txt    2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/10dynop.txt    2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,47 @@
 +
 +# Copyright (C) 2010-2011 Junjiro R. Okajima
@@ -1309,7 +1308,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt lin
 +vm_operations_struct for regular files only.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linux/Documentation/filesystems/aufs/design/99plan.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/99plan.txt     2011-08-24 13:30:24.727980364 +0200
++++ linux/Documentation/filesystems/aufs/design/99plan.txt     2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,96 @@
 +
 +# Copyright (C) 2005-2011 Junjiro R. Okajima
@@ -1409,8 +1408,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linu
 +Otherwise from /new.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documentation/filesystems/aufs/README
 --- /usr/share/empty/Documentation/filesystems/aufs/README     1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/README        2011-08-24 13:30:24.727980364 +0200
-@@ -0,0 +1,290 @@
++++ linux/Documentation/filesystems/aufs/README        2012-05-22 09:06:08.864125478 +0200
+@@ -0,0 +1,330 @@
 +
 +Aufs3 -- advanced multi layered unification filesystem version 3.x
 +http://aufs.sf.net
@@ -1507,14 +1506,32 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +
 +2. Download
 +----------------------------------------
-+There were three GIT trees for aufs2, but for aufs3 two GIT trees,
-+aufs3-standalone and aufs-util. Note that there is no "3" in "aufs-util."
-+The aufs3-standalone tree has only aufs source files
++There were three GIT trees for aufs3, aufs3-linux.git,
++aufs3-standalone.git, and aufs-util.git. Note that there is no "3" in
++"aufs-util.git."
++While the aufs-util is always necessary, you need either of aufs3-linux
++or aufs3-standalone.
++
++The aufs3-linux tree includes the whole linux mainline GIT tree,
++git://git.kernel.org/.../torvalds/linux.git.
++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot
++build aufs3 as an externel kernel module.
++
++On the other hand, the aufs3-standalone tree has only aufs source files
 +and necessary patches, and you can select CONFIG_AUFS_FS=m.
 +
 +You will find GIT branches whose name is in form of "aufs3.x" where "x"
 +represents the linux kernel version, "linux-3.x". For instance,
-+"aufs3.0" is for linux-3.0.
++"aufs3.0" is for linux-3.0. For latest "linux-3.x-rcN", use
++"aufs3.x-rcN" branch.
++
++o aufs3-linux tree
++$ git clone --reference /your/linux/git/tree \
++      git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-linux.git \
++      aufs3-linux.git
++- if you don't have linux GIT tree, then remove "--reference ..."
++$ cd aufs3-linux.git
++$ git checkout origin/aufs3.0
 +
 +o aufs3-standalone tree
 +$ git clone git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-standalone.git \
@@ -1528,12 +1545,23 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +$ cd aufs-util.git
 +$ git checkout origin/aufs3.0
 +
-+You may not be able to find the GIT branch in aufs-util for your
-+version. In this case, you should git-checkout the branch for the
++Note: The 3.x-rcN branch is to be used with `rc' kernel versions ONLY.
++The minor version number, 'x' in '3.x', of aufs may not always
++follow the minor version number of the kernel.
++Because changes in the kernel that cause the use of a new
++minor version number do not always require changes to aufs-util.
++
++Since aufs-util has its own minor version number, you may not be
++able to find a GIT branch in aufs-util for your kernel's
++exact minor version number.
++In this case, you should git-checkout the branch for the
 +nearest lower number.
-+If you are using linux-3.10 and aufs3.10 (which are not released yet),
-+but the "aufs3.10" branch doesn't exit in this repository, then
-+"aufs3.9", "aufs3.8", ... or something is the branch for you.
++
++For (an unreleased) example:
++If you are using "linux-3.10" and the "aufs3.10" branch
++does not exist in aufs-util repository, then "aufs3.9", "aufs3.8"
++or something numerically smaller is the branch for your kernel.
++
 +Also you can view all branches by
 +      $ git branch -a
 +
@@ -1542,6 +1570,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +----------------------------------------
 +Make sure you have git-checkout'ed the correct branch.
 +
++For aufs3-linux tree,
++- enable CONFIG_EXPERIMENTAL and CONFIG_AUFS_FS.
++- set other aufs configurations if necessary.
++
 +For aufs3-standalone tree,
 +There are several ways to build.
 +
@@ -1559,7 +1591,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +  =m or =y.
 +- and build your kernel as usual.
 +- install the built kernel.
-+- install the header files too by "make headers_install".
++- install the header files too by "make headers_install" to the
++  directory where you specify. By default, it is $PWD/usr.
 +- and reboot your system.
 +
 +2.
@@ -1581,7 +1614,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +    ./aufs.ko to /lib/modules/... and run depmod -a (or reboot simply).
 +  + run "make headers_install" to install the aufs header file (you can
 +    specify DESTDIR), or copty ./usr/include/linux/aufs_type.h to
-+    /usr/include/linux or wherever you like.
++    /usr/include/linux or wherever you like. By default, the target
++    directory is $PWD/usr.
 +- no need to apply aufs3-kbuild.patch, nor copying source files to your
 +  kernel source tree.
 +
@@ -1594,6 +1628,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +
 +And then,
 +- read README in aufs-util, build and install it
++- note that your distribution may contain an obsoleted version of
++  aufs_type.h in /usr/include/linux or something. When you build aufs
++  utilities, make sure that your compiler refers the correct aufs header
++  file which is built by "make headers_install."
 +- if you want to use readdir(3) in userspace or pathconf(3) wrapper,
 +  then run "make install_ulib" too. And refer to the aufs manual in
 +  detail.
@@ -1683,7 +1721,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +Pavel Pronskiy made a donation (2011/2).
 +Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy
 +      Networks (Ed Wildgoose) made a donation for hardware (2011/3).
-+Max Lekomcev (DOM-TV project) made a donation (2011/7).
++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12 and 2012/3).
++Sam Liddicott made a donation (2011/9).
 +
 +Thank you very much.
 +Donations are always, including future donations, very important and
@@ -1703,10 +1742,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +# End: ;
 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       2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/aufs.h       2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,60 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -1767,10 +1806,10 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h
 +#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     2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,1170 @@
++++ linux/fs/aufs/branch.c     2012-05-22 09:06:08.864125478 +0200
+@@ -0,0 +1,1169 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -1792,7 +1831,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 + */
 +
 +#include <linux/compat.h>
-+#include <linux/file.h>
 +#include <linux/statfs.h>
 +#include "aufs.h"
 +
@@ -2941,10 +2979,10 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +}
 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     2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,233 @@
++++ linux/fs/aufs/branch.h     2012-05-22 09:06:08.864125478 +0200
+@@ -0,0 +1,230 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -2970,9 +3008,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/fs.h>
 +#include <linux/mount.h>
-+#include <linux/aufs_type.h>
 +#include "dynop.h"
 +#include "rwsem.h"
 +#include "super.h"
@@ -3040,30 +3076,29 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 +
 +/* ---------------------------------------------------------------------- */
 +
-+/* branch permission and attribute */
-+enum {
-+      AuBrPerm_RW,            /* writable, linkable wh */
-+      AuBrPerm_RO,            /* readonly, no wh */
-+      AuBrPerm_RR,            /* natively readonly, no wh */
-+
-+      AuBrPerm_RWNoLinkWH,    /* un-linkable whiteouts */
++/* branch permissions and attributes */
++#define AuBrPerm_RW           1               /* writable, hardlinkable wh */
++#define AuBrPerm_RO           (1 << 1)        /* readonly */
++#define AuBrPerm_RR           (1 << 2)        /* natively readonly */
++#define AuBrPerm_Mask         (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR)
 +
-+      AuBrPerm_ROWH,          /* whiteout-able */
-+      AuBrPerm_RRWH,          /* whiteout-able */
++#define AuBrRAttr_WH          (1 << 3)        /* whiteout-able */
 +
-+      AuBrPerm_Last
-+};
++#define AuBrWAttr_NoLinkWH    (1 << 4)        /* un-hardlinkable whiteouts */
 +
 +static inline int au_br_writable(int brperm)
 +{
-+      return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH;
++      return brperm & AuBrPerm_RW;
 +}
 +
 +static inline int au_br_whable(int brperm)
 +{
-+      return brperm == AuBrPerm_RW
-+              || brperm == AuBrPerm_ROWH
-+              || brperm == AuBrPerm_RRWH;
++      return brperm & (AuBrPerm_RW | AuBrRAttr_WH);
++}
++
++static inline int au_br_wh_linkable(int brperm)
++{
++      return !(brperm & AuBrWAttr_NoLinkWH);
 +}
 +
 +static inline int au_br_rdonly(struct au_branch *br)
@@ -3076,7 +3111,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 +static inline int au_br_hnotifyable(int brperm __maybe_unused)
 +{
 +#ifdef CONFIG_AUFS_HNOTIFY
-+      return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH;
++      return !(brperm & AuBrPerm_RR);
 +#else
 +      return 0;
 +#endif
@@ -3178,7 +3213,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 +#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      2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/conf.mk      2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,38 @@
 +
 +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
@@ -3220,10 +3255,10 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk
 +-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       2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,1080 @@
++++ linux/fs/aufs/cpup.c       2012-05-22 09:06:08.864125478 +0200
+@@ -0,0 +1,1084 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -3244,10 +3279,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 + * copy-up functions, see wbr_policy.c for copy-down
 + */
 +
-+#include <linux/file.h>
 +#include <linux/fs_stack.h>
 +#include <linux/mm.h>
-+#include <linux/uaccess.h>
 +#include "aufs.h"
 +
 +void au_cpup_attr_flags(struct inode *dst, struct inode *src)
@@ -3284,7 +3317,12 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +          && au_plink_test(inode))
 +              return;
 +
-+      inode->i_nlink = h_inode->i_nlink;
++      /*
++       * 0 can happen in revalidating.
++       * h_inode->i_mutex is not held, but it is harmless since once i_nlink
++       * reaches 0, it will never become positive.
++       */
++      set_nlink(inode, h_inode->i_nlink);
 +
 +      /*
 +       * fewer nlink makes find(1) noisy, but larger nlink doesn't.
@@ -3647,6 +3685,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      if (unlikely(!sym.k))
 +              goto out;
 +
++      /* unnecessary to support mmap_sem since symlink is not mmap-able */
 +      old_fs = get_fs();
 +      set_fs(KERNEL_DS);
 +      symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX);
@@ -4304,10 +4343,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +}
 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       2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,83 @@
++++ linux/fs/aufs/cpup.h       2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,81 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -4334,8 +4373,6 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
 +#ifdef __KERNEL__
 +
 +#include <linux/path.h>
-+#include <linux/time.h>
-+#include <linux/aufs_type.h>
 +
 +struct inode;
 +struct file;
@@ -4391,10 +4428,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
 +#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    2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/dbgaufs.c    2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,334 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -4532,7 +4569,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 +                   || memcmp(name->name, DbgaufsXi_PREFIX,
 +                             sizeof(DbgaufsXi_PREFIX) - 1)))
 +              goto out;
-+      err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
++      err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
 +      if (unlikely(err))
 +              goto out;
 +
@@ -4729,10 +4766,10 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 +}
 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    2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,52 @@
++++ linux/fs/aufs/dbgaufs.h    2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,49 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -4758,9 +4795,6 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/init.h>
-+#include <linux/aufs_type.h>
-+
 +struct super_block;
 +struct au_sbinfo;
 +
@@ -4785,10 +4819,10 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h
 +#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      2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/dcsub.c      2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,243 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -5032,10 +5066,10 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +}
 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      2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,95 @@
++++ linux/fs/aufs/dcsub.h      2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,94 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -5063,7 +5097,6 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
 +
 +#include <linux/dcache.h>
 +#include <linux/fs.h>
-+#include <linux/types.h>
 +
 +struct dentry;
 +
@@ -5131,10 +5164,10 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
 +#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      2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,486 @@
++++ linux/fs/aufs/debug.c      2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,489 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -5155,7 +5188,6 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 + * debug print functions
 + */
 +
-+#include <linux/module.h>
 +#include <linux/vt_kern.h>
 +#include "aufs.h"
 +
@@ -5399,11 +5431,11 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +      if (!sb || IS_ERR(sb))
 +              goto out;
 +
-+      dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, "
++      dpri("s%d: {perm 0x%x, id %d, cnt %d, wbr %p}, "
 +           "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, "
 +           "xino %d\n",
-+           bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr,
-+           au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
++           bindex, br->br_perm, br->br_id, atomic_read(&br->br_count),
++           br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
 +           sb->s_flags, sb->s_count,
 +           atomic_read(&sb->s_active), !!br->br_xino.xi_file);
 +      return 0;
@@ -5572,7 +5604,11 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +{
 +      if (au_wkq_test()) {
 +              au_dbg_blocked();
-+              WARN_ON(1);
++              /*
++               * It may be recursive, but udba=notify between two aufs mounts,
++               * where a single ro branch is shared, is not a problem.
++               */
++              /* WARN_ON(1); */
 +      }
 +}
 +
@@ -5621,10 +5657,10 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +}
 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      2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,252 @@
++++ linux/fs/aufs/debug.h      2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,242 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -5650,19 +5686,9 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
 +
 +#ifdef __KERNEL__
 +
-+#include <asm/system.h>
-+#include <linux/bug.h>
-+/* #include <linux/err.h> */
-+#include <linux/init.h>
 +#include <linux/module.h>
 +#include <linux/kallsyms.h>
-+/* #include <linux/kernel.h> */
-+#include <linux/delay.h>
-+/* #include <linux/kd.h> */
 +#include <linux/sysrq.h>
-+#include <linux/aufs_type.h>
-+
-+#include <asm/system.h>
 +
 +#ifdef CONFIG_AUFS_DEBUG
 +#define AuDebugOn(a)          BUG_ON(a)
@@ -5877,10 +5903,10 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
 +#endif /* __AUFS_DEBUG_H__ */
 diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 --- /usr/share/empty/fs/aufs/dentry.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.c     2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/dentry.c     2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,1140 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -7021,10 +7047,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +};
 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     2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,238 @@
++++ linux/fs/aufs/dentry.h     2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,237 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -7051,7 +7077,6 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
 +#ifdef __KERNEL__
 +
 +#include <linux/dcache.h>
-+#include <linux/aufs_type.h>
 +#include "rwsem.h"
 +
 +struct au_hdentry {
@@ -7263,10 +7288,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
 +#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      2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/dinfo.c      2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,543 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -7810,10 +7835,10 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
 +}
 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        2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,624 @@
++++ linux/fs/aufs/dir.c        2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,636 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -7834,26 +7859,35 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 + * directory operations
 + */
 +
-+#include <linux/file.h>
 +#include <linux/fs_stack.h>
 +#include "aufs.h"
 +
 +void au_add_nlink(struct inode *dir, struct inode *h_dir)
 +{
++      unsigned int nlink;
++
 +      AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
 +
-+      dir->i_nlink += h_dir->i_nlink - 2;
++      nlink = dir->i_nlink;
++      nlink += h_dir->i_nlink - 2;
 +      if (h_dir->i_nlink < 2)
-+              dir->i_nlink += 2;
++              nlink += 2;
++      /* 0 can happen in revaliding */
++      set_nlink(dir, nlink);
 +}
 +
 +void au_sub_nlink(struct inode *dir, struct inode *h_dir)
 +{
++      unsigned int nlink;
++
 +      AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
 +
-+      dir->i_nlink -= h_dir->i_nlink - 2;
++      nlink = dir->i_nlink;
++      nlink -= h_dir->i_nlink - 2;
 +      if (h_dir->i_nlink < 2)
-+              dir->i_nlink -= 2;
++              nlink -= 2;
++      /* nlink == 0 means the branch-fs is broken */
++      set_nlink(dir, nlink);
 +}
 +
 +loff_t au_dir_size(struct file *file, struct dentry *dentry)
@@ -8135,16 +8169,18 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 +/*
 + * @file may be NULL
 + */
-+static int aufs_fsync_dir(struct file *file, int datasync)
++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end,
++                        int datasync)
 +{
 +      int err;
 +      struct dentry *dentry;
 +      struct super_block *sb;
-+
-+      dentry = file->f_dentry;
-+      IMustLock(dentry->d_inode);
++      struct mutex *mtx;
 +
 +      err = 0;
++      dentry = file->f_dentry;
++      mtx = &dentry->d_inode->i_mutex;
++      mutex_lock(mtx);
 +      sb = dentry->d_sb;
 +      si_noflush_read_lock(sb);
 +      if (file)
@@ -8159,6 +8195,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 +              fi_write_unlock(file);
 +
 +      si_read_unlock(sb);
++      mutex_unlock(mtx);
 +      return err;
 +}
 +
@@ -8168,7 +8205,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 +{
 +      int err;
 +      struct dentry *dentry;
-+      struct inode *inode;
++      struct inode *inode, *h_inode;
 +      struct super_block *sb;
 +
 +      dentry = file->f_dentry;
@@ -8187,22 +8224,22 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 +      if (unlikely(err))
 +              goto out_unlock;
 +
++      h_inode = au_h_iptr(inode, au_ibstart(inode));
 +      if (!au_test_nfsd()) {
 +              err = au_vdir_fill_de(file, dirent, filldir);
-+              fsstack_copy_attr_atime(inode,
-+                                      au_h_iptr(inode, au_ibstart(inode)));
++              fsstack_copy_attr_atime(inode, h_inode);
 +      } else {
 +              /*
 +               * nfsd filldir may call lookup_one_len(), vfs_getattr(),
 +               * encode_fh() and others.
 +               */
-+              struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode));
-+
++              atomic_inc(&h_inode->i_count);
 +              di_read_unlock(dentry, AuLock_IR);
 +              si_read_unlock(sb);
 +              err = au_vdir_fill_de(file, dirent, filldir);
 +              fsstack_copy_attr_atime(inode, h_inode);
 +              fi_write_unlock(file);
++              iput(h_inode);
 +
 +              AuTraceErr(err);
 +              return err;
@@ -8438,10 +8475,10 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
 +};
 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        2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,138 @@
++++ linux/fs/aufs/dir.h        2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,137 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -8468,7 +8505,6 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
 +#ifdef __KERNEL__
 +
 +#include <linux/fs.h>
-+#include <linux/aufs_type.h>
 +
 +/* ---------------------------------------------------------------------- */
 +
@@ -8580,10 +8616,10 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
 +#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      2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/dynop.c      2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,377 @@
 +/*
-+ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ * Copyright (C) 2010-2012 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
@@ -8961,10 +8997,10 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
 +}
 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      2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,80 @@
++++ linux/fs/aufs/dynop.h      2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,76 @@
 +/*
-+ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ * Copyright (C) 2010-2012 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
@@ -8990,10 +9026,6 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/fs.h>
-+#include <linux/mm.h>
-+#include <linux/rcupdate.h>
-+#include <linux/aufs_type.h>
 +#include "inode.h"
 +
 +enum {AuDy_AOP, AuDyLast};
@@ -9045,10 +9077,10 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
 +#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     2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,805 @@
++++ linux/fs/aufs/export.c     2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,803 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -9070,12 +9102,12 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 + */
 +
 +#include <linux/exportfs.h>
-+#include <linux/file.h>
-+#include <linux/mnt_namespace.h>
++#include <linux/fs_struct.h>
 +#include <linux/namei.h>
 +#include <linux/nsproxy.h>
 +#include <linux/random.h>
 +#include <linux/writeback.h>
++#include "../fs/mount.h"
 +#include "aufs.h"
 +
 +union conv {
@@ -9329,18 +9361,16 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +static struct vfsmount *au_mnt_get(struct super_block *sb)
 +{
 +      int err;
++      struct path root;
 +      struct au_compare_mnt_args args = {
 +              .sb = sb
 +      };
-+      struct mnt_namespace *ns;
 +
++      get_fs_root(current->fs, &root);
 +      br_read_lock(vfsmount_lock);
-+      /* no get/put ?? */
-+      AuDebugOn(!current->nsproxy);
-+      ns = current->nsproxy->mnt_ns;
-+      AuDebugOn(!ns);
-+      err = iterate_mounts(au_compare_mnt, &args, ns->root);
++      err = iterate_mounts(au_compare_mnt, &args, root.mnt);
 +      br_read_unlock(vfsmount_lock);
++      path_put(&root);
 +      AuDebugOn(!err);
 +      AuDebugOn(!args.mnt);
 +      return args.mnt;
@@ -9854,10 +9884,10 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +}
 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       2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/file.c       2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,676 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -9878,9 +9908,9 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 + * handling file/dir, and address_space operation
 + */
 +
-+#include <linux/file.h>
-+#include <linux/fsnotify.h>
-+#include <linux/namei.h>
++#ifdef CONFIG_AUFS_DEBUG
++#include <linux/migrate.h>
++#endif
 +#include <linux/pagemap.h>
 +#include "aufs.h"
 +
@@ -10499,7 +10529,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +static int aufs_releasepage(struct page *page, gfp_t gfp)
 +{ AuUnsupport(); return 0; }
 +static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
-+                          struct page *page)
++                          struct page *page, enum migrate_mode mode)
 +{ AuUnsupport(); return 0; }
 +static int aufs_launder_page(struct page *page)
 +{ AuUnsupport(); return 0; }
@@ -10534,10 +10564,10 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +};
 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       2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,299 @@
++++ linux/fs/aufs/file.h       2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,298 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -10566,7 +10596,6 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +#include <linux/file.h>
 +#include <linux/fs.h>
 +#include <linux/poll.h>
-+#include <linux/aufs_type.h>
 +#include "rwsem.h"
 +
 +struct au_branch;
@@ -10837,10 +10866,10 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +#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      2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,153 @@
++++ linux/fs/aufs/finfo.c      2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,156 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -10861,7 +10890,6 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 + * file private data
 + */
 +
-+#include <linux/file.h>
 +#include "aufs.h"
 +
 +void au_hfput(struct au_hfile *hf, struct file *file)
@@ -10969,7 +10997,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 +
 +int au_finfo_init(struct file *file, struct au_fidir *fidir)
 +{
-+      int err;
++      int err, lc_idx;
 +      struct au_finfo *finfo;
 +      struct dentry *dentry;
 +
@@ -10981,6 +11009,10 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 +
 +      err = 0;
 +      au_nfiles_inc(dentry->d_sb);
++      lc_idx = AuLcNonDir_FIINFO;
++      if (fidir)
++              lc_idx = AuLcDir_FIINFO;
++      au_rw_class(&finfo->fi_rwsem, au_lc_key + lc_idx);
 +      au_rw_write_lock(&finfo->fi_rwsem);
 +      finfo->fi_btop = -1;
 +      finfo->fi_hdir = fidir;
@@ -10994,10 +11026,10 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 +}
 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       2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,717 @@
++++ linux/fs/aufs/f_op.c       2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,729 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -11018,10 +11050,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 + * file and vm operations
 + */
 +
-+#include <linux/file.h>
 +#include <linux/fs_stack.h>
 +#include <linux/mman.h>
-+#include <linux/mm.h>
 +#include <linux/security.h>
 +#include "aufs.h"
 +
@@ -11113,6 +11143,13 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +}
 +
 +/* ---------------------------------------------------------------------- */
++/*
++ * read and write functions acquire [fdi]_rwsem once, but release before
++ * mmap_sem. This is because to stop a race condition between mmap(2).
++ * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping
++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in
++ * read functions after [fdi]_rwsem are released, but it should be harmless.
++ */
 +
 +static ssize_t aufs_read(struct file *file, char __user *buf, size_t count,
 +                       loff_t *ppos)
@@ -11130,13 +11167,18 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +              goto out;
 +
 +      h_file = au_hf_top(file);
++      get_file(h_file);
++      di_read_unlock(dentry, AuLock_IR);
++      fi_read_unlock(file);
++
++      /* filedata may be obsoleted by concurrent copyup, but no problem */
 +      err = vfsub_read_u(h_file, buf, count, ppos);
 +      /* todo: necessary? */
 +      /* file->f_ra = h_file->f_ra; */
++      /* update without lock, I don't think it a problem */
 +      fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++      fput(h_file);
 +
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_read_unlock(file);
 +out:
 +      si_read_unlock(sb);
 +      return err;
@@ -11170,11 +11212,13 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +      ssize_t err;
 +      struct au_pin pin;
 +      struct dentry *dentry;
++      struct super_block *sb;
 +      struct inode *inode;
 +      struct file *h_file;
 +      char __user *buf = (char __user *)ubuf;
 +
 +      dentry = file->f_dentry;
++      sb = dentry->d_sb;
 +      inode = dentry->d_inode;
 +      au_mtx_and_read_lock(inode);
 +
@@ -11184,20 +11228,27 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +
 +      err = au_ready_to_write(file, -1, &pin);
 +      di_downgrade_lock(dentry, AuLock_IR);
-+      if (unlikely(err))
-+              goto out_unlock;
++      if (unlikely(err)) {
++              di_read_unlock(dentry, AuLock_IR);
++              fi_write_unlock(file);
++              goto out;
++      }
 +
 +      h_file = au_hf_top(file);
++      get_file(h_file);
 +      au_unpin(&pin);
++      di_read_unlock(dentry, AuLock_IR);
++      fi_write_unlock(file);
++
 +      err = vfsub_write_u(h_file, buf, count, ppos);
++      ii_write_lock_child(inode);
 +      au_cpup_attr_timesizes(inode);
 +      inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++      ii_write_unlock(inode);
++      fput(h_file);
 +
-+out_unlock:
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_write_unlock(file);
 +out:
-+      si_read_unlock(inode->i_sb);
++      si_read_unlock(sb);
 +      mutex_unlock(&inode->i_mutex);
 +      return err;
 +}
@@ -11252,12 +11303,16 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +              goto out;
 +
 +      h_file = au_hf_top(file);
++      get_file(h_file);
++      di_read_unlock(dentry, AuLock_IR);
++      fi_read_unlock(file);
++
 +      err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos);
 +      /* todo: necessary? */
 +      /* file->f_ra = h_file->f_ra; */
++      /* update without lock, I don't think it a problem */
 +      fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_read_unlock(file);
++      fput(h_file);
 +
 +out:
 +      si_read_unlock(sb);
@@ -11272,9 +11327,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;
++      sb = dentry->d_sb;
 +      inode = dentry->d_inode;
 +      au_mtx_and_read_lock(inode);
 +
@@ -11284,20 +11341,27 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +
 +      err = au_ready_to_write(file, -1, &pin);
 +      di_downgrade_lock(dentry, AuLock_IR);
-+      if (unlikely(err))
-+              goto out_unlock;
++      if (unlikely(err)) {
++              di_read_unlock(dentry, AuLock_IR);
++              fi_write_unlock(file);
++              goto out;
++      }
 +
-+      au_unpin(&pin);
 +      h_file = au_hf_top(file);
++      get_file(h_file);
++      au_unpin(&pin);
++      di_read_unlock(dentry, AuLock_IR);
++      fi_write_unlock(file);
++
 +      err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos);
++      ii_write_lock_child(inode);
 +      au_cpup_attr_timesizes(inode);
 +      inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++      ii_write_unlock(inode);
++      fput(h_file);
 +
-+out_unlock:
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_write_unlock(file);
 +out:
-+      si_read_unlock(inode->i_sb);
++      si_read_unlock(sb);
 +      mutex_unlock(&inode->i_mutex);
 +      return err;
 +}
@@ -11320,6 +11384,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +
 +      err = -EINVAL;
 +      h_file = au_hf_top(file);
++      get_file(h_file);
 +      if (au_test_loopback_kthread()) {
 +              au_warn_loopback(h_file->f_dentry->d_sb);
 +              if (file->f_mapping != h_file->f_mapping) {
@@ -11327,13 +11392,15 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +                      smp_mb(); /* unnecessary? */
 +              }
 +      }
++      di_read_unlock(dentry, AuLock_IR);
++      fi_read_unlock(file);
++
 +      err = vfsub_splice_to(h_file, ppos, pipe, len, flags);
 +      /* todo: necessasry? */
 +      /* file->f_ra = h_file->f_ra; */
++      /* update without lock, I don't think it a problem */
 +      fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
-+
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_read_unlock(file);
++      fput(h_file);
 +
 +out:
 +      si_read_unlock(sb);
@@ -11349,36 +11416,65 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +      struct dentry *dentry;
 +      struct inode *inode;
 +      struct file *h_file;
++      struct super_block *sb;
 +
 +      dentry = file->f_dentry;
++      sb = dentry->d_sb;
 +      inode = dentry->d_inode;
 +      au_mtx_and_read_lock(inode);
++
 +      err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
 +      if (unlikely(err))
 +              goto out;
 +
 +      err = au_ready_to_write(file, -1, &pin);
 +      di_downgrade_lock(dentry, AuLock_IR);
-+      if (unlikely(err))
-+              goto out_unlock;
++      if (unlikely(err)) {
++              di_read_unlock(dentry, AuLock_IR);
++              fi_write_unlock(file);
++              goto out;
++      }
 +
 +      h_file = au_hf_top(file);
++      get_file(h_file);
 +      au_unpin(&pin);
++      di_read_unlock(dentry, AuLock_IR);
++      fi_write_unlock(file);
++
 +      err = vfsub_splice_from(pipe, h_file, ppos, len, flags);
++      ii_write_lock_child(inode);
 +      au_cpup_attr_timesizes(inode);
 +      inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++      ii_write_unlock(inode);
++      fput(h_file);
 +
-+out_unlock:
-+      di_read_unlock(dentry, AuLock_IR);
-+      fi_write_unlock(file);
 +out:
-+      si_read_unlock(inode->i_sb);
++      si_read_unlock(sb);
 +      mutex_unlock(&inode->i_mutex);
 +      return err;
 +}
 +
 +/* ---------------------------------------------------------------------- */
 +
++/*
++ * The locking order around current->mmap_sem.
++ * - in most and regular cases
++ *   file I/O syscall -- aufs_read() or something
++ *    -- si_rwsem for read -- mmap_sem
++ *    (Note that [fdi]i_rwsem are released before mmap_sem).
++ * - in mmap case
++ *   mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem
++ * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for
++ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in
++ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though.
++ * It means that when aufs acquires si_rwsem for write, the process should never
++ * acquire mmap_sem.
++ *
++ * Actually aufs_readdir() holds [fdi]i_rwsem before mmap_sem, but this is not a
++ * problem either since any directory is not able to be mmap-ed.
++ * The similar scenario is applied to aufs_readlink() too.
++ */
++
 +/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */
 +#define AuConv_VM_PROT(f, b)  _calc_vm_trans(f, VM_##b, PROT_##b)
 +
@@ -11413,124 +11509,81 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +              | AuConv_VM_MAP(flags, EXECUTABLE)
 +              | AuConv_VM_MAP(flags, LOCKED);
 +}
-+/*
-+ * This is another ugly approach to keep the lock order, particularly
-+ * mm->mmap_sem and aufs rwsem. The previous approach was reverted and you can
-+ * find it in git-log, if you want.
-+ *
-+ * native readdir: i_mutex, copy_to_user, mmap_sem
-+ * aufs readdir: i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
-+ *
-+ * Before aufs_mmap() mmap_sem is acquired already, but aufs_mmap() has to
-+ * acquire aufs rwsem. It introduces a circular locking dependency.
-+ * To address this problem, aufs_mmap() delegates the part which requires aufs
-+ * rwsem to its internal workqueue.
-+ */
-+
-+struct au_mmap_pre_args {
-+      /* input */
-+      struct file *file;
-+      struct vm_area_struct *vma;
-+
-+      /* output */
-+      int *errp;
-+      struct file *h_file;
-+      struct au_branch *br;
-+};
 +
-+static int au_mmap_pre(struct file *file, struct vm_area_struct *vma,
-+                     struct file **h_file, struct au_branch **br)
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
 +{
 +      int err;
++      unsigned long prot;
 +      aufs_bindex_t bstart;
 +      const unsigned char wlock
-+              = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
++              = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
 +      struct dentry *dentry;
 +      struct super_block *sb;
++      struct file *h_file;
++      struct au_branch *br;
++      struct au_pin pin;
++
++      AuDbgVmRegion(file, vma);
 +
 +      dentry = file->f_dentry;
 +      sb = dentry->d_sb;
++      lockdep_off();
 +      si_read_lock(sb, AuLock_NOPLMW);
 +      err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
 +      if (unlikely(err))
 +              goto out;
 +
 +      if (wlock) {
-+              struct au_pin pin;
-+
 +              err = au_ready_to_write(file, -1, &pin);
 +              di_write_unlock(dentry);
-+              if (unlikely(err))
-+                      goto out_unlock;
++              if (unlikely(err)) {
++                      fi_write_unlock(file);
++                      goto out;
++              }
 +              au_unpin(&pin);
 +      } else
 +              di_write_unlock(dentry);
++
 +      bstart = au_fbstart(file);
-+      *br = au_sbr(sb, bstart);
-+      *h_file = au_hf_top(file);
-+      get_file(*h_file);
++      br = au_sbr(sb, bstart);
++      h_file = au_hf_top(file);
++      get_file(h_file);
 +      au_set_mmapped(file);
-+
-+out_unlock:
 +      fi_write_unlock(file);
-+out:
-+      si_read_unlock(sb);
-+      return err;
-+}
-+
-+static void au_call_mmap_pre(void *args)
-+{
-+      struct au_mmap_pre_args *a = args;
-+      *a->errp = au_mmap_pre(a->file, a->vma, &a->h_file, &a->br);
-+}
-+
-+static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+      int err, wkq_err;
-+      unsigned long prot;
-+      struct au_mmap_pre_args args = {
-+              .file           = file,
-+              .vma            = vma,
-+              .errp           = &err
-+      };
-+
-+      AuDbgVmRegion(file, vma);
-+      wkq_err = au_wkq_wait_pre(au_call_mmap_pre, &args);
-+      if (unlikely(wkq_err))
-+              err = wkq_err;
-+      if (unlikely(err))
-+              goto out;
++      lockdep_on();
 +
-+      au_vm_file_reset(vma, args.h_file);
++      au_vm_file_reset(vma, h_file);
 +      prot = au_prot_conv(vma->vm_flags);
-+      err = security_file_mmap(args.h_file, /*reqprot*/prot, prot,
++      err = security_file_mmap(h_file, /*reqprot*/prot, prot,
 +                               au_flag_conv(vma->vm_flags), vma->vm_start, 0);
-+      if (unlikely(err))
-+              goto out_reset;
-+
-+      err = args.h_file->f_op->mmap(args.h_file, vma);
++      if (!err)
++              err = h_file->f_op->mmap(h_file, vma);
 +      if (unlikely(err))
 +              goto out_reset;
 +
 +      au_vm_prfile_set(vma, file);
-+      vfsub_file_accessed(args.h_file);
 +      /* update without lock, I don't think it a problem */
 +      fsstack_copy_attr_atime(file->f_dentry->d_inode,
-+                              args.h_file->f_dentry->d_inode);
++                              h_file->f_dentry->d_inode);
 +      goto out_fput; /* success */
 +
 +out_reset:
 +      au_unset_mmapped(file);
 +      au_vm_file_reset(vma, file);
 +out_fput:
-+      fput(args.h_file);
++      fput(h_file);
++      lockdep_off();
 +out:
++      si_read_unlock(sb);
++      lockdep_on();
++      AuTraceErr(err);
 +      return err;
 +}
 +
 +/* ---------------------------------------------------------------------- */
 +
-+static int aufs_fsync_nondir(struct file *file, int datasync)
++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end,
++                           int datasync)
 +{
 +      int err;
 +      struct au_pin pin;
@@ -11541,14 +11594,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +
 +      dentry = file->f_dentry;
 +      inode = dentry->d_inode;
-+      IMustLock(file->f_mapping->host);
-+      if (inode != file->f_mapping->host) {
-+              mutex_unlock(&file->f_mapping->host->i_mutex);
-+              mutex_lock(&inode->i_mutex);
-+      }
-+      IMustLock(inode);
-+
 +      sb = dentry->d_sb;
++      mutex_lock(&inode->i_mutex);
 +      err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
 +      if (unlikely(err))
 +              goto out;
@@ -11577,10 +11624,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +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);
-+      }
++      mutex_unlock(&inode->i_mutex);
 +      return err;
 +}
 +
@@ -11715,10 +11759,10 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +};
 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    2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,299 @@
++++ linux/fs/aufs/f_op_sp.c    2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,298 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -11741,7 +11785,6 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 + * their file I/O is handled out of aufs.
 + */
 +
-+#include <linux/fs_stack.h>
 +#include "aufs.h"
 +
 +static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov,
@@ -12018,10 +12061,10 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 +}
 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     2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,497 @@
++++ linux/fs/aufs/fstype.h     2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,496 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -12050,7 +12093,6 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 +#include <linux/fs.h>
 +#include <linux/magic.h>
 +#include <linux/romfs_fs.h>
-+#include <linux/aufs_type.h>
 +
 +static inline int au_test_aufs(struct super_block *sb)
 +{
@@ -12519,10 +12561,10 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 +#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  2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,247 @@
++++ linux/fs/aufs/hfsnotify.c  2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,260 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -12549,15 +12591,17 @@ 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 DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0);
 +
 +static void au_hfsn_free_mark(struct fsnotify_mark *mark)
 +{
 +      struct au_hnotify *hn = container_of(mark, struct au_hnotify,
 +                                           hn_mark);
 +      AuDbg("here\n");
-+      hn->hn_mark_dead = 1;
-+      smp_mb();
-+      wake_up_all(&au_hfsn_wq);
++      au_cache_free_hnotify(hn);
++      smp_mb__before_atomic_dec();
++      atomic64_dec(&au_hfsn_ifree);
++      wake_up(&au_hfsn_wq);
 +}
 +
 +static int au_hfsn_alloc(struct au_hinode *hinode)
@@ -12572,7 +12616,6 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +      sb = hn->hn_aufs_inode->i_sb;
 +      bindex = au_br_index(sb, hinode->hi_id);
 +      br = au_sbr(sb, bindex);
-+      hn->hn_mark_dead = 0;
 +      mark = &hn->hn_mark;
 +      fsnotify_init_mark(mark, au_hfsn_free_mark);
 +      mark->mask = AuHfsnMask;
@@ -12584,18 +12627,20 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +                               /*mnt*/NULL, /*allow_dups*/1);
 +}
 +
-+static void au_hfsn_free(struct au_hinode *hinode)
++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn)
 +{
-+      struct au_hnotify *hn;
 +      struct fsnotify_mark *mark;
++      unsigned long long ull;
++
++      ull = atomic64_inc_return(&au_hfsn_ifree);
++      BUG_ON(!ull);
 +
-+      hn = hinode->hi_notify;
 +      mark = &hn->hn_mark;
 +      fsnotify_destroy_mark(mark);
 +      fsnotify_put_mark(mark);
 +
-+      /* TODO: bad approach */
-+      wait_event(au_hfsn_wq, hn->hn_mark_dead);
++      /* free hn by myself */
++      return 0;
 +}
 +
 +/* ---------------------------------------------------------------------- */
@@ -12759,21 +12804,31 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +      return err;
 +}
 +
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_fin(void)
++{
++      AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree));
++      wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree));
++}
++
 +const struct au_hnotify_op au_hnotify_op = {
 +      .ctl            = au_hfsn_ctl,
 +      .alloc          = au_hfsn_alloc,
 +      .free           = au_hfsn_free,
 +
++      .fin            = au_hfsn_fin,
++
 +      .reset_br       = au_hfsn_reset_br,
 +      .fin_br         = au_hfsn_fin_br,
 +      .init_br        = au_hfsn_init_br
 +};
 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    2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,58 @@
++++ linux/fs/aufs/hfsplus.c    2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,57 @@
 +/*
-+ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ * Copyright (C) 2010-2012 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
@@ -12800,7 +12855,6 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c
 + * and au_h_open_post() after releasing it.
 + */
 +
-+#include <linux/file.h>
 +#include "aufs.h"
 +
 +struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
@@ -12832,10 +12886,10 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c
 +}
 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    2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/hnotify.c    2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,712 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -12894,9 +12948,9 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +
 +      hn = hinode->hi_notify;
 +      if (hn) {
-+              au_hnotify_op.free(hinode);
-+              au_cache_free_hnotify(hn);
 +              hinode->hi_notify = NULL;
++              if (au_hnotify_op.free(hinode, hn))
++                      au_cache_free_hnotify(hn);
 +      }
 +}
 +
@@ -13548,10 +13602,10 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/iinfo.c      2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,264 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -13816,10 +13870,10 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/inode.c      2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,471 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -14291,10 +14345,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,556 @@
++++ linux/fs/aufs/inode.h      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,560 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -14320,9 +14374,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/fs.h>
 +#include <linux/fsnotify.h>
-+#include <linux/aufs_type.h>
 +#include "rwsem.h"
 +
 +struct vfsmount;
@@ -14332,7 +14384,6 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +#ifdef CONFIG_AUFS_HFSNOTIFY
 +      /* never use fsnotify_add_vfsmount_mark() */
 +      struct fsnotify_mark            hn_mark;
-+      int                             hn_mark_dead;
 +#endif
 +      struct inode                    *hn_aufs_inode; /* no get/put */
 +#endif
@@ -14455,13 +14506,14 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +/* i_op_add.c */
 +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
 +             struct dentry *h_parent, int isdir);
-+int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++             dev_t dev);
 +int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
-+int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 +              struct nameidata *nd);
 +int aufs_link(struct dentry *src_dentry, struct inode *dir,
 +            struct dentry *dentry);
-+int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 +
 +/* i_op_del.c */
 +int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
@@ -14752,7 +14804,13 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +struct au_hnotify_op {
 +      void (*ctl)(struct au_hinode *hinode, int do_set);
 +      int (*alloc)(struct au_hinode *hinode);
-+      void (*free)(struct au_hinode *hinode);
++
++      /*
++       * if it returns true, the the caller should free hinode->hi_notify,
++       * otherwise ->free() frees it.
++       */
++      int (*free)(struct au_hinode *hinode,
++                  struct au_hnotify *hn) __must_check;
 +
 +      void (*fin)(void);
 +      int (*init)(void);
@@ -14851,10 +14909,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +#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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,158 @@
++++ linux/fs/aufs/ioctl.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,196 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -14877,49 +14935,86 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 + * assist the pathconf(3) wrapper library.
 + */
 +
-+#include <linux/file.h>
 +#include "aufs.h"
 +
-+static int au_wbr_fd(struct path *path)
++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg)
 +{
 +      int err, fd;
 +      aufs_bindex_t wbi, bindex, bend;
 +      struct file *h_file;
 +      struct super_block *sb;
 +      struct dentry *root;
-+      struct au_branch *wbr;
++      struct au_branch *br;
++      struct aufs_wbr_fd wbrfd = {
++              .oflags = au_dir_roflags,
++              .brid   = -1
++      };
++      const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY
++              | O_NOATIME | O_CLOEXEC;
 +
-+      err = get_unused_fd();
-+      if (unlikely(err < 0))
++      AuDebugOn(wbrfd.oflags & ~valid);
++
++      if (arg) {
++              err = copy_from_user(&wbrfd, arg, sizeof(wbrfd));
++              if (unlikely(err)) {
++                      err = -EFAULT;
++                      goto out;
++              }
++
++              err = -EINVAL;
++              AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid);
++              wbrfd.oflags |= au_dir_roflags;
++              AuDbg("0%o\n", wbrfd.oflags);
++              if (unlikely(wbrfd.oflags & ~valid))
++                      goto out;
++      }
++
++      fd = get_unused_fd();
++      err = fd;
++      if (unlikely(fd < 0))
 +              goto out;
-+      fd = err;
 +
++      h_file = ERR_PTR(-EINVAL);
 +      wbi = 0;
++      br = NULL;
 +      sb = path->dentry->d_sb;
 +      root = sb->s_root;
 +      aufs_read_lock(root, AuLock_IR);
-+      wbr = au_sbr(sb, wbi);
-+      if (!(path->mnt->mnt_flags & MNT_READONLY)
-+          && !au_br_writable(wbr->br_perm)) {
-+              bend = au_sbend(sb);
-+              for (bindex = 1; bindex <= bend; bindex++) {
-+                      wbr = au_sbr(sb, bindex);
-+                      if (au_br_writable(wbr->br_perm)) {
++      bend = au_sbend(sb);
++      if (wbrfd.brid >= 0) {
++              wbi = au_br_index(sb, wbrfd.brid);
++              if (unlikely(wbi < 0 || wbi > bend))
++                      goto out_unlock;
++      }
++
++      h_file = ERR_PTR(-ENOENT);
++      br = au_sbr(sb, wbi);
++      if (!au_br_writable(br->br_perm)) {
++              if (arg)
++                      goto out_unlock;
++
++              bindex = wbi + 1;
++              wbi = -1;
++              for (; bindex <= bend; bindex++) {
++                      br = au_sbr(sb, bindex);
++                      if (au_br_writable(br->br_perm)) {
 +                              wbi = bindex;
++                              br = au_sbr(sb, wbi);
 +                              break;
 +                      }
 +              }
-+              wbr = au_sbr(sb, wbi);
 +      }
 +      AuDbg("wbi %d\n", wbi);
-+      h_file = au_h_open(root, wbi, O_RDONLY | O_DIRECTORY | O_LARGEFILE,
-+                         NULL);
++      if (wbi >= 0)
++              h_file = au_h_open(root, wbi, wbrfd.oflags, NULL);
++
++out_unlock:
 +      aufs_read_unlock(root, AuLock_IR);
 +      err = PTR_ERR(h_file);
 +      if (IS_ERR(h_file))
 +              goto out_fd;
 +
-+      atomic_dec(&wbr->br_count); /* cf. au_h_open() */
++      atomic_dec(&br->br_count); /* cf. au_h_open() */
 +      fd_install(fd, h_file);
 +      err = fd;
 +      goto out; /* success */
@@ -14927,6 +15022,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +out_fd:
 +      put_unused_fd(fd);
 +out:
++      AuTraceErr(err);
 +      return err;
 +}
 +
@@ -14943,7 +15039,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +              break;
 +
 +      case AUFS_CTL_WBR_FD:
-+              err = au_wbr_fd(&file->f_path);
++              err = au_wbr_fd(&file->f_path, (void __user *)arg);
 +              break;
 +
 +      case AUFS_CTL_IBUSY:
@@ -14966,7 +15062,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +
 +      switch (cmd) {
 +      case AUFS_CTL_WBR_FD:
-+              err = au_wbr_fd(&file->f_path);
++              err = au_wbr_fd(&file->f_path, (void __user *)arg);
 +              break;
 +
 +      default:
@@ -15013,10 +15109,10 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +#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   2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,711 @@
++++ linux/fs/aufs/i_op_add.c   2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,712 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -15232,14 +15328,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      int type;
 +      union {
 +              struct {
-+                      int mode;
++                      umode_t mode;
 +                      struct nameidata *nd;
 +              } c;
 +              struct {
 +                      const char *symname;
 +              } s;
 +              struct {
-+                      int mode;
++                      umode_t mode;
 +                      dev_t dev;
 +              } m;
 +      } u;
@@ -15326,7 +15422,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      return err;
 +}
 +
-+int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++             dev_t dev)
 +{
 +      struct simple_arg arg = {
 +              .type = Mknod,
@@ -15347,7 +15444,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      return add_simple(dir, dentry, &arg);
 +}
 +
-+int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 +              struct nameidata *nd)
 +{
 +      struct simple_arg arg = {
@@ -15395,7 +15492,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +              err = PTR_ERR(h_file);
 +              h_file = NULL;
 +      } else
-+              err = au_sio_cpup_simple(src_dentry, a->bdst, a->bsrc,
++              err = au_sio_cpup_simple(src_dentry, a->bdst, -1,
 +                                       AuCpup_DTIME /* | AuCpup_KEEPLINO */);
 +      mutex_unlock(h_mtx);
 +      au_h_open_post(src_dentry, a->bsrc, h_file);
@@ -15619,7 +15716,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      return err;
 +}
 +
-+int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 +{
 +      int err, rerr;
 +      aufs_bindex_t bindex;
@@ -15728,10 +15825,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +}
 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       2011-08-24 13:30:24.731313534 +0200
-@@ -0,0 +1,976 @@
++++ linux/fs/aufs/i_op.c       2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,993 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -15757,10 +15854,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +#include <linux/mm.h>
 +#include <linux/namei.h>
 +#include <linux/security.h>
-+#include <linux/uaccess.h>
 +#include "aufs.h"
 +
-+static int h_permission(struct inode *h_inode, int mask, unsigned int flags,
++static int h_permission(struct inode *h_inode, int mask,
 +                      struct vfsmount *h_mnt, int brperm)
 +{
 +      int err;
@@ -15784,11 +15880,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              && write_mask && !(mask & MAY_READ))
 +          || !h_inode->i_op->permission) {
 +              /* AuLabel(generic_permission); */
-+              err = generic_permission(h_inode, mask, flags,
-+                                       h_inode->i_op->check_acl);
++              err = generic_permission(h_inode, mask);
 +      } else {
 +              /* AuLabel(h_inode->permission); */
-+              err = h_inode->i_op->permission(h_inode, mask, flags);
++              err = h_inode->i_op->permission(h_inode, mask);
 +              AuTraceErr(err);
 +      }
 +
@@ -15814,7 +15909,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      return err;
 +}
 +
-+static int aufs_permission(struct inode *inode, int mask, unsigned int flags)
++static int aufs_permission(struct inode *inode, int mask)
 +{
 +      int err;
 +      aufs_bindex_t bindex, bend;
@@ -15825,7 +15920,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      struct au_branch *br;
 +
 +      /* todo: support rcu-walk? */
-+      if (flags & IPERM_FLAG_RCU)
++      if (mask & MAY_NOT_BLOCK)
 +              return -ECHILD;
 +
 +      sb = inode->i_sb;
@@ -15848,8 +15943,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              err = 0;
 +              bindex = au_ibstart(inode);
 +              br = au_sbr(sb, bindex);
-+              err = h_permission(h_inode, mask, flags, br->br_mnt,
-+                                 br->br_perm);
++              err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
 +              if (write_mask
 +                  && !err
 +                  && !special_file(h_inode->i_mode)) {
@@ -15875,7 +15969,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +                              break;
 +
 +                      br = au_sbr(sb, bindex);
-+                      err = h_permission(h_inode, mask, flags, br->br_mnt,
++                      err = h_permission(h_inode, mask, br->br_mnt,
 +                                         br->br_perm);
 +              }
 +      }
@@ -15894,7 +15988,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      struct dentry *ret, *parent;
 +      struct inode *inode;
 +      struct super_block *sb;
-+      int err, npositive;
++      int err, npositive, lc_idx;
 +
 +      IMustLock(dir);
 +
@@ -15912,6 +16006,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      if (unlikely(err))
 +              goto out_si;
 +
++      inode = NULL;
 +      npositive = 0; /* suppress a warning */
 +      parent = dentry->d_parent; /* dir inode is locked */
 +      di_read_lock_parent(parent, AuLock_IR);
@@ -15928,22 +16023,37 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      if (unlikely(err < 0))
 +              goto out_unlock;
 +
-+      inode = NULL;
 +      if (npositive) {
 +              inode = au_new_inode(dentry, /*must_new*/0);
 +              ret = (void *)inode;
 +      }
-+      if (IS_ERR(inode))
++      if (IS_ERR(inode)) {
++              inode = NULL;
 +              goto out_unlock;
++      }
 +
 +      ret = d_splice_alias(inode, dentry);
 +      if (unlikely(IS_ERR(ret) && inode)) {
 +              ii_write_unlock(inode);
++              lc_idx = AuLcNonDir_IIINFO;
++              if (S_ISLNK(inode->i_mode))
++                      lc_idx = AuLcSymlink_IIINFO;
++              else if (S_ISDIR(inode->i_mode))
++                      lc_idx = AuLcDir_IIINFO;
++              au_rw_class(&au_ii(inode)->ii_rwsem, au_lc_key + lc_idx);
 +              iput(inode);
 +      }
 +
 +out_unlock:
 +      di_write_unlock(dentry);
++      if (unlikely(IS_ERR(ret) && inode)) {
++              lc_idx = AuLcNonDir_DIINFO;
++              if (S_ISLNK(inode->i_mode))
++                      lc_idx = AuLcSymlink_DIINFO;
++              else if (S_ISDIR(inode->i_mode))
++                      lc_idx = AuLcDir_DIINFO;
++              au_rw_class(&au_di(dentry)->di_rwsem, au_lc_key + lc_idx);
++      }
 +out_si:
 +      si_read_unlock(sb);
 +out:
@@ -16417,8 +16527,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
 +      if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
 +          == (ATTR_MODE | ATTR_CTIME)) {
-+              err = security_path_chmod(a->h_path.dentry, a->h_path.mnt,
-+                                        ia->ia_mode);
++              err = security_path_chmod(&a->h_path, ia->ia_mode);
 +              if (unlikely(err))
 +                      goto out_unlock;
 +      } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
@@ -16470,6 +16579,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +static void au_refresh_iattr(struct inode *inode, struct kstat *st,
 +                           unsigned int nlink)
 +{
++      unsigned int n;
++
 +      inode->i_mode = st->mode;
 +      inode->i_uid = st->uid;
 +      inode->i_gid = st->gid;
@@ -16479,8 +16590,11 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +      au_cpup_attr_nlink(inode, /*force*/0);
 +      if (S_ISDIR(inode->i_mode)) {
-+              inode->i_nlink -= nlink;
-+              inode->i_nlink += st->nlink;
++              n = inode->i_nlink;
++              n -= nlink;
++              n += st->nlink;
++              /* 0 can happen */
++              set_nlink(inode, n);
 +      }
 +
 +      spin_lock(&inode->i_lock);
@@ -16708,10 +16822,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +};
 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   2011-08-24 13:30:24.731313534 +0200
++++ linux/fs/aufs/i_op_del.c   2012-05-22 09:06:08.867458905 +0200
 @@ -0,0 +1,478 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -17190,10 +17304,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +}
 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   2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,1017 @@
++++ linux/fs/aufs/i_op_ren.c   2012-05-22 09:06:08.867458905 +0200
+@@ -0,0 +1,1026 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -18101,6 +18215,15 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +      } else if (unlikely(d_unhashed(a->dst_dentry)))
 +              goto out_unlock;
 +
++      /*
++       * is it possible?
++       * yes, it happend (in linux-3.3-rcN) but I don't know why.
++       * there may exist a problem somewhere else.
++       */
++      err = -EINVAL;
++      if (unlikely(a->dst_parent->d_inode == a->src_dentry->d_inode))
++              goto out_unlock;
++
 +      au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
 +      di_write_lock_parent(a->dst_parent);
 +
@@ -18211,7 +18334,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +}
 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      2011-08-24 13:30:24.727980364 +0200
++++ linux/fs/aufs/Kconfig      2012-05-22 09:06:08.864125478 +0200
 @@ -0,0 +1,203 @@
 +config AUFS_FS
 +      tristate "Aufs (Advanced multi layered unification filesystem) support"
@@ -18418,10 +18541,10 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig
 +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       2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/loop.c       2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,133 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -18555,10 +18678,10 @@ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c
 +}
 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       2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/loop.h       2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,50 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -18609,7 +18732,7 @@ diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h
 +#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     2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/magic.mk     2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,54 @@
 +
 +# defined in ${srctree}/fs/fuse/inode.c
@@ -18667,8 +18790,8 @@ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk
 +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     2011-08-24 13:30:24.727980364 +0200
-@@ -0,0 +1,38 @@
++++ linux/fs/aufs/Makefile     2012-05-22 09:06:08.864125478 +0200
+@@ -0,0 +1,42 @@
 +
 +include ${src}/magic.mk
 +ifeq (${CONFIG_AUFS_FS},m)
@@ -18679,8 +18802,12 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +# cf. include/linux/kernel.h
 +# enable pr_debug
 +ccflags-y += -DDEBUG
-+# sparse doesn't allow spaces
-+ccflags-y += -D'pr_fmt(fmt)=AUFS_NAME"\040%s:%d:%s[%d]:\040"fmt,__func__,__LINE__,current->comm,current->pid'
++# sparse requires the full pathname
++ifdef M
++ccflags-y += -include ${M}/../../include/linux/aufs_type.h
++else
++ccflags-y += -include ${srctree}/include/linux/aufs_type.h
++endif
 +
 +obj-$(CONFIG_AUFS_FS) += aufs.o
 +aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
@@ -18709,10 +18836,10 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +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     2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,189 @@
++++ linux/fs/aufs/module.c     2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,196 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -18778,8 +18905,9 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
 +{
 +      int i;
 +
-+      /* including AuCache_HNOTIFY */
-+      for (i = 0; i < AuCache_Last; i++)
++      /* excluding AuCache_HNOTIFY */
++      BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
++      for (i = 0; i < AuCache_HNOTIFY; i++)
 +              if (au_cachep[i]) {
 +                      kmem_cache_destroy(au_cachep[i]);
 +                      au_cachep[i] = NULL;
@@ -18791,9 +18919,15 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
 +int au_dir_roflags;
 +
 +#ifdef CONFIG_AUFS_SBILIST
++/*
++ * iterate_supers_type() doesn't protect us from
++ * remounting (branch management)
++ */
 +struct au_splhead au_sbilist;
 +#endif
 +
++struct lock_class_key au_lc_key[AuLcKey_Last];
++
 +/*
 + * functions for module interface.
 + */
@@ -18902,10 +19036,10 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
 +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     2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,91 @@
++++ linux/fs/aufs/module.h     2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,105 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -18943,6 +19077,22 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 +
 +extern int au_dir_roflags;
 +
++enum {
++      AuLcNonDir_FIINFO,
++      AuLcNonDir_DIINFO,
++      AuLcNonDir_IIINFO,
++
++      AuLcDir_FIINFO,
++      AuLcDir_DIINFO,
++      AuLcDir_IIINFO,
++
++      AuLcSymlink_DIINFO,
++      AuLcSymlink_IIINFO,
++
++      AuLcKey_Last
++};
++extern struct lock_class_key au_lc_key[AuLcKey_Last];
++
 +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);
 +
@@ -18964,9 +19114,7 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 +      AuCache_FINFO,
 +      AuCache_VDIR,
 +      AuCache_DEHSTR,
-+#ifdef CONFIG_AUFS_HNOTIFY
-+      AuCache_HNOTIFY,
-+#endif
++      AuCache_HNOTIFY, /* must be last */
 +      AuCache_Last
 +};
 +
@@ -18997,10 +19145,10 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 +#endif /* __AUFS_MODULE_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       2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,1595 @@
++++ linux/fs/aufs/opts.c       2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,1677 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -19021,8 +19169,6 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 + * mount options/flags
 + */
 +
-+#include <linux/file.h>
-+#include <linux/jiffies.h>
 +#include <linux/namei.h>
 +#include <linux/types.h> /* a distribution requires */
 +#include <linux/parser.h>
@@ -19182,31 +19328,127 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +
 +/* ---------------------------------------------------------------------- */
 +
-+static match_table_t brperms = {
++static match_table_t brperm = {
 +      {AuBrPerm_RO, AUFS_BRPERM_RO},
 +      {AuBrPerm_RR, AUFS_BRPERM_RR},
 +      {AuBrPerm_RW, AUFS_BRPERM_RW},
++      {0, NULL}
++};
 +
-+      {AuBrPerm_ROWH, AUFS_BRPERM_ROWH},
-+      {AuBrPerm_RRWH, AUFS_BRPERM_RRWH},
-+      {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH},
++static match_table_t brrattr = {
++      {AuBrRAttr_WH, AUFS_BRRATTR_WH},
++      {0, NULL}
++};
 +
-+      {AuBrPerm_ROWH, "nfsro"},
-+      {AuBrPerm_RO, NULL}
++static match_table_t brwattr = {
++      {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH},
++      {0, NULL}
 +};
 +
++#define AuBrStr_LONGEST       AUFS_BRPERM_RW "+" AUFS_BRWATTR_NLWH
++
++static int br_attr_val(char *str, match_table_t table, substring_t args[])
++{
++      int attr, v;
++      char *p;
++
++      attr = 0;
++      do {
++              p = strchr(str, '+');
++              if (p)
++                      *p = 0;
++              v = match_token(str, table, args);
++              if (v)
++                      attr |= v;
++              else {
++                      if (p)
++                              *p = '+';
++                      pr_warning("ignored branch attribute %s\n", str);
++                      break;
++              }
++              if (p)
++                      str = p + 1;
++      } while (p);
++
++      return attr;
++}
++
 +static int noinline_for_stack br_perm_val(char *perm)
 +{
 +      int val;
++      char *p;
 +      substring_t args[MAX_OPT_ARGS];
 +
-+      val = match_token(perm, brperms, args);
++      p = strchr(perm, '+');
++      if (p)
++              *p = 0;
++      val = match_token(perm, brperm, args);
++      if (!val) {
++              if (p)
++                      *p = '+';
++              pr_warning("ignored branch permission %s\n", perm);
++              val = AuBrPerm_RO;
++              goto out;
++      }
++      if (!p)
++              goto out;
++
++      switch (val) {
++      case AuBrPerm_RO:
++      case AuBrPerm_RR:
++              val |= br_attr_val(p + 1, brrattr, args);
++              break;
++      case AuBrPerm_RW:
++              val |= br_attr_val(p + 1, brwattr, args);
++              break;
++      }
++
++out:
 +      return val;
 +}
 +
-+const char *au_optstr_br_perm(int brperm)
++/* Caller should free the return value */
++char *au_optstr_br_perm(int brperm)
 +{
-+      return au_parser_pattern(brperm, (void *)brperms);
++      char *p, a[sizeof(AuBrStr_LONGEST)];
++      int sz;
++
++#define SetPerm(str) do {                     \
++              sz = sizeof(str);               \
++              memcpy(a, str, sz);             \
++              p = a + sz - 1;                 \
++      } while (0)
++
++#define AppendAttr(flag, str) do {                    \
++              if (brperm & flag) {            \
++                      sz = sizeof(str);       \
++                      *p++ = '+';             \
++                      memcpy(p, str, sz);     \
++                      p += sz - 1;            \
++              }                               \
++      } while (0)
++
++      switch (brperm & AuBrPerm_Mask) {
++      case AuBrPerm_RO:
++              SetPerm(AUFS_BRPERM_RO);
++              break;
++      case AuBrPerm_RR:
++              SetPerm(AUFS_BRPERM_RR);
++              break;
++      case AuBrPerm_RW:
++              SetPerm(AUFS_BRPERM_RW);
++              break;
++      default:
++              AuDebugOn(1);
++      }
++
++      AppendAttr(AuBrRAttr_WH, AUFS_BRRATTR_WH);
++      AppendAttr(AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH);
++
++      AuDebugOn(strlen(a) >= sizeof(a));
++      return kstrdup(a, GFP_NOFS);
++#undef SetPerm
++#undef AppendAttr
 +}
 +
 +/* ---------------------------------------------------------------------- */
@@ -19258,7 +19500,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +/*
 + * cf. linux/lib/parser.c and cmdline.c
 + * gave up calling memparse() since it uses simple_strtoull() instead of
-+ * strict_...().
++ * kstrto...().
 + */
 +static int noinline_for_stack
 +au_match_ull(substring_t *s, unsigned long long *result)
@@ -19272,7 +19514,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      if (len + 1 <= sizeof(a)) {
 +              memcpy(a, s->from, len);
 +              a[len] = '\0';
-+              err = strict_strtoull(a, 0, result);
++              err = kstrtoull(a, 0, result);
 +      }
 +      return err;
 +}
@@ -19597,7 +19839,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      char *p;
 +
 +      add->bindex = bindex;
-+      add->perm = AuBrPerm_Last;
++      add->perm = AuBrPerm_RO;
 +      add->pathname = opt_str;
 +      p = strchr(opt_str, '=');
 +      if (p) {
@@ -20390,19 +20632,13 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              if (wbr)
 +                      wbr_wh_read_lock(wbr);
 +
-+              switch (br->br_perm) {
-+              case AuBrPerm_RO:
-+              case AuBrPerm_ROWH:
-+              case AuBrPerm_RR:
-+              case AuBrPerm_RRWH:
++              if (!au_br_writable(br->br_perm)) {
 +                      do_free = !!wbr;
 +                      skip = (!wbr
 +                              || (!wbr->wbr_whbase
 +                                  && !wbr->wbr_plink
 +                                  && !wbr->wbr_orph));
-+                      break;
-+
-+              case AuBrPerm_RWNoLinkWH:
++              } else if (!au_br_wh_linkable(br->br_perm)) {
 +                      /* skip = (!br->br_whbase && !br->br_orph); */
 +                      skip = (!wbr || !wbr->wbr_whbase);
 +                      if (skip && wbr) {
@@ -20411,9 +20647,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +                              else
 +                                      skip = !wbr->wbr_plink;
 +                      }
-+                      break;
-+
-+              case AuBrPerm_RW:
++              } else {
 +                      /* skip = (br->br_whbase && br->br_ohph); */
 +                      skip = (wbr && wbr->wbr_whbase);
 +                      if (skip) {
@@ -20422,10 +20656,6 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +                              else
 +                                      skip = !wbr->wbr_plink;
 +                      }
-+                      break;
-+
-+              default:
-+                      BUG();
 +              }
 +              if (wbr)
 +                      wbr_wh_read_unlock(wbr);
@@ -20596,10 +20826,10 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +}
 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       2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,210 @@
++++ linux/fs/aufs/opts.h       2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,209 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -20626,7 +20856,6 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
 +#ifdef __KERNEL__
 +
 +#include <linux/path.h>
-+#include <linux/aufs_type.h>
 +
 +struct file;
 +struct super_block;
@@ -20790,7 +21019,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
 +
 +/* ---------------------------------------------------------------------- */
 +
-+const char *au_optstr_br_perm(int brperm);
++char *au_optstr_br_perm(int brperm);
 +const char *au_optstr_udba(int udba);
 +const char *au_optstr_wbr_copyup(int wbr_copyup);
 +const char *au_optstr_wbr_create(int wbr_create);
@@ -20810,10 +21039,10 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
 +#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      2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/plink.c      2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,515 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -21329,10 +21558,10 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
 +}
 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       2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/poll.c       2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,56 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -21389,10 +21618,10 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c
 +}
 diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c
 --- /usr/share/empty/fs/aufs/procfs.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/procfs.c     2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/procfs.c     2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,170 @@
 +/*
-+ * Copyright (C) 2010-2011 Junjiro R. Okajima
++ * Copyright (C) 2010-2012 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
@@ -21507,7 +21736,7 @@ diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c
 +      } else if (unlikely(strncmp("si=", buf, 3)))
 +              goto out;
 +
-+      err = strict_strtoul(buf + 3, 16, &id);
++      err = kstrtoul(buf + 3, 16, &id);
 +      if (unlikely(err))
 +              goto out;
 +
@@ -21563,10 +21792,10 @@ diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c
 +}
 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        2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,383 @@
++++ linux/fs/aufs/rdu.c        2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,384 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -21590,8 +21819,6 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
 +#include <linux/compat.h>
 +#include <linux/fs_stack.h>
 +#include <linux/security.h>
-+#include <linux/uaccess.h>
-+#include <linux/aufs_type.h>
 +#include "aufs.h"
 +
 +/* bits for struct aufs_rdu.flags */
@@ -21633,6 +21860,7 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
 +              if (unlikely(nlen > AUFS_MAX_NAMELEN))
 +                      ent.type = DT_UNKNOWN;
 +
++              /* unnecessary to support mmap_sem since this is a dir */
 +              err = -EFAULT;
 +              if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
 +                      goto out;
@@ -21663,6 +21891,7 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
 +      loff_t offset;
 +      struct au_rdu_cookie *cookie = &arg->rdu->cookie;
 +
++      /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */
 +      offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
 +      err = offset;
 +      if (unlikely(offset != cookie->h_pos))
@@ -21806,6 +22035,7 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
 +      sb = file->f_dentry->d_sb;
 +      si_read_lock(sb, AuLock_FLUSH);
 +      while (nent-- > 0) {
++              /* unnecessary to support mmap_sem since this is a dir */
 +              err = copy_from_user(&ent, u->e, sizeof(ent));
 +              if (!err)
 +                      err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
@@ -21950,10 +22180,10 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c
 +#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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,189 @@
++++ linux/fs/aufs/rwsem.h      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,188 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -21979,7 +22209,6 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/rwsem.h>
 +#include "debug.h"
 +
 +struct au_rwsem {
@@ -22143,10 +22372,10 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h
 +#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     2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,344 @@
++++ linux/fs/aufs/sbinfo.c     2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,343 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -22167,7 +22396,6 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
 + * superblock private data
 + */
 +
-+#include <linux/jiffies.h>
 +#include "aufs.h"
 +
 +/*
@@ -22491,10 +22719,10 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
 +}
 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        2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,66 @@
++++ linux/fs/aufs/spl.h        2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,62 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -22520,10 +22748,6 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+#include <linux/rculist.h>
-+
 +struct au_splhead {
 +      spinlock_t              spin;
 +      struct list_head        head;
@@ -22561,10 +22785,10 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
 +#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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,930 @@
++++ linux/fs/aufs/super.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,962 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -22585,8 +22809,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 + * mount and super_block operations
 + */
 +
-+#include <linux/buffer_head.h>
-+#include <linux/jiffies.h>
++#include <linux/mm.h>
 +#include <linux/module.h>
 +#include <linux/seq_file.h>
 +#include <linux/statfs.h>
@@ -22663,6 +22886,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      struct path path;
 +      struct au_hdentry *hdp;
 +      struct au_branch *br;
++      char *perm;
 +
 +      err = 0;
 +      bend = au_sbend(sb);
@@ -22672,9 +22896,16 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +              path.mnt = br->br_mnt;
 +              path.dentry = hdp[bindex].hd_dentry;
 +              err = au_seq_path(seq, &path);
-+              if (err > 0)
-+                      err = seq_printf(seq, "=%s",
-+                                       au_optstr_br_perm(br->br_perm));
++              if (err > 0) {
++                      perm = au_optstr_br_perm(br->br_perm);
++                      if (perm) {
++                              err = seq_printf(seq, "=%s", perm);
++                              kfree(perm);
++                              if (err == -1)
++                                      err = -E2BIG;
++                      } else
++                              err = -ENOMEM;
++              }
 +              if (!err && bindex != bend)
 +                      err = seq_putc(seq, ':');
 +      }
@@ -22721,7 +22952,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      }
 +}
 +
-+static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt)
++static int au_show_xino(struct seq_file *seq, struct super_block *sb)
 +{
 +#ifdef CONFIG_SYSFS
 +      return 0;
@@ -22729,7 +22960,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      int err;
 +      const int len = sizeof(AUFS_XINO_FNAME) - 1;
 +      aufs_bindex_t bindex, brid;
-+      struct super_block *sb;
 +      struct qstr *name;
 +      struct file *f;
 +      struct dentry *d, *h_root;
@@ -22738,7 +22968,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      AuRwMustAnyLock(&sbinfo->si_rwsem);
 +
 +      err = 0;
-+      sb = mnt->mnt_sb;
 +      f = au_sbi(sb)->si_xib;
 +      if (!f)
 +              goto out;
@@ -22768,7 +22997,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +}
 +
 +/* seq_file will re-call me in case of too long string */
-+static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
++static int aufs_show_options(struct seq_file *m, struct dentry *dentry)
 +{
 +      int err;
 +      unsigned int mnt_flags, v;
@@ -22793,14 +23022,14 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +} while (0)
 +
 +      /* lock free root dinfo */
-+      sb = mnt->mnt_sb;
++      sb = dentry->d_sb;
 +      si_noflush_read_lock(sb);
 +      sbinfo = au_sbi(sb);
 +      seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
 +
 +      mnt_flags = au_mntflags(sb);
 +      if (au_opt_test(mnt_flags, XINO)) {
-+              err = au_show_xino(m, mnt);
++              err = au_show_xino(m, sb);
 +              if (unlikely(err))
 +                      goto out;
 +      } else
@@ -22863,7 +23092,18 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +
 +      old = a;
 +      a += b;
-+      if (old < a)
++      if (old <= a)
++              return a;
++      return ULLONG_MAX;
++}
++
++static u64 au_mul_till_max(u64 a, long mul)
++{
++      u64 old;
++
++      old = a;
++      a *= mul;
++      if (old <= a)
 +              return a;
 +      return ULLONG_MAX;
 +}
@@ -22871,25 +23111,26 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
 +{
 +      int err;
++      long bsize, factor;
 +      u64 blocks, bfree, bavail, files, ffree;
 +      aufs_bindex_t bend, bindex, i;
 +      unsigned char shared;
 +      struct path h_path;
 +      struct super_block *h_sb;
 +
++      err = 0;
++      bsize = LONG_MAX;
++      files = 0;
++      ffree = 0;
 +      blocks = 0;
 +      bfree = 0;
 +      bavail = 0;
-+      files = 0;
-+      ffree = 0;
-+
-+      err = 0;
 +      bend = au_sbend(sb);
-+      for (bindex = bend; bindex >= 0; bindex--) {
++      for (bindex = 0; bindex <= bend; bindex++) {
 +              h_path.mnt = au_sbr_mnt(sb, bindex);
 +              h_sb = h_path.mnt->mnt_sb;
 +              shared = 0;
-+              for (i = bindex + 1; !shared && i <= bend; i++)
++              for (i = 0; !shared && i < bindex; i++)
 +                      shared = (au_sbr_sb(sb, i) == h_sb);
 +              if (shared)
 +                      continue;
@@ -22900,18 +23141,36 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +              if (unlikely(err))
 +                      goto out;
 +
-+              blocks = au_add_till_max(blocks, buf->f_blocks);
-+              bfree = au_add_till_max(bfree, buf->f_bfree);
-+              bavail = au_add_till_max(bavail, buf->f_bavail);
++              if (bsize > buf->f_bsize) {
++                      /*
++                       * we will reduce bsize, so we have to expand blocks
++                       * etc. to match them again
++                       */
++                      factor = (bsize / buf->f_bsize);
++                      blocks = au_mul_till_max(blocks, factor);
++                      bfree = au_mul_till_max(bfree, factor);
++                      bavail = au_mul_till_max(bavail, factor);
++                      bsize = buf->f_bsize;
++              }
++
++              factor = (buf->f_bsize / bsize);
++              blocks = au_add_till_max(blocks,
++                              au_mul_till_max(buf->f_blocks, factor));
++              bfree = au_add_till_max(bfree,
++                              au_mul_till_max(buf->f_bfree, factor));
++              bavail = au_add_till_max(bavail,
++                              au_mul_till_max(buf->f_bavail, factor));
 +              files = au_add_till_max(files, buf->f_files);
 +              ffree = au_add_till_max(ffree, buf->f_ffree);
 +      }
 +
++      buf->f_bsize = bsize;
 +      buf->f_blocks = blocks;
 +      buf->f_bfree = bfree;
 +      buf->f_bavail = bavail;
 +      buf->f_files = files;
 +      buf->f_ffree = ffree;
++      buf->f_frsize = 0;
 +
 +out:
 +      return err;
@@ -23330,15 +23589,15 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      inode->i_op = &aufs_dir_iop;
 +      inode->i_fop = &aufs_dir_fop;
 +      inode->i_mode = S_IFDIR;
-+      inode->i_nlink = 2;
++      set_nlink(inode, 2);
 +      unlock_new_inode(inode);
 +
-+      root = d_alloc_root(inode);
++      root = d_make_root(inode);
 +      if (unlikely(!root))
-+              goto out_iput;
++              goto out;
 +      err = PTR_ERR(root);
 +      if (IS_ERR(root))
-+              goto out_iput;
++              goto out;
 +
 +      err = au_di_init(root);
 +      if (!err) {
@@ -23346,13 +23605,9 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +              return 0; /* success */
 +      }
 +      dput(root);
-+      goto out; /* do not iput */
 +
-+out_iput:
-+      iget_failed(inode);
 +out:
 +      return err;
-+
 +}
 +
 +static int aufs_fill_super(struct super_block *sb, void *raw_data,
@@ -23477,6 +23732,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +              if (au_opt_test(sbinfo->si_mntflags, PLINK))
 +                      au_plink_put(sb, /*verbose*/1);
 +              au_xino_clr(sb);
++              sbinfo->si_sb = NULL;
 +              aufs_write_unlock(sb->s_root);
 +              au_nwt_flush(&sbinfo->si_nowait);
 +      }
@@ -23495,10 +23751,10 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +};
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,547 @@
++++ linux/fs/aufs/super.h      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,546 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -23525,7 +23781,6 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +#ifdef __KERNEL__
 +
 +#include <linux/fs.h>
-+#include <linux/aufs_type.h>
 +#include "rwsem.h"
 +#include "spl.h"
 +#include "wkq.h"
@@ -24046,10 +24301,10 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +#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    2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,107 @@
++++ linux/fs/aufs/sysaufs.c    2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,105 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -24071,9 +24326,7 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c
 + * they are necessary regardless sysfs is disabled.
 + */
 +
-+#include <linux/fs.h>
 +#include <linux/random.h>
-+#include <linux/sysfs.h>
 +#include "aufs.h"
 +
 +unsigned long sysaufs_si_mask;
@@ -24157,10 +24410,10 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c
 +}
 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    2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,105 @@
++++ linux/fs/aufs/sysaufs.h    2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,104 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -24187,7 +24440,6 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h
 +#ifdef __KERNEL__
 +
 +#include <linux/sysfs.h>
-+#include <linux/aufs_type.h>
 +#include "module.h"
 +
 +struct super_block;
@@ -24266,10 +24518,10 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h
 +#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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,250 @@
++++ linux/fs/aufs/sysfs.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,257 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -24290,10 +24542,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
 + * sysfs interface
 + */
 +
-+#include <linux/fs.h>
-+#include <linux/module.h>
 +#include <linux/seq_file.h>
-+#include <linux/sysfs.h>
 +#include "aufs.h"
 +
 +#ifdef CONFIG_AUFS_FS_MODULE
@@ -24353,12 +24602,15 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
 +static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
 +                       aufs_bindex_t bindex)
 +{
++      int err;
 +      struct path path;
 +      struct dentry *root;
 +      struct au_branch *br;
++      char *perm;
 +
 +      AuDbg("b%d\n", bindex);
 +
++      err = 0;
 +      root = sb->s_root;
 +      di_read_lock_parent(root, !AuLock_IR);
 +      br = au_sbr(sb, bindex);
@@ -24366,8 +24618,15 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
 +      path.dentry = au_h_dptr(root, bindex);
 +      au_seq_path(seq, &path);
 +      di_read_unlock(root, !AuLock_IR);
-+      seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm));
-+      return 0;
++      perm = au_optstr_br_perm(br->br_perm);
++      if (perm) {
++              err = seq_printf(seq, "=%s\n", perm);
++              kfree(perm);
++              if (err == -1)
++                      err = -E2BIG;
++      } else
++              err = -ENOMEM;
++      return err;
 +}
 +
 +/* ---------------------------------------------------------------------- */
@@ -24439,7 +24698,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
 +      bend = au_sbend(sb);
 +      if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) {
 +              name += sizeof(SysaufsBr_PREFIX) - 1;
-+              err = strict_strtol(name, 10, &l);
++              err = kstrtol(name, 10, &l);
 +              if (!err) {
 +                      if (l <= bend)
 +                              err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l);
@@ -24520,10 +24779,10 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,151 @@
++++ linux/fs/aufs/sysrq.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,148 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -24544,9 +24803,6 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c
 + * magic sysrq hanlder
 + */
 +
-+#include <linux/fs.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
 +/* #include <linux/sysrq.h> */
 +#include <linux/writeback.h>
 +#include "aufs.h"
@@ -24675,10 +24931,10 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c
 +}
 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       2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,886 @@
++++ linux/fs/aufs/vdir.c       2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,885 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -24699,7 +24955,6 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
 + * virtual or vertical directory
 + */
 +
-+#include <linux/hash.h>
 +#include "aufs.h"
 +
 +static unsigned int calc_size(int nlen)
@@ -25565,10 +25820,10 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,836 @@
++++ linux/fs/aufs/vfsub.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,832 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -25589,12 +25844,10 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 + * sub-routines for VFS
 + */
 +
-+#include <linux/file.h>
 +#include <linux/ima.h>
 +#include <linux/namei.h>
 +#include <linux/security.h>
 +#include <linux/splice.h>
-+#include <linux/uaccess.h>
 +#include "aufs.h"
 +
 +int vfsub_update_h_iattr(struct path *h_path, int *did)
@@ -25710,22 +25963,19 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 + */
 +int vfsub_name_hash(const char *name, struct qstr *this, int len)
 +{
-+      unsigned long hash;
 +      unsigned int c;
 +
 +      this->name = name;
 +      this->len = len;
++      this->hash = full_name_hash(name, len);
 +      if (!len)
 +              return -EACCES;
 +
-+      hash = init_name_hash();
 +      while (len--) {
 +              c = *(const unsigned char *)name++;
 +              if (c == '/' || c == '\0')
 +                      return -EACCES;
-+              hash = partial_name_hash(c, hash);
 +      }
-+      this->hash = end_name_hash(hash);
 +      return 0;
 +}
 +
@@ -26022,6 +26272,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +
 +/* ---------------------------------------------------------------------- */
 +
++/* todo: support mmap_sem? */
 +ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
 +                   loff_t *ppos)
 +{
@@ -26405,10 +26656,10 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/vfsub.h      2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,232 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -26576,7 +26827,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +              .dentry = h_dentry,
 +              .mnt    = h_mnt
 +      };
-+      touch_atime(h_mnt, h_dentry);
++      touch_atime(&h_path);
 +      vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
 +}
 +
@@ -26641,10 +26892,10 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +#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 2011-08-24 13:30:24.734646739 +0200
++++ linux/fs/aufs/wbr_policy.c 2012-05-22 09:06:08.870792417 +0200
 @@ -0,0 +1,700 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -27345,10 +27596,10 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +};
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,1062 @@
++++ linux/fs/aufs/whout.c      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,1049 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -27369,7 +27620,6 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 + * whiteout for logical deletion and opaque directory
 + */
 +
-+#include <linux/fs.h>
 +#include "aufs.h"
 +
 +#define WH_MASK                       S_IRUGO
@@ -27851,33 +28101,21 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +              }
 +
 +      err = 0;
-+      switch (br->br_perm) {
-+      case AuBrPerm_RO:
-+      case AuBrPerm_ROWH:
-+      case AuBrPerm_RR:
-+      case AuBrPerm_RRWH:
++      if (!au_br_writable(br->br_perm)) {
 +              h_dir = h_root->d_inode;
 +              au_wh_init_ro(h_dir, base, &path);
-+              break;
-+
-+      case AuBrPerm_RWNoLinkWH:
++      } else if (!au_br_wh_linkable(br->br_perm)) {
 +              err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path);
 +              if (err > 0)
 +                      goto out;
 +              else if (err)
 +                      goto out_err;
-+              break;
-+
-+      case AuBrPerm_RW:
++      } else {
 +              err = au_wh_init_rw(h_root, wbr, do_plink, base, &path);
 +              if (err > 0)
 +                      goto out;
 +              else if (err)
 +                      goto out_err;
-+              break;
-+
-+      default:
-+              BUG();
 +      }
 +      goto out; /* success */
 +
@@ -28411,10 +28649,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +}
 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      2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,89 @@
++++ linux/fs/aufs/whout.h      2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,88 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -28440,7 +28678,6 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/aufs_type.h>
 +#include "dir.h"
 +
 +/* whout.c */
@@ -28504,10 +28741,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h
 +#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        2011-08-24 13:30:24.734646739 +0200
-@@ -0,0 +1,244 @@
++++ linux/fs/aufs/wkq.c        2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,214 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -28532,23 +28769,9 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +#include <linux/module.h>
 +#include "aufs.h"
 +
-+/* internal workqueue named AUFS_WKQ_NAME and AUFS_WKQ_PRE_NAME */
-+enum {
-+      AuWkq_INORMAL,
-+      AuWkq_IPRE
-+};
++/* internal workqueue named AUFS_WKQ_NAME */
 +
-+static struct {
-+      char *name;
-+      struct workqueue_struct *wkq;
-+} au_wkq[] = {
-+      [AuWkq_INORMAL] = {
-+              .name = AUFS_WKQ_NAME
-+      },
-+      [AuWkq_IPRE] = {
-+              .name = AUFS_WKQ_PRE_NAME
-+      }
-+};
++static struct workqueue_struct *au_wkq;
 +
 +struct au_wkinfo {
 +      struct work_struct wk;
@@ -28576,7 +28799,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +              complete(wkinfo->comp);
 +      else {
 +              kobject_put(wkinfo->kobj);
-+              module_put(THIS_MODULE);
++              module_put(THIS_MODULE); /* todo: ?? */
 +              kfree(wkinfo);
 +      }
 +}
@@ -28624,8 +28847,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +
 +static void au_wkq_run(struct au_wkinfo *wkinfo)
 +{
-+      struct workqueue_struct *wkq;
-+
 +      if (au_ftest_wkq(wkinfo->flags, NEST)) {
 +              if (au_wkq_test()) {
 +                      AuWarn1("wkq from wkq, due to a dead dir by UDBA?\n");
@@ -28636,10 +28857,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +
 +      if (au_ftest_wkq(wkinfo->flags, WAIT)) {
 +              INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func);
-+              wkq = au_wkq[AuWkq_INORMAL].wkq;
-+              if (au_ftest_wkq(wkinfo->flags, PRE))
-+                      wkq = au_wkq[AuWkq_IPRE].wkq;
-+              queue_work(wkq, &wkinfo->wk);
++              queue_work(au_wkq, &wkinfo->wk);
 +      } else {
 +              INIT_WORK(&wkinfo->wk, wkq_func);
 +              schedule_work(&wkinfo->wk);
@@ -28700,7 +28918,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +              wkinfo->args = args;
 +              wkinfo->comp = NULL;
 +              kobject_get(wkinfo->kobj);
-+              __module_get(THIS_MODULE);
++              __module_get(THIS_MODULE); /* todo: ?? */
 +
 +              au_wkq_run(wkinfo);
 +      } else {
@@ -28722,40 +28940,29 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +
 +void au_wkq_fin(void)
 +{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(au_wkq); i++)
-+              if (au_wkq[i].wkq)
-+                      destroy_workqueue(au_wkq[i].wkq);
++      destroy_workqueue(au_wkq);
 +}
 +
 +int __init au_wkq_init(void)
 +{
-+      int err, i;
++      int err;
 +
 +      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);
-+              if (IS_ERR(au_wkq[i].wkq))
-+                      err = PTR_ERR(au_wkq[i].wkq);
-+              else if (!au_wkq[i].wkq)
-+                      err = -ENOMEM;
-+              if (unlikely(err))
-+                      au_wkq[i].wkq = NULL;
-+      }
-+      if (unlikely(err))
-+              au_wkq_fin();
++      BUILD_BUG_ON(!WQ_RESCUER);
++      au_wkq = alloc_workqueue(AUFS_WKQ_NAME, !WQ_RESCUER, WQ_DFL_ACTIVE);
++      if (IS_ERR(au_wkq))
++              err = PTR_ERR(au_wkq);
++      else if (!au_wkq)
++              err = -ENOMEM;
 +
 +      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        2011-08-24 13:30:24.737979976 +0200
-@@ -0,0 +1,101 @@
++++ linux/fs/aufs/wkq.h        2012-05-22 09:06:08.870792417 +0200
+@@ -0,0 +1,92 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -28782,10 +28989,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
 +
 +#ifdef __KERNEL__
 +
-+#include <linux/sched.h>
-+#include <linux/wait.h>
-+#include <linux/aufs_type.h>
-+
 +struct super_block;
 +
 +/* ---------------------------------------------------------------------- */
@@ -28804,18 +29007,18 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
 +
 +/* wkq flags */
 +#define AuWkq_WAIT    1
-+#define AuWkq_PRE     (1 << 1)
-+#ifdef CONFIG_AUFS_HNOTIFY
-+#define AuWkq_NEST    (1 << 2)
-+#else
-+#define AuWkq_NEST    0
-+#endif
++#define AuWkq_NEST    (1 << 1)
 +#define au_ftest_wkq(flags, name)     ((flags) & AuWkq_##name)
 +#define au_fset_wkq(flags, name) \
 +      do { (flags) |= AuWkq_##name; } while (0)
 +#define au_fclr_wkq(flags, name) \
 +      do { (flags) &= ~AuWkq_##name; } while (0)
 +
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuWkq_NEST
++#define AuWkq_NEST    0
++#endif
++
 +/* wkq.c */
 +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
 +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb,
@@ -28831,11 +29034,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
 +      return current->flags & PF_WQ_WORKER;
 +}
 +
-+static inline int au_wkq_wait_pre(au_wkq_func_t func, void *args)
-+{
-+      return au_wkq_do_wait(AuWkq_WAIT | AuWkq_PRE, func, args);
-+}
-+
 +static inline int au_wkq_wait(au_wkq_func_t func, void *args)
 +{
 +      return au_wkq_do_wait(AuWkq_WAIT, func, args);
@@ -28857,10 +29055,10 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
 +#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       2011-08-24 13:30:24.737979976 +0200
-@@ -0,0 +1,1265 @@
++++ linux/fs/aufs/xino.c       2012-05-22 09:06:08.874125894 +0200
+@@ -0,0 +1,1264 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -28881,11 +29079,10 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 + * external inode number translation table and bitmap
 + */
 +
-+#include <linux/file.h>
 +#include <linux/seq_file.h>
-+#include <linux/uaccess.h>
 +#include "aufs.h"
 +
++/* todo: unnecessary to support mmap_sem since kernel-space? */
 +ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size,
 +                 loff_t *pos)
 +{
@@ -30126,10 +30323,10 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +}
 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    2011-08-24 13:30:24.737979976 +0200
-@@ -0,0 +1,211 @@
++++ linux/include/linux/aufs_type.h    2012-05-23 12:07:43.277739181 +0200
+@@ -0,0 +1,233 @@
 +/*
-+ * Copyright (C) 2005-2011 Junjiro R. Okajima
++ * Copyright (C) 2005-2012 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
@@ -30149,12 +30346,27 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +#ifndef __AUFS_TYPE_H__
 +#define __AUFS_TYPE_H__
 +
-+#include <linux/ioctl.h>
-+#include <linux/kernel.h>
++#define AUFS_NAME     "aufs"
++
++#ifdef __KERNEL__
++/*
++ * define it before including all other headers.
++ * sched.h may use pr_* macros before defining "current", so define the
++ * no-current version first, and re-define later.
++ */
++#define pr_fmt(fmt)   AUFS_NAME " %s:%d: " fmt, __func__, __LINE__
++#include <linux/sched.h>
++#undef pr_fmt
++#define pr_fmt(fmt)   AUFS_NAME " %s:%d:%s[%d]: " fmt, \
++              __func__, __LINE__, current->comm, current->pid
++#else
++#include <stdint.h>
++#include <sys/types.h>
++#endif /* __KERNEL__ */
++
 +#include <linux/limits.h>
-+#include <linux/types.h>
 +
-+#define AUFS_VERSION  "3.0-20110822"
++#define AUFS_VERSION  "3.4-20120521"
 +
 +/* todo? move this to linux-2.6.19/include/magic.h */
 +#define AUFS_SUPER_MAGIC      ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -30162,10 +30374,10 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +/* ---------------------------------------------------------------------- */
 +
 +#ifdef CONFIG_AUFS_BRANCH_MAX_127
-+typedef __s8 aufs_bindex_t;
++typedef int8_t aufs_bindex_t;
 +#define AUFS_BRANCH_MAX 127
 +#else
-+typedef __s16 aufs_bindex_t;
++typedef int16_t aufs_bindex_t;
 +#ifdef CONFIG_AUFS_BRANCH_MAX_511
 +#define AUFS_BRANCH_MAX 511
 +#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
@@ -30183,7 +30395,6 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +
 +/* ---------------------------------------------------------------------- */
 +
-+#define AUFS_NAME             "aufs"
 +#define AUFS_FSTYPE           AUFS_NAME
 +
 +#define AUFS_ROOT_INO         2
@@ -30207,7 +30418,6 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +#define AUFS_RDBLK_DEF                512 /* bytes */
 +#define AUFS_RDHASH_DEF               32
 +#define AUFS_WKQ_NAME         AUFS_NAME "d"
-+#define AUFS_WKQ_PRE_NAME     AUFS_WKQ_NAME "_pre"
 +#define AUFS_MFS_DEF_SEC      30 /* seconds */
 +#define AUFS_MFS_MAX_SEC      3600 /* seconds */
 +#define AUFS_PLINK_WARN               100 /* number of plinks */
@@ -30229,15 +30439,12 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +#define AUFS_WH_PLINKDIR      AUFS_WH_PFX AUFS_PLINKDIR_NAME
 +#define AUFS_WH_ORPHDIR               AUFS_WH_PFX AUFS_ORPHDIR_NAME
 +
-+/* branch permission */
++/* branch permissions and attributes */
 +#define AUFS_BRPERM_RW                "rw"
 +#define AUFS_BRPERM_RO                "ro"
 +#define AUFS_BRPERM_RR                "rr"
-+#define AUFS_BRPERM_WH                "wh"
-+#define AUFS_BRPERM_NLWH      "nolwh"
-+#define AUFS_BRPERM_ROWH      AUFS_BRPERM_RO "+" AUFS_BRPERM_WH
-+#define AUFS_BRPERM_RRWH      AUFS_BRPERM_RR "+" AUFS_BRPERM_WH
-+#define AUFS_BRPERM_RWNLWH    AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH
++#define AUFS_BRRATTR_WH               "wh"
++#define AUFS_BRWATTR_NLWH     "nolwh"
 +
 +/* ---------------------------------------------------------------------- */
 +
@@ -30272,19 +30479,19 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +#endif
 +
 +struct au_rdu_cookie {
-+      __u64           h_pos;
-+      __s16           bindex;
-+      __u8            flags;
-+      __u8            pad;
-+      __u32           generation;
++      uint64_t        h_pos;
++      int16_t         bindex;
++      uint8_t         flags;
++      uint8_t         pad;
++      uint32_t        generation;
 +} __aligned(8);
 +
 +struct au_rdu_ent {
-+      __u64           ino;
-+      __s16           bindex;
-+      __u8            type;
-+      __u8            nlen;
-+      __u8            wh;
++      uint64_t        ino;
++      int16_t         bindex;
++      uint8_t         type;
++      uint8_t         nlen;
++      uint8_t         wh;
 +      char            name[0];
 +} __aligned(8);
 +
@@ -30292,12 +30499,12 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +{
 +      /* include the terminating NULL */
 +      return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
-+                   sizeof(__u64));
++                   sizeof(uint64_t));
 +}
 +
 +union au_rdu_ent_ul {
 +      struct au_rdu_ent __user        *e;
-+      __u64                           ul;
++      uint64_t                        ul;
 +};
 +
 +enum {
@@ -30308,34 +30515,46 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +struct aufs_rdu {
 +      /* input */
 +      union {
-+              __u64           sz;     /* AuCtl_RDU */
-+              __u64           nent;   /* AuCtl_RDU_INO */
++              uint64_t        sz;     /* AuCtl_RDU */
++              uint64_t        nent;   /* AuCtl_RDU_INO */
 +      };
 +      union au_rdu_ent_ul     ent;
-+      __u16                   verify[AufsCtlRduV_End];
++      uint16_t                verify[AufsCtlRduV_End];
 +
 +      /* input/output */
-+      __u32                   blk;
++      uint32_t                blk;
 +
 +      /* output */
 +      union au_rdu_ent_ul     tail;
 +      /* number of entries which were added in a single call */
-+      __u64                   rent;
-+      __u8                    full;
-+      __u8                    shwh;
++      uint64_t                rent;
++      uint8_t                 full;
++      uint8_t                 shwh;
 +
 +      struct au_rdu_cookie    cookie;
 +} __aligned(8);
 +
++/* ---------------------------------------------------------------------- */
++
++struct aufs_wbr_fd {
++      uint32_t        oflags;
++      int16_t         brid;
++} __aligned(8);
++
++/* ---------------------------------------------------------------------- */
++
 +struct aufs_ibusy {
-+      __u64           ino, h_ino;
-+      __s16           bindex;
++      uint64_t        ino, h_ino;
++      int16_t         bindex;
 +} __aligned(8);
 +
++/* ---------------------------------------------------------------------- */
++
 +#define AuCtlType             'A'
 +#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)
++#define AUFS_CTL_WBR_FD               _IOW(AuCtlType, AuCtl_WBR_FD, \
++                                   struct aufs_wbr_fd)
 +#define AUFS_CTL_IBUSY                _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy)
 +
 +#endif /* __AUFS_TYPE_H__ */
This page took 0.258589 seconds and 4 git commands to generate.