]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- updated aufs patch to 3.18.1+
authorJan Rękorajski <baggins@pld-linux.org>
Sun, 25 Jan 2015 12:13:10 +0000 (13:13 +0100)
committerJan Rękorajski <baggins@pld-linux.org>
Sun, 25 Jan 2015 12:13:10 +0000 (13:13 +0100)
kernel-aufs3.patch

index d728d117012d63a311e09ee1cb4db0f06891f39e..68ab2f5754ddcc872f435af8acba430cb2c5c988 100644 (file)
@@ -1,10 +1,10 @@
-aufs3.16 kbuild patch
+aufs3.18.1+ kbuild patch
 
 diff --git a/fs/Kconfig b/fs/Kconfig
-index 312393f..78632ed 100644
+index 664991a..1481093 100644
 --- a/fs/Kconfig
 +++ b/fs/Kconfig
-@@ -209,6 +209,7 @@ source "fs/ufs/Kconfig"
+@@ -210,6 +210,7 @@ source "fs/ufs/Kconfig"
  source "fs/exofs/Kconfig"
  source "fs/f2fs/Kconfig"
  source "fs/efivarfs/Kconfig"
@@ -13,16 +13,16 @@ index 312393f..78632ed 100644
  endif # MISC_FILESYSTEMS
  
 diff --git a/fs/Makefile b/fs/Makefile
-index 4030cbf..5bd169a 100644
+index da0bbb4..c8bc724 100644
 --- a/fs/Makefile
 +++ b/fs/Makefile
-@@ -125,3 +125,4 @@ obj-y                              += exofs/ # Multiple modules
+@@ -126,3 +126,4 @@ obj-y                              += exofs/ # Multiple modules
  obj-$(CONFIG_CEPH_FS)         += ceph/
  obj-$(CONFIG_PSTORE)          += pstore/
  obj-$(CONFIG_EFIVAR_FS)               += efivarfs/
 +obj-$(CONFIG_AUFS_FS)           += aufs/
 diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
-index 24e9033..fe9a8d4 100644
+index 8523f9b..11f8f74 100644
 --- a/include/uapi/linux/Kbuild
 +++ b/include/uapi/linux/Kbuild
 @@ -56,6 +56,7 @@ header-y += atmppp.h
@@ -33,8 +33,33 @@ index 24e9033..fe9a8d4 100644
  header-y += auto_fs.h
  header-y += auto_fs4.h
  header-y += auxvec.h
-aufs3.16 base patch
+aufs3.18.1+ base patch
 
+diff --git a/MAINTAINERS b/MAINTAINERS
+index c721042..83801d0 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1795,6 +1795,20 @@ F:      include/linux/audit.h
+ F:    include/uapi/linux/audit.h
+ F:    kernel/audit*
++AUFS (advanced multi layered unification filesystem) FILESYSTEM
++M:    "J. R. Okajima" <hooanon05g@gmail.com>
++L:    linux-unionfs@vger.kernel.org
++L:    aufs-users@lists.sourceforge.net (members only)
++W:    http://aufs.sourceforge.net
++T:    git://git.code.sf.net/p/aufs/aufs3-linux
++T:    git://github.com/sfjro/aufs3-linux.git
++S:    Supported
++F:    Documentation/filesystems/aufs/
++F:    Documentation/ABI/testing/debugfs-aufs
++F:    Documentation/ABI/testing/sysfs-aufs
++F:    fs/aufs/
++F:    include/uapi/linux/aufs_type.h
++
+ AUXILIARY DISPLAY DRIVERS
+ M:    Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
+ W:    http://miguelojeda.es/auxdisplay.htm
 diff --git a/drivers/block/loop.c b/drivers/block/loop.c
 index 6cb1beb..30efd68 100644
 --- a/drivers/block/loop.c
@@ -64,11 +89,24 @@ index 6cb1beb..30efd68 100644
  /* loop sysfs attributes */
  
  static ssize_t loop_attr_show(struct device *dev, char *page,
+diff --git a/fs/dcache.c b/fs/dcache.c
+index 71acf8d..da7342e 100644
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -1019,7 +1019,7 @@ enum d_walk_ret {
+  *
+  * The @enter() and @finish() callbacks are called with d_lock held.
+  */
+-static void d_walk(struct dentry *parent, void *data,
++void d_walk(struct dentry *parent, void *data,
+                  enum d_walk_ret (*enter)(void *, struct dentry *),
+                  void (*finish)(void *))
+ {
 diff --git a/fs/inode.c b/fs/inode.c
-index 6eecb7f..b225c0f 100644
+index 26753ba..df21e66 100644
 --- a/fs/inode.c
 +++ b/fs/inode.c
-@@ -1496,7 +1496,7 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
+@@ -1497,7 +1497,7 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
   * This does the actual work of updating an inodes time or version.  Must have
   * had called mnt_want_write() before calling this.
   */
@@ -78,7 +116,7 @@ index 6eecb7f..b225c0f 100644
        if (inode->i_op->update_time)
                return inode->i_op->update_time(inode, time, flags);
 diff --git a/fs/splice.c b/fs/splice.c
-index f5cb9ba..9ba380c 100644
+index 75c6058..619359a 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
 @@ -1114,8 +1114,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
@@ -106,10 +144,10 @@ index f5cb9ba..9ba380c 100644
        ssize_t (*splice_read)(struct file *, loff_t *,
                               struct pipe_inode_info *, size_t, unsigned int);
 diff --git a/include/linux/fs.h b/include/linux/fs.h
-index e11d60c..2f32b35 100644
+index 9ab779e..aabcbba 100644
 --- a/include/linux/fs.h
 +++ b/include/linux/fs.h
-@@ -2618,6 +2618,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *);
+@@ -2664,6 +2664,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *);
  extern int inode_newsize_ok(const struct inode *, loff_t offset);
  extern void setattr_copy(struct inode *inode, const struct iattr *attr);
  
@@ -132,13 +170,13 @@ index da2751d..2e0fca6 100644
 +                       struct pipe_inode_info *pipe, size_t len,
 +                       unsigned int flags);
  #endif
-aufs3.16 mmap patch
+aufs3.18.1+ mmap patch
 
 diff --git a/fs/buffer.c b/fs/buffer.c
-index eba6e4f..31f0b2d 100644
+index 20805db..363569f 100644
 --- a/fs/buffer.c
 +++ b/fs/buffer.c
-@@ -2460,7 +2460,7 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
+@@ -2450,7 +2450,7 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
         * Update file times before taking page lock. We may end up failing the
         * fault so this update may be superfluous but who really cares...
         */
@@ -147,6 +185,19 @@ index eba6e4f..31f0b2d 100644
  
        ret = __block_page_mkwrite(vma, vmf, get_block);
        sb_end_pagefault(sb);
+diff --git a/fs/proc/base.c b/fs/proc/base.c
+index 772efa4..2c944de 100644
+--- a/fs/proc/base.c
++++ b/fs/proc/base.c
+@@ -1735,7 +1735,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
+       down_read(&mm->mmap_sem);
+       vma = find_exact_vma(mm, vm_start, vm_end);
+       if (vma && vma->vm_file) {
+-              *path = vma->vm_file->f_path;
++              *path = vma_pr_or_file(vma)->f_path;
+               path_get(path);
+               rc = 0;
+       }
 diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
 index d4a3574..1397181 100644
 --- a/fs/proc/nommu.c
@@ -164,10 +215,10 @@ index d4a3574..1397181 100644
                ino = inode->i_ino;
        }
 diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
-index cfa63ee..bf4919e 100644
+index 4e0388c..fc429e7 100644
 --- a/fs/proc/task_mmu.c
 +++ b/fs/proc/task_mmu.c
-@@ -265,7 +265,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
+@@ -276,7 +276,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
        const char *name = NULL;
  
        if (file) {
@@ -179,7 +230,7 @@ index cfa63ee..bf4919e 100644
                dev = inode->i_sb->s_dev;
                ino = inode->i_ino;
                pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
-@@ -1390,7 +1393,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
+@@ -1440,7 +1443,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
        struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
        struct vm_area_struct *vma = v;
        struct numa_maps *md = &numa_priv->md;
@@ -189,10 +240,10 @@ index cfa63ee..bf4919e 100644
        struct mm_walk walk = {};
        struct mempolicy *pol;
 diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
-index 678455d..0ef7ef4 100644
+index 599ec2e..de6cd6e 100644
 --- a/fs/proc/task_nommu.c
 +++ b/fs/proc/task_nommu.c
-@@ -141,7 +141,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
+@@ -160,7 +160,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
        file = vma->vm_file;
  
        if (file) {
@@ -205,10 +256,10 @@ index 678455d..0ef7ef4 100644
                ino = inode->i_ino;
                pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
 diff --git a/include/linux/mm.h b/include/linux/mm.h
-index e03dd29..dd32624 100644
+index b464611..8027d51 100644
 --- a/include/linux/mm.h
 +++ b/include/linux/mm.h
-@@ -1184,6 +1184,28 @@ static inline int fixup_user_fault(struct task_struct *tsk,
+@@ -1206,6 +1206,28 @@ static inline int fixup_user_fault(struct task_struct *tsk,
  }
  #endif
  
@@ -238,7 +289,7 @@ index e03dd29..dd32624 100644
  extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
                void *buf, int len, int write);
 diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
-index 96c5750..a087ecd 100644
+index 6e0b286..8f374ed 100644
 --- a/include/linux/mm_types.h
 +++ b/include/linux/mm_types.h
 @@ -232,6 +232,7 @@ struct vm_region {
@@ -258,10 +309,10 @@ index 96c5750..a087ecd 100644
  
  #ifndef CONFIG_MMU
 diff --git a/kernel/fork.c b/kernel/fork.c
-index 6a13c46..714302c 100644
+index 9b7d746..9a3b8fe 100644
 --- a/kernel/fork.c
 +++ b/kernel/fork.c
-@@ -416,7 +416,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
+@@ -430,7 +430,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                        struct inode *inode = file_inode(file);
                        struct address_space *mapping = file->f_mapping;
  
@@ -271,23 +322,23 @@ index 6a13c46..714302c 100644
                                atomic_dec(&inode->i_writecount);
                        mutex_lock(&mapping->i_mmap_mutex);
 diff --git a/mm/Makefile b/mm/Makefile
-index 4064f3e..0003fdf 100644
+index 8405eb0..e0bda2d 100644
 --- a/mm/Makefile
 +++ b/mm/Makefile
-@@ -18,7 +18,7 @@ obj-y                        := filemap.o mempool.o oom_kill.o fadvise.o \
+@@ -18,7 +18,7 @@ obj-y                        := filemap.o mempool.o oom_kill.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
-                          compaction.o balloon_compaction.o vmacache.o \
+                          compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o \
 -                         iov_iter.o debug.o $(mmu-y)
-+                         iov_iter.o debug.o prfile.o $(mmu-y)
++                         iov_iter.o prfile.o debug.o $(mmu-y)
  
  obj-y += init-mm.o
  
 diff --git a/mm/filemap.c b/mm/filemap.c
-index 900edfa..f4dda0c 100644
+index 14b4642..99bc835 100644
 --- a/mm/filemap.c
 +++ b/mm/filemap.c
-@@ -2040,7 +2040,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+@@ -2067,7 +2067,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        int ret = VM_FAULT_LOCKED;
  
        sb_start_pagefault(inode->i_sb);
@@ -332,10 +383,10 @@ index 72b8fa3..a00bbf0 100644
                        }
                        goto out_freed;
 diff --git a/mm/madvise.c b/mm/madvise.c
-index a402f8f..134e15d 100644
+index 0938b30..0b66856 100644
 --- a/mm/madvise.c
 +++ b/mm/madvise.c
-@@ -327,12 +327,12 @@ static long madvise_remove(struct vm_area_struct *vma,
+@@ -324,12 +324,12 @@ static long madvise_remove(struct vm_area_struct *vma,
         * vma's reference to the file) can go away as soon as we drop
         * mmap_sem.
         */
@@ -351,10 +402,10 @@ index a402f8f..134e15d 100644
        return error;
  }
 diff --git a/mm/memory.c b/mm/memory.c
-index 8b44f76..69a72bf 100644
+index d5f2ae9..0830a96 100644
 --- a/mm/memory.c
 +++ b/mm/memory.c
-@@ -2161,7 +2161,7 @@ reuse:
+@@ -2163,7 +2163,7 @@ reuse:
                        set_page_dirty_balance(dirty_page);
                        /* file_update_time outside page_lock */
                        if (vma->vm_file)
@@ -364,10 +415,10 @@ index 8b44f76..69a72bf 100644
                put_page(dirty_page);
                if (page_mkwrite) {
 diff --git a/mm/mmap.c b/mm/mmap.c
-index 129b847..869d1d7 100644
+index ae91989..e3bee5c 100644
 --- a/mm/mmap.c
 +++ b/mm/mmap.c
-@@ -253,7 +253,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
+@@ -277,7 +277,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
        if (vma->vm_ops && vma->vm_ops->close)
                vma->vm_ops->close(vma);
        if (vma->vm_file)
@@ -376,7 +427,7 @@ index 129b847..869d1d7 100644
        mpol_put(vma_policy(vma));
        kmem_cache_free(vm_area_cachep, vma);
        return next;
-@@ -863,7 +863,7 @@ again:                     remove_next = 1 + (end > next->vm_end);
+@@ -895,7 +895,7 @@ again:                     remove_next = 1 + (end > next->vm_end);
        if (remove_next) {
                if (file) {
                        uprobe_munmap(next, next->vm_start, next->vm_end);
@@ -385,7 +436,7 @@ index 129b847..869d1d7 100644
                }
                if (next->anon_vma)
                        anon_vma_merge(vma, next);
-@@ -1643,8 +1643,8 @@ out:
+@@ -1680,8 +1680,8 @@ out:
        return addr;
  
  unmap_and_free_vma:
@@ -395,7 +446,7 @@ index 129b847..869d1d7 100644
  
        /* Undo any partial mapping done by a device driver. */
        unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
-@@ -2434,7 +2434,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
+@@ -2477,7 +2477,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out_free_mpol;
  
        if (new->vm_file)
@@ -404,7 +455,7 @@ index 129b847..869d1d7 100644
  
        if (new->vm_ops && new->vm_ops->open)
                new->vm_ops->open(new);
-@@ -2453,7 +2453,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
+@@ -2496,7 +2496,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        if (new->vm_ops && new->vm_ops->close)
                new->vm_ops->close(new);
        if (new->vm_file)
@@ -413,7 +464,7 @@ index 129b847..869d1d7 100644
        unlink_anon_vmas(new);
   out_free_mpol:
        mpol_put(vma_policy(new));
-@@ -2842,7 +2842,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
+@@ -2886,7 +2886,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                        if (anon_vma_clone(new_vma, vma))
                                goto out_free_mempol;
                        if (new_vma->vm_file)
@@ -443,7 +494,7 @@ index 992a167..ce1915b 100644
                                goto out;
                        down_read(&mm->mmap_sem);
 diff --git a/mm/nommu.c b/mm/nommu.c
-index 4a852f6..b369644 100644
+index bd1808e..c9ea035 100644
 --- a/mm/nommu.c
 +++ b/mm/nommu.c
 @@ -658,7 +658,7 @@ static void __put_nommu_region(struct vm_region *region)
@@ -578,10 +629,22 @@ index 0000000..fc708d2
 +              fput(pr);
 +}
 +#endif /* CONFIG_MMU */
-aufs3.16 standalone patch
+aufs3.18.1+ standalone patch
 
+diff --git a/fs/dcache.c b/fs/dcache.c
+index da7342e..b147b6c 100644
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -1124,6 +1124,7 @@ rename_retry:
+       seq = 1;
+       goto again;
+ }
++EXPORT_SYMBOL(d_walk);
+ /*
+  * Search for at least 1 mount point in the dentry's subdirs.
 diff --git a/fs/inode.c b/fs/inode.c
-index b225c0f..73259c8 100644
+index df21e66..c8df03d 100644
 --- a/fs/inode.c
 +++ b/fs/inode.c
 @@ -57,6 +57,7 @@ static struct hlist_head *inode_hashtable __read_mostly;
@@ -592,7 +655,7 @@ index b225c0f..73259c8 100644
  
  /*
   * Empty aops. Can be used for the cases where the user does not
-@@ -1512,6 +1513,7 @@ int update_time(struct inode *inode, struct timespec *time, int flags)
+@@ -1513,6 +1514,7 @@ int update_time(struct inode *inode, struct timespec *time, int flags)
        mark_inode_dirty_sync(inode);
        return 0;
  }
@@ -601,10 +664,10 @@ index b225c0f..73259c8 100644
  /**
   *    touch_atime     -       update the access time
 diff --git a/fs/namespace.c b/fs/namespace.c
-index 182bc41..c88e101 100644
+index 5b66b2b..68ff4e4 100644
 --- a/fs/namespace.c
 +++ b/fs/namespace.c
-@@ -453,6 +453,7 @@ void __mnt_drop_write(struct vfsmount *mnt)
+@@ -454,6 +454,7 @@ void __mnt_drop_write(struct vfsmount *mnt)
        mnt_dec_writers(real_mount(mnt));
        preempt_enable();
  }
@@ -612,7 +675,7 @@ index 182bc41..c88e101 100644
  
  /**
   * mnt_drop_write - give up write access to a mount
-@@ -1564,6 +1565,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
+@@ -1727,6 +1728,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
        }
        return 0;
  }
@@ -621,7 +684,7 @@ index 182bc41..c88e101 100644
  static void cleanup_group_ids(struct mount *mnt, struct mount *end)
  {
 diff --git a/fs/notify/group.c b/fs/notify/group.c
-index ad19959..adf290d 100644
+index d16b62c..06ca6bc 100644
 --- a/fs/notify/group.c
 +++ b/fs/notify/group.c
 @@ -22,6 +22,7 @@
@@ -657,7 +720,7 @@ index ad19959..adf290d 100644
  int fsnotify_fasync(int fd, struct file *file, int on)
  {
 diff --git a/fs/notify/mark.c b/fs/notify/mark.c
-index d90deaa..60b4239 100644
+index 34c38fa..d40cf58 100644
 --- a/fs/notify/mark.c
 +++ b/fs/notify/mark.c
 @@ -109,6 +109,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
@@ -676,7 +739,7 @@ index d90deaa..60b4239 100644
  
  void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
  {
-@@ -275,6 +277,7 @@ err:
+@@ -311,6 +313,7 @@ err:
  
        return ret;
  }
@@ -684,7 +747,7 @@ index d90deaa..60b4239 100644
  
  int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
                      struct inode *inode, struct vfsmount *mnt, int allow_dups)
-@@ -336,6 +339,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
+@@ -372,6 +375,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
        atomic_set(&mark->refcnt, 1);
        mark->free_mark = free_mark;
  }
@@ -693,7 +756,7 @@ index d90deaa..60b4239 100644
  static int fsnotify_mark_destroy(void *ignored)
  {
 diff --git a/fs/open.c b/fs/open.c
-index d6fd3ac..5e99d8b 100644
+index de92c13..65d8ab0 100644
 --- a/fs/open.c
 +++ b/fs/open.c
 @@ -62,6 +62,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
@@ -713,7 +776,7 @@ index d6fd3ac..5e99d8b 100644
  SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
  {
 diff --git a/fs/splice.c b/fs/splice.c
-index 9ba380c..3419932 100644
+index 619359a..c14f60e 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
 @@ -1127,6 +1127,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
@@ -732,11 +795,23 @@ index 9ba380c..3419932 100644
  
  /**
   * splice_direct_to_actor - splices data directly between two non-pipes
+diff --git a/fs/xattr.c b/fs/xattr.c
+index 64e83ef..bd71e53 100644
+--- a/fs/xattr.c
++++ b/fs/xattr.c
+@@ -207,6 +207,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
+       *xattr_value = value;
+       return error;
+ }
++EXPORT_SYMBOL(vfs_getxattr_alloc);
+ /* Compare an extended attribute value with the given value */
+ int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
 diff --git a/security/commoncap.c b/security/commoncap.c
-index b9d613e..ba3b618 100644
+index bab0611..3fa2f82 100644
 --- a/security/commoncap.c
 +++ b/security/commoncap.c
-@@ -988,9 +988,11 @@ int cap_mmap_addr(unsigned long addr)
+@@ -979,9 +979,11 @@ int cap_mmap_addr(unsigned long addr)
        }
        return ret;
  }
@@ -749,7 +824,7 @@ index b9d613e..ba3b618 100644
  }
 +EXPORT_SYMBOL(cap_mmap_file);
 diff --git a/security/device_cgroup.c b/security/device_cgroup.c
-index d9d69e6..3f6f471 100644
+index 188c1d2..426d9af 100644
 --- a/security/device_cgroup.c
 +++ b/security/device_cgroup.c
 @@ -7,6 +7,7 @@
@@ -769,7 +844,7 @@ index d9d69e6..3f6f471 100644
  int devcgroup_inode_mknod(int mode, dev_t dev)
  {
 diff --git a/security/security.c b/security/security.c
-index 31614e9..b223a66 100644
+index 18b35c6..12c67af 100644
 --- a/security/security.c
 +++ b/security/security.c
 @@ -407,6 +407,7 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry)
@@ -854,7 +929,7 @@ index 31614e9..b223a66 100644
  {
 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       2014-01-30 21:10:02.794146538 +0100
++++ linux/Documentation/ABI/testing/debugfs-aufs       2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,50 @@
 +What:         /debug/aufs/si_<id>/
 +Date:         March 2009
@@ -908,7 +983,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 2014-01-30 21:10:02.794146538 +0100
++++ linux/Documentation/ABI/testing/sysfs-aufs 2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,31 @@
 +What:         /sys/fs/aufs/si_<id>/
 +Date:         March 2009
@@ -943,7 +1018,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    2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/01intro.txt    2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,161 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1108,7 +1183,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   2014-08-14 10:15:45.115275734 +0200
++++ linux/Documentation/filesystems/aufs/design/02struct.txt   2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,251 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1363,7 +1438,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li
 +For this purpose, use "aumvdown" command in aufs-util.git.
 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   2014-08-14 10:15:45.118609182 +0200
++++ linux/Documentation/filesystems/aufs/design/03lookup.txt   2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,133 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1500,7 +1575,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   2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/04branch.txt   2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,75 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1579,7 +1654,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       2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt       2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,64 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1647,7 +1722,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.tx
 +  copyup policy.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt linux/Documentation/filesystems/aufs/design/06fhsm.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/06fhsm.txt     2014-08-14 10:15:45.118609182 +0200
++++ linux/Documentation/filesystems/aufs/design/06fhsm.txt     2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,120 @@
 +
 +# Copyright (C) 2011-2014 Junjiro R. Okajima
@@ -1771,7 +1846,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt linu
 +should restore the original file state after an error happens.
 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     2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/06mmap.txt     2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,46 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1819,9 +1894,109 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linu
 +generic_file_mmap() and handles struct vm_operations_struct. In this
 +approach, aufs met a hard problem and I could not solve it without
 +switching the approach.
+diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06xattr.txt linux/Documentation/filesystems/aufs/design/06xattr.txt
+--- /usr/share/empty/Documentation/filesystems/aufs/design/06xattr.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux/Documentation/filesystems/aufs/design/06xattr.txt    2015-01-25 13:00:38.627713742 +0100
+@@ -0,0 +1,96 @@
++
++# Copyright (C) 2014 Junjiro R. Okajima
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++
++
++Listing XATTR/EA and getting the value
++----------------------------------------------------------------------
++For the inode standard attributes (owner, group, timestamps, etc.), aufs
++shows the values from the topmost existing file. This behaviour is good
++for the non-dir entreis since the bahaviour exactly matches the shown
++information. But for the directories, aufs considers all the same named
++entries on the lower branches. Which means, if one of the lower entry
++rejects readdir call, then aufs returns an error even if the topmost
++entry allows it. This behaviour is necessary to respect the branch fs's
++security, but can make users confused since the user-visible standard
++attributes don't match the behaviour.
++To address this issue, aufs has a mount option called dirperm1 which
++checks the permission for the topmost entry only, and ignores the lower
++entry's permission.
++
++A similar issue can happen around XATTR.
++getxattr(2) and listxattr(2) families behave as if dirperm1 option is
++always set. Otherwise these very unpleasant situation can happen.
++- listxattr(2) may return the duplicated entires.
++- users may not be able to remove or reset the XATTR forever,
++
++
++XATTR/EA support in the internal (copy,move)-(up,down)
++----------------------------------------------------------------------
++Generally the extended attributes of inode are categorazied as these.
++- "security" for LSM and capability.
++- "system" for posix ACL, 'acl' mount option is required for the branch
++  fs generally.
++- "trusted" for userspace, CAP_SYS_ADMIN is required.
++- "user" for userspace, 'user_xattr' mount option is required for the
++  branch fs generally.
++
++Moreover there are some other categories. Aufs handles these rather
++unpopular categories as the ordinary ones, ie. there is no special
++condition nor exception.
++
++In copy-up, the support for XATTR on the dst branch may differ from the
++src branch. In this case, the copy-up operation will get an error and
++the original user operation which triggered the copy-up fails. It can
++happen that even all copy-up will fail.
++When both of src and dst branches support XATTR and if an error occurs
++during copying XATTR, then the copy-up should fail obviously. That is a
++good reason and aufs should return an error to userspace. But when only
++the src branch support XATTR, aufs should not return an error.
++For example, the src branch supports ACL but the dst branch doesn't
++because the dst branch may natively un-support it or temporary
++un-support it due to "noacl" mount option. Of course, the dst branch fs
++may NOT return an error even if the XATTR is not supported. It is
++totally up to the branch fs.
++
++Anyway when the aufs internal copy-up gets an error from the dst branch
++fs, then aufs tries removing the just copied entry and returns the error
++to the userspace. The worst case of this situation will be all copy-up
++will fail.
++
++For the copy-up operation, there two basic approaches.
++- copy the specified XATTR only (by category above), and return the
++  error if it happens inconditionally.
++- copy all XATTR, and ignore the error on the specified category only.
++
++In order to support XATTR and to implement the correct behaviour, aufs
++chooses the latter approach and introduces some attributes for its
++branch, "icexsec", "icexsys", "icextr", "icexusr", and "icexoth".
++They correspond to the XATTR namespaces (see above). Additionally, to be
++convenient, "icex" is also provided which means all "ix*" attributes are
++set.
++
++The meaning of these attributes is to ignore the error from setting
++XATTR on that branch.
++Note that aufs tries copying all XATTR unconditionally, and ignores the
++error from the dst branch according to the specified attributes.
++
++Some XATTR may have its default value. The default value may come from
++the parent dir or the environment. If the default value is set at the
++file creating-time, it will be overwritten by copy-up.
++Some contradiction may happen I am afraid.
++Do we need another attribute to stop copying XATTR? I am unsure. For
++now, aufs implements the branch attributes to ignore the error.
 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   2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/07export.txt   2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,58 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1883,7 +2058,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     2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/08shwh.txt     2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,52 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -1939,7 +2114,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    2014-01-30 21:10:02.807480310 +0100
++++ linux/Documentation/filesystems/aufs/design/10dynop.txt    2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,46 @@
 +
 +# Copyright (C) 2010-2014 Junjiro R. Okajima
@@ -1989,7 +2164,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     2014-08-14 10:15:45.118609182 +0200
++++ linux/Documentation/filesystems/aufs/design/99plan.txt     2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,58 @@
 +
 +# Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -2051,7 +2226,7 @@ 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        2014-08-14 10:15:45.115275734 +0200
++++ linux/Documentation/filesystems/aufs/README        2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,370 @@
 +
 +Aufs3 -- advanced multi layered unification filesystem version 3.x
@@ -2425,7 +2600,7 @@ 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       2014-01-30 21:10:02.827480967 +0100
++++ linux/fs/aufs/aufs.h       2015-01-25 13:00:38.627713742 +0100
 @@ -0,0 +1,59 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -2488,8 +2663,8 @@ 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     2014-08-14 10:16:04.512608923 +0200
-@@ -0,0 +1,1447 @@
++++ linux/fs/aufs/branch.c     2015-01-25 13:00:38.627713742 +0100
+@@ -0,0 +1,1410 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -2518,34 +2693,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +/*
 + * free a single branch
 + */
-+
-+/* prohibit rmdir to the root of the branch */
-+/* todo: another new flag? */
-+static void au_br_dflags_force(struct au_branch *br)
-+{
-+      struct dentry *h_dentry;
-+
-+      h_dentry = au_br_dentry(br);
-+      spin_lock(&h_dentry->d_lock);
-+      br->br_dflags = h_dentry->d_flags & DCACHE_MOUNTED;
-+      h_dentry->d_flags |= DCACHE_MOUNTED;
-+      spin_unlock(&h_dentry->d_lock);
-+}
-+
-+/* restore its d_flags */
-+static void au_br_dflags_restore(struct au_branch *br)
-+{
-+      struct dentry *h_dentry;
-+
-+      if (br->br_dflags)
-+              return;
-+
-+      h_dentry = au_br_dentry(br);
-+      spin_lock(&h_dentry->d_lock);
-+      h_dentry->d_flags &= ~DCACHE_MOUNTED;
-+      spin_unlock(&h_dentry->d_lock);
-+}
-+
 +static void au_br_do_free(struct au_branch *br)
 +{
 +      int i;
@@ -2580,8 +2727,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +              else
 +                      break;
 +
-+      au_br_dflags_restore(br);
-+
 +      /* recursive lock, s_umount of branch's */
 +      lockdep_off();
 +      path_put(&br->br_path);
@@ -2768,6 +2913,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +              goto out;
 +      }
 +
++      if (unlikely(inode->i_sb->s_stack_depth)) {
++              pr_err("already stacked, %s (%s)\n",
++                     add->pathname, au_sbtype(inode->i_sb));
++              goto out;
++      }
++
 +      err = test_br(add->path.dentry->d_inode, add->perm, add->pathname);
 +      if (unlikely(err))
 +              goto out;
@@ -2885,7 +3036,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +      return err;
 +}
 +
-+/* intialize a new branch */
++/* initialize a new branch */
 +static int au_br_init(struct au_branch *br, struct super_block *sb,
 +                    struct au_opt_add *add)
 +{
@@ -2895,9 +3046,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +      memset(&br->br_xino, 0, sizeof(br->br_xino));
 +      mutex_init(&br->br_xino.xi_nondir_mtx);
 +      br->br_perm = add->perm;
-+      BUILD_BUG_ON(sizeof(br->br_dflags)
-+                   != sizeof(br->br_path.dentry->d_flags));
-+      br->br_dflags = DCACHE_MOUNTED;
 +      br->br_path = add->path; /* set first, path_get() later */
 +      spin_lock_init(&br->br_dykey_lock);
 +      memset(br->br_dykey, 0, sizeof(br->br_dykey));
@@ -2985,8 +3133,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +      struct inode *root_inode;
 +      aufs_bindex_t bend, amount;
 +
-+      au_br_dflags_force(br);
-+
 +      root = sb->s_root;
 +      root_inode = root->d_inode;
 +      bend = au_sbend(sb);
@@ -3161,7 +3307,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +              ndentry = dpage->ndentry;
 +              for (j = 0; !err && j < ndentry; j++) {
 +                      d = dpage->dentries[j];
-+                      AuDebugOn(!d_count(d));
++                      AuDebugOn(au_dcount(d) <= 0);
 +                      if (!au_digen_test(d, sigen)) {
 +                              di_read_lock_child(d, AuLock_IR);
 +                              if (unlikely(au_dbrange_test(d))) {
@@ -3281,14 +3427,21 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +                       struct file **to_free, int *idx)
 +{
 +      int err;
-+      unsigned char matched, unmatched;
++      unsigned char matched, root;
 +      aufs_bindex_t bindex, bend;
 +      struct au_fidir *fidir;
 +      struct au_hfile *hfile;
 +
 +      err = 0;
++      root = IS_ROOT(file->f_dentry);
++      if (root) {
++              get_file(file);
++              to_free[*idx] = file;
++              (*idx)++;
++              goto out;
++      }
++
 +      matched = 0;
-+      unmatched = 0;
 +      fidir = au_fi(file)->fi_hdir;
 +      AuDebugOn(!fidir);
 +      bend = au_fbend_dir(file);
@@ -3297,21 +3450,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +              if (!hfile->hf_file)
 +                      continue;
 +
-+              if (hfile->hf_br->br_id == br_id)
++              if (hfile->hf_br->br_id == br_id) {
 +                      matched = 1;
-+              else
-+                      unmatched = 1;
-+              if (matched && unmatched)
 +                      break;
++              }
 +      }
-+      if (!matched)
-+              goto out; /* success */
-+
-+      if (unmatched) {
-+              get_file(file);
-+              to_free[*idx] = file;
-+              (*idx)++;
-+      } else
++      if (matched)
 +              err = -EBUSY;
 +
 +out:
@@ -3903,12 +4047,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +              /* non-fhsm --> fhsm */
 +              br->br_fhsm = bf;
 +
-+      if ((br->br_perm & AuBrAttr_UNPIN)
-+          && !(mod->perm & AuBrAttr_UNPIN))
-+              au_br_dflags_force(br);
-+      else if (!(br->br_perm & AuBrAttr_UNPIN)
-+               && (mod->perm & AuBrAttr_UNPIN))
-+              au_br_dflags_restore(br);
 +      *do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
 +      br->br_perm = mod->perm;
 +      goto out; /* success */
@@ -3939,8 +4077,8 @@ 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     2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,268 @@
++++ linux/fs/aufs/branch.h     2015-01-25 13:00:38.627713742 +0100
+@@ -0,0 +1,267 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -4039,7 +4177,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 +      aufs_bindex_t           br_id;
 +
 +      int                     br_perm;
-+      unsigned int            br_dflags;
 +      struct path             br_path;
 +      spinlock_t              br_dykey_lock;
 +      struct au_dykey         *br_dykey[AuBrDynOp];
@@ -4211,8 +4348,8 @@ 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      2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,37 @@
++++ linux/fs/aufs/conf.mk      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,38 @@
 +
 +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
 +
@@ -4226,6 +4363,7 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk
 +      SBILIST \
 +      HNOTIFY HFSNOTIFY \
 +      EXPORT INO_T_64 \
++      XATTR \
 +      FHSM \
 +      RDU \
 +      SHWH \
@@ -4252,8 +4390,8 @@ 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       2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,1301 @@
++++ linux/fs/aufs/cpup.c       2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,1303 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -4421,15 +4559,17 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
 +             struct au_cpup_reg_attr *h_src_attr)
 +{
-+      int err, sbits;
++      int err, sbits, icex;
 +      struct iattr ia;
 +      struct path h_path;
 +      struct inode *h_isrc, *h_idst;
 +      struct kstat *h_st;
++      struct au_branch *br;
 +
 +      h_path.dentry = au_h_dptr(dst, bindex);
 +      h_idst = h_path.dentry->d_inode;
-+      h_path.mnt = au_sbr_mnt(dst->d_sb, bindex);
++      br = au_sbr(dst->d_sb, bindex);
++      h_path.mnt = au_br_mnt(br);
 +      h_isrc = h_src->d_inode;
 +      ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
 +              | ATTR_ATIME | ATTR_MTIME
@@ -4470,6 +4610,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL);
 +      }
 +
++      icex = br->br_perm & AuBrAttr_ICEX;
++      if (!err)
++              err = au_cpup_xattr(h_path.dentry, h_src, icex);
++
 +      return err;
 +}
 +
@@ -5377,7 +5521,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +{
 +      int err, wkq_err;
 +      aufs_bindex_t bdst;
-+      struct dentry *dentry, *parent, *h_orph, *h_parent, *h_dentry;
++      struct dentry *dentry, *parent, *h_orph, *h_parent;
 +      struct inode *dir, *h_dir, *h_tmpdir;
 +      struct au_wbr *wbr;
 +      struct au_pin wh_pin, *pin_orig;
@@ -5400,10 +5544,6 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              h_tmpdir = h_orph->d_inode;
 +              au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
 +
-+              if (file)
-+                      h_dentry = au_hf_top(file)->f_dentry;
-+              else
-+                      h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
 +              mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
 +              /* todo: au_h_open_pre()? */
 +
@@ -5557,7 +5697,7 @@ 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       2014-01-30 21:10:02.827480967 +0100
++++ linux/fs/aufs/cpup.h       2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,94 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -5655,7 +5795,7 @@ 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    2014-01-30 21:10:02.827480967 +0100
++++ linux/fs/aufs/dbgaufs.c    2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,432 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -5990,7 +6130,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 +      int err;
 +
 +      /*
-+       * This function is a dynamic '__init' fucntion actually,
++       * This function is a dynamic '__init' function actually,
 +       * so the tiny check for si_rwsem is unnecessary.
 +       */
 +      /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
@@ -6016,7 +6156,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 +void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
 +{
 +      /*
-+       * This function is a dynamic '__init' fucntion actually,
++       * This function is a dynamic '__init' function actually,
 +       * so the tiny check for si_rwsem is unnecessary.
 +       */
 +      /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
@@ -6032,7 +6172,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 +      char name[SysaufsSiNameLen];
 +
 +      /*
-+       * This function is a dynamic '__init' fucntion actually,
++       * This function is a dynamic '__init' function actually,
 +       * so the tiny check for si_rwsem is unnecessary.
 +       */
 +      /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
@@ -6091,7 +6231,7 @@ 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    2014-01-30 21:10:02.827480967 +0100
++++ linux/fs/aufs/dbgaufs.h    2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,48 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -6143,8 +6283,8 @@ 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      2014-01-30 21:10:02.827480967 +0100
-@@ -0,0 +1,243 @@
++++ linux/fs/aufs/dcsub.c      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,224 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -6244,7 +6384,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +              dpages->ndpage++;
 +      }
 +
-+      AuDebugOn(!d_count(dentry));
++      AuDebugOn(au_dcount(dentry) <= 0);
 +      dpage->dentries[dpage->ndentry++] = dget_dlock(dentry);
 +      return 0; /* success */
 +
@@ -6252,79 +6392,60 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +      return err;
 +}
 +
-+/* try d_walk() in linux/fs/dcache.c */
-+int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
-+                 au_dpages_test test, void *arg)
-+{
++/* todo: BAD approach */
++/* copied from linux/fs/dcache.c */
++enum d_walk_ret {
++      D_WALK_CONTINUE,
++      D_WALK_QUIT,
++      D_WALK_NORETRY,
++      D_WALK_SKIP,
++};
++
++extern void d_walk(struct dentry *parent, void *data,
++                 enum d_walk_ret (*enter)(void *, struct dentry *),
++                 void (*finish)(void *));
++
++struct ac_dpages_arg {
 +      int err;
-+      struct dentry *this_parent;
-+      struct list_head *next;
-+      struct super_block *sb = root->d_sb;
++      struct au_dcsub_pages *dpages;
++      struct super_block *sb;
++      au_dpages_test test;
++      void *arg;
++};
 +
-+      err = 0;
-+      write_seqlock(&rename_lock);
-+      this_parent = root;
-+      spin_lock(&this_parent->d_lock);
-+repeat:
-+      next = this_parent->d_subdirs.next;
-+resume:
-+      if (this_parent->d_sb == sb
-+          && !IS_ROOT(this_parent)
-+          && au_di(this_parent)
-+          && d_count(this_parent)
-+          && (!test || test(this_parent, arg))) {
-+              err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
-+              if (unlikely(err))
-+                      goto out;
-+      }
++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry)
++{
++      enum d_walk_ret ret;
++      struct ac_dpages_arg *arg = _arg;
 +
-+      while (next != &this_parent->d_subdirs) {
-+              struct list_head *tmp = next;
-+              struct dentry *dentry = list_entry(tmp, struct dentry,
-+                                                 d_u.d_child);
-+
-+              next = tmp->next;
-+              spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-+              if (d_count(dentry)) {
-+                      if (!list_empty(&dentry->d_subdirs)) {
-+                              spin_unlock(&this_parent->d_lock);
-+                              spin_release(&dentry->d_lock.dep_map, 1,
-+                                           _RET_IP_);
-+                              this_parent = dentry;
-+                              spin_acquire(&this_parent->d_lock.dep_map, 0, 1,
-+                                           _RET_IP_);
-+                              goto repeat;
-+                      }
-+                      if (dentry->d_sb == sb
-+                          && au_di(dentry)
-+                          && (!test || test(dentry, arg)))
-+                              err = au_dpages_append(dpages, dentry,
-+                                                     GFP_ATOMIC);
-+              }
-+              spin_unlock(&dentry->d_lock);
-+              if (unlikely(err))
-+                      goto out;
++      ret = D_WALK_CONTINUE;
++      if (dentry->d_sb == arg->sb
++          && !IS_ROOT(dentry)
++          && au_dcount(dentry) > 0
++          && au_di(dentry)
++          && (!arg->test || arg->test(dentry, arg->arg))) {
++              arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC);
++              if (unlikely(arg->err))
++                      ret = D_WALK_QUIT;
 +      }
 +
-+      if (this_parent != root) {
-+              struct dentry *tmp;
-+              struct dentry *child;
++      return ret;
++}
 +
-+              tmp = this_parent->d_parent;
-+              rcu_read_lock();
-+              spin_unlock(&this_parent->d_lock);
-+              child = this_parent;
-+              this_parent = tmp;
-+              spin_lock(&this_parent->d_lock);
-+              rcu_read_unlock();
-+              next = child->d_u.d_child.next;
-+              goto resume;
-+      }
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++                 au_dpages_test test, void *arg)
++{
++      struct ac_dpages_arg args = {
++              .err    = 0,
++              .dpages = dpages,
++              .sb     = root->d_sb,
++              .test   = test,
++              .arg    = arg
++      };
 +
-+out:
-+      spin_unlock(&this_parent->d_lock);
-+      write_sequnlock(&rename_lock);
-+      return err;
++      d_walk(root, &args, au_call_dpages_append, NULL);
++
++      return args.err;
 +}
 +
 +int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
@@ -6336,7 +6457,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +      write_seqlock(&rename_lock);
 +      spin_lock(&dentry->d_lock);
 +      if (do_include
-+          && d_count(dentry)
++          && au_dcount(dentry) > 0
 +          && (!test || test(dentry, arg)))
 +              err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
 +      spin_unlock(&dentry->d_lock);
@@ -6350,7 +6471,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +      while (!IS_ROOT(dentry)) {
 +              dentry = dentry->d_parent; /* rename_lock is locked */
 +              spin_lock(&dentry->d_lock);
-+              if (d_count(dentry)
++              if (au_dcount(dentry) > 0
 +                  && (!test || test(dentry, arg)))
 +                      err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
 +              spin_unlock(&dentry->d_lock);
@@ -6390,8 +6511,8 @@ 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      2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,120 @@
++++ linux/fs/aufs/dcsub.h      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,125 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -6510,12 +6631,17 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
 +              && !memcmp(a->name, b->name, a->len);
 +}
 +
++static inline int au_dcount(struct dentry *d)
++{
++      return (int)d_count(d);
++}
++
 +#endif /* __KERNEL__ */
 +#endif /* __AUFS_DCSUB_H__ */
 diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 --- /usr/share/empty/fs/aufs/debug.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/debug.c      2014-08-14 10:15:45.121942630 +0200
-@@ -0,0 +1,519 @@
++++ linux/fs/aufs/debug.c      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,520 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -6574,6 +6700,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +MODULE_PARM_DESC(debug, "debug print");
 +module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP);
 +
++DEFINE_MUTEX(au_dbg_mtx);     /* just to serialize the dbg msgs */
 +char *au_plevel = KERN_DEBUG;
 +#define dpri(fmt, ...) do {                                   \
 +      if ((au_plevel                                          \
@@ -6686,7 +6813,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +      struct dentry *d;
 +
 +      spin_lock(&inode->i_lock);
-+      hlist_for_each_entry(d, &inode->i_dentry, d_alias)
++      hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias)
 +              au_dpri_dentry(d);
 +      spin_unlock(&inode->i_lock);
 +}
@@ -6706,7 +6833,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +      dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n",
 +           bindex, dentry, dentry,
 +           dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
-+           d_count(dentry), dentry->d_flags,
++           au_dcount(dentry), dentry->d_flags,
 +           d_unhashed(dentry) ? "un" : "");
 +      hn = -1;
 +      if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) {
@@ -7037,8 +7164,8 @@ 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      2014-01-30 21:10:02.827480967 +0100
-@@ -0,0 +1,247 @@
++++ linux/fs/aufs/debug.h      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,262 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -7151,6 +7278,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
 +struct au_finfo;
 +struct dentry;
 +#ifdef CONFIG_AUFS_DEBUG
++extern struct mutex au_dbg_mtx;
 +extern char *au_plevel;
 +struct au_nhash;
 +void au_dpri_whlist(struct au_nhash *whlist);
@@ -7179,38 +7307,52 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
 +int __init au_debug_init(void);
 +void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
 +#define AuDbgWhlist(w) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#w "\n"); \
 +      au_dpri_whlist(w); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgVdir(v) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#v "\n"); \
 +      au_dpri_vdir(v); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgInode(i) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#i "\n"); \
 +      au_dpri_inode(i); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgDAlias(i) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#i "\n"); \
 +      au_dpri_dalias(i); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgDentry(d) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#d "\n"); \
 +      au_dpri_dentry(d); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgFile(f) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#f "\n"); \
 +      au_dpri_file(f); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgSb(sb) do { \
++      mutex_lock(&au_dbg_mtx); \
 +      AuDbg(#sb "\n"); \
 +      au_dpri_sb(sb); \
++      mutex_unlock(&au_dbg_mtx); \
 +} while (0)
 +
 +#define AuDbgSleep(sec) do { \
@@ -7288,8 +7430,8 @@ 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     2014-08-14 10:16:04.515942371 +0200
-@@ -0,0 +1,1094 @@
++++ linux/fs/aufs/dentry.c     2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,1096 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -8296,10 +8438,6 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +      if (unlikely(!au_di(dentry)))
 +              goto out;
 +
-+      inode = dentry->d_inode;
-+      if (inode && is_bad_inode(inode))
-+              goto out;
-+
 +      valid = 1;
 +      sb = dentry->d_sb;
 +      /*
@@ -8313,6 +8451,12 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +              AuTraceErr(err);
 +              goto out;
 +      }
++      inode = dentry->d_inode;
++      if (unlikely(inode && is_bad_inode(inode))) {
++              err = -EINVAL;
++              AuTraceErr(err);
++              goto out_dgrade;
++      }
 +      if (unlikely(au_dbrange_test(dentry))) {
 +              err = -EINVAL;
 +              AuTraceErr(err);
@@ -8331,7 +8475,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +      di_downgrade_lock(dentry, AuLock_IR);
 +
 +      err = -EINVAL;
-+      if (!(flags & LOOKUP_OPEN)
++      if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY))
 +          && inode
 +          && !(inode->i_state && I_LINKABLE)
 +          && (IS_DEADDIR(inode) || !inode->i_nlink))
@@ -8386,7 +8530,7 @@ 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     2014-08-14 10:15:45.121942630 +0200
++++ linux/fs/aufs/dentry.h     2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,233 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -8623,7 +8767,7 @@ 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      2014-08-14 10:15:45.121942630 +0200
++++ linux/fs/aufs/dinfo.c      2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,544 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -8945,7 +9089,7 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
 +              return NULL;
 +      AuDebugOn(bindex < 0);
 +      d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
-+      AuDebugOn(d && d_count(d) <= 0);
++      AuDebugOn(d && au_dcount(d) <= 0);
 +      return d;
 +}
 +
@@ -9171,7 +9315,7 @@ 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        2014-08-14 10:15:45.121942630 +0200
++++ linux/fs/aufs/dir.c        2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,645 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -9820,8 +9964,8 @@ 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        2014-01-30 21:10:02.830814411 +0100
-@@ -0,0 +1,136 @@
++++ linux/fs/aufs/dir.h        2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,130 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -9942,17 +10086,11 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
 +                       unsigned long arg);
 +#endif
 +#else
-+static inline long au_rdu_ioctl(struct file *file, unsigned int cmd,
-+                              unsigned long arg)
-+{
-+      return -EINVAL;
-+}
++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file,
++       unsigned int cmd, unsigned long arg)
 +#ifdef CONFIG_COMPAT
-+static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
-+                                     unsigned long arg)
-+{
-+      return -EINVAL;
-+}
++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file,
++       unsigned int cmd, unsigned long arg)
 +#endif
 +#endif
 +
@@ -9960,7 +10098,7 @@ 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      2014-01-30 21:10:02.830814411 +0100
++++ linux/fs/aufs/dynop.c      2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,379 @@
 +/*
 + * Copyright (C) 2010-2014 Junjiro R. Okajima
@@ -10222,7 +10360,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
 +/* ---------------------------------------------------------------------- */
 +/*
 + * Aufs prohibits O_DIRECT by defaut even if the branch supports it.
-+ * This behaviour is neccessary to return an error from open(O_DIRECT) instead
++ * This behaviour is necessary to return an error from open(O_DIRECT) instead
 + * of the succeeding I/O. The dio mount option enables O_DIRECT and makes
 + * open(O_DIRECT) always succeed, but the succeeding I/O may return an error.
 + * See the aufs manual in detail.
@@ -10343,7 +10481,7 @@ 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      2014-01-30 21:10:02.830814411 +0100
++++ linux/fs/aufs/dynop.h      2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,75 @@
 +/*
 + * Copyright (C) 2010-2014 Junjiro R. Okajima
@@ -10422,7 +10560,7 @@ 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     2014-01-30 21:10:02.830814411 +0100
++++ linux/fs/aufs/export.c     2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,831 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -10669,7 +10807,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +              dentry = d_find_alias(inode);
 +      else {
 +              spin_lock(&inode->i_lock);
-+              hlist_for_each_entry(d, &inode->i_dentry, d_alias) {
++              hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
 +                      spin_lock(&d->d_lock);
 +                      if (!au_test_anon(d)
 +                          && d->d_parent->d_inode->i_ino == dir_ino) {
@@ -11140,7 +11278,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +      ii_read_lock_child(inode);
 +      bindex = au_ibstart(inode);
 +      if (!dir) {
-+              dentry = d_find_alias(inode);
++              dentry = d_find_any_alias(inode);
 +              if (unlikely(!dentry))
 +                      goto out_unlock;
 +              AuDebugOn(au_test_anon(dentry));
@@ -11156,7 +11294,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +      ii_read_unlock(dir);
 +      if (unlikely(!h_dir))
 +              goto out_parent;
-+      h_parent = d_find_alias(h_dir);
++      h_parent = d_find_any_alias(h_dir);
 +      if (unlikely(!h_parent))
 +              goto out_hparent;
 +
@@ -11257,8 +11395,8 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +}
 diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 --- /usr/share/empty/fs/aufs/fhsm.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/fhsm.c       2014-08-14 10:15:45.121942630 +0200
-@@ -0,0 +1,410 @@
++++ linux/fs/aufs/fhsm.c       2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,426 @@
 +/*
 + * Copyright (C) 2011-2014 Junjiro R. Okajima
 + *
@@ -11287,6 +11425,34 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +#include <linux/statfs.h>
 +#include "aufs.h"
 +
++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb)
++{
++      struct au_sbinfo *sbinfo;
++      struct au_fhsm *fhsm;
++
++      SiMustAnyLock(sb);
++
++      sbinfo = au_sbi(sb);
++      fhsm = &sbinfo->si_fhsm;
++      AuDebugOn(!fhsm);
++      return fhsm->fhsm_bottom;
++}
++
++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex)
++{
++      struct au_sbinfo *sbinfo;
++      struct au_fhsm *fhsm;
++
++      SiMustWriteLock(sb);
++
++      sbinfo = au_sbi(sb);
++      fhsm = &sbinfo->si_fhsm;
++      AuDebugOn(!fhsm);
++      fhsm->fhsm_bottom = bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
 +static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br)
 +{
 +      struct au_br_fhsm *bf;
@@ -11360,8 +11526,6 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force)
 +{
 +      int err;
-+      unsigned char do_notify;
-+      aufs_bindex_t bend, blower;
 +      struct au_sbinfo *sbinfo;
 +      struct au_fhsm *fhsm;
 +      struct au_branch *br;
@@ -11372,19 +11536,8 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +
 +      sbinfo = au_sbi(sb);
 +      fhsm = &sbinfo->si_fhsm;
-+      if (!au_ftest_si(sbinfo, FHSM))
-+              return;
-+
-+      do_notify = 0;
-+      bend = au_sbend(sb);
-+      for (blower = bindex + 1; blower <= bend; blower++) {
-+              br = au_sbr(sb, blower);
-+              if (au_br_fhsm(br->br_perm)) {
-+                      do_notify = 1;
-+                      break;
-+              }
-+      }
-+      if (!do_notify)
++      if (!au_ftest_si(sbinfo, FHSM)
++          || fhsm->fhsm_bottom == bindex)
 +              return;
 +
 +      br = au_sbr(sb, bindex);
@@ -11405,7 +11558,7 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +      struct au_branch *br;
 +
 +      /* exclude the bottom */
-+      bend = au_sbend(sb);
++      bend = au_fhsm_bottom(sb);
 +      for (bindex = 0; bindex < bend; bindex++) {
 +              br = au_sbr(sb, bindex);
 +              if (au_br_fhsm(br->br_perm))
@@ -11459,7 +11612,7 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +      /* except the bottom branch */
 +      err = 0;
 +      nstbr = 0;
-+      bend = au_sbend(sb);
++      bend = au_fhsm_bottom(sb);
 +      for (bindex = 0; !err && bindex < bend; bindex++) {
 +              br = au_sbr(sb, bindex);
 +              if (!au_br_fhsm(br->br_perm))
@@ -11522,7 +11675,7 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +              AuDebugOn(!sb);
 +              /* exclude the bottom branch */
 +              nfhsm = 0;
-+              bend = au_sbend(sb);
++              bend = au_fhsm_bottom(sb);
 +              for (bindex = 0; bindex < bend; bindex++) {
 +                      br = au_sbr(sb, bindex);
 +                      if (au_br_fhsm(br->br_perm))
@@ -11650,6 +11803,7 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +      atomic_set(&fhsm->fhsm_readable, 0);
 +      fhsm->fhsm_expire
 +              = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC);
++      fhsm->fhsm_bottom = -1;
 +}
 +
 +void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec)
@@ -11671,8 +11825,8 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.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       2014-08-14 10:16:04.515942371 +0200
-@@ -0,0 +1,835 @@
++++ linux/fs/aufs/file.c       2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,829 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -12062,7 +12216,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +{
 +      int err;
 +      aufs_bindex_t dbstart;
-+      struct dentry *parent, *h_dentry;
++      struct dentry *parent;
 +      struct inode *inode;
 +      struct super_block *sb;
 +      struct file *h_file;
@@ -12105,13 +12259,9 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +      if (unlikely(err))
 +              goto out_dgrade;
 +
-+      h_dentry = au_hf_top(file)->f_dentry;
 +      dbstart = au_dbstart(cpg.dentry);
-+      if (dbstart <= cpg.bdst) {
-+              h_dentry = au_h_dptr(cpg.dentry, cpg.bdst);
-+              AuDebugOn(!h_dentry);
++      if (dbstart <= cpg.bdst)
 +              cpg.bsrc = cpg.bdst;
-+      }
 +
 +      if (dbstart <= cpg.bdst         /* just reopen */
 +          || !d_unhashed(cpg.dentry)  /* copyup and reopen */
@@ -12297,8 +12447,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +                      if (p->hf_file) {
 +                              if (file_inode(p->hf_file))
 +                                      break;
-+                              else
-+                                      au_hfput(p, file);
++                              au_hfput(p, file);
 +                      }
 +      } else {
 +              bend = au_br_index(sb, brid);
@@ -12315,8 +12464,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +              if (p->hf_file) {
 +                      if (file_inode(p->hf_file))
 +                              break;
-+                      else
-+                              au_hfput(p, file);
++                      au_hfput(p, file);
 +              }
 +      AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
 +}
@@ -12510,8 +12658,8 @@ 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       2014-08-14 10:15:45.121942630 +0200
-@@ -0,0 +1,289 @@
++++ linux/fs/aufs/file.h       2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,284 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -12609,13 +12757,8 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
 +                  struct file *h_file);
 +#else
-+static inline
-+struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex,
-+                         int force_wr)
-+{
-+      return NULL;
-+}
-+
++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry,
++       aufs_bindex_t bindex, int force_wr)
 +AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
 +         struct file *h_file);
 +#endif
@@ -12803,7 +12946,7 @@ 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      2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/finfo.c      2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,156 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -12963,7 +13106,7 @@ 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       2014-08-14 10:16:04.515942371 +0200
++++ linux/fs/aufs/f_op.c       2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,813 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -13177,7 +13320,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +      bstart = au_fbstart(file);
 +      h_file = au_hf_top(file);
 +      get_file(h_file);
-+      h_inode = h_file->f_dentry->d_inode;
++      h_inode = file_inode(h_file);
 +      blks = h_inode->i_blocks;
 +      au_unpin(&pin);
 +      di_read_unlock(dentry, AuLock_IR);
@@ -13306,7 +13449,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +      bstart = au_fbstart(file);
 +      h_file = au_hf_top(file);
 +      get_file(h_file);
-+      h_inode = h_file->f_dentry->d_inode;
++      h_inode = file_inode(h_file);
 +      blks = h_inode->i_blocks;
 +      au_unpin(&pin);
 +      di_read_unlock(dentry, AuLock_IR);
@@ -13402,7 +13545,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +      bstart = au_fbstart(file);
 +      h_file = au_hf_top(file);
 +      get_file(h_file);
-+      h_inode = h_file->f_dentry->d_inode;
++      h_inode = file_inode(h_file);
 +      blks = h_inode->i_blocks;
 +      au_unpin(&pin);
 +      di_read_unlock(dentry, AuLock_IR);
@@ -13780,7 +13923,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.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     2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/fstype.h     2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,469 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -14253,8 +14396,8 @@ 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  2014-08-14 10:16:04.515942371 +0200
-@@ -0,0 +1,281 @@
++++ linux/fs/aufs/hfsnotify.c  2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,288 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -14317,10 +14460,12 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +       * by udba rename or rmdir, aufs assign a new inode to the known
 +       * h_inode, so specify 1 to allow dups.
 +       */
++      lockdep_off();
 +      err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode,
 +                               /*mnt*/NULL, /*allow_dups*/1);
 +      /* even if err */
 +      fsnotify_put_mark(mark);
++      lockdep_on();
 +
 +      return err;
 +}
@@ -14339,8 +14484,10 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +      group = mark->group;
 +      fsnotify_get_group(group);
 +      spin_unlock(&mark->lock);
++      lockdep_off();
 +      fsnotify_destroy_mark(mark, group);
 +      fsnotify_put_group(group);
++      lockdep_on();
 +
 +      /* free hn by myself */
 +      return 0;
@@ -14467,8 +14614,11 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +      struct au_br_hfsnotify *hfsn;
 +
 +      hfsn = br->br_hfsn;
-+      if (hfsn)
++      if (hfsn) {
++              lockdep_off();
 +              fsnotify_put_group(hfsn->hfsn_group);
++              lockdep_on();
++      }
 +}
 +
 +static int au_hfsn_init_br(struct au_branch *br, int perm)
@@ -14538,7 +14688,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
 +};
 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    2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/hfsplus.c    2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,56 @@
 +/*
 + * Copyright (C) 2010-2014 Junjiro R. Okajima
@@ -14598,7 +14748,7 @@ 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    2014-08-14 10:16:04.515942371 +0200
++++ linux/fs/aufs/hnotify.c    2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,714 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -14813,7 +14963,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +              AuDebugOn(!name);
 +              au_iigen_dec(inode);
 +              spin_lock(&inode->i_lock);
-+              hlist_for_each_entry(d, &inode->i_dentry, d_alias) {
++              hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) {
 +                      spin_lock(&d->d_lock);
 +                      dname = &d->d_name;
 +                      if (dname->len != nlen
@@ -14829,7 +14979,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +              spin_unlock(&inode->i_lock);
 +      } else {
 +              au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
-+              d = d_find_alias(inode);
++              d = d_find_any_alias(inode);
 +              if (!d) {
 +                      au_iigen_dec(inode);
 +                      goto out;
@@ -14974,13 +15124,13 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +      struct dentry *dentry, *d, *parent;
 +      struct qstr *dname;
 +
-+      parent = d_find_alias(dir);
++      parent = d_find_any_alias(dir);
 +      if (!parent)
 +              return NULL;
 +
 +      dentry = NULL;
 +      spin_lock(&parent->d_lock);
-+      list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
++      list_for_each_entry(d, &parent->d_subdirs, d_child) {
 +              /* AuDbg("%pd\n", d); */
 +              spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
 +              dname = &d->d_name;
@@ -14990,7 +15140,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +                      au_digen_dec(d);
 +              else
 +                      goto cont_unlock;
-+              if (d_count(d)) {
++              if (au_dcount(d) > 0) {
 +                      dentry = dget_dlock(d);
 +                      spin_unlock(&d->d_lock);
 +                      break;
@@ -15316,7 +15466,7 @@ 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      2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/iinfo.c      2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,277 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -15597,8 +15747,8 @@ 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      2014-08-14 10:15:45.128609525 +0200
-@@ -0,0 +1,492 @@
++++ linux/fs/aufs/inode.c      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,496 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -15839,6 +15989,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
 +                                    au_igrab(h_dentry->d_inode), flags);
 +      }
 +      au_cpup_attr_all(inode, /*force*/1);
++      /*
++       * to force calling aufs_get_acl() every time,
++       * do not call cache_no_acl() for aufs inode.
++       */
 +
 +out:
 +      return err;
@@ -16093,8 +16247,8 @@ 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      2014-08-14 10:15:45.128609525 +0200
-@@ -0,0 +1,601 @@
++++ linux/fs/aufs/inode.h      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,667 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -16205,6 +16359,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +};
 +
 +void au_pin_hdir_unlock(struct au_pin *p);
++int au_pin_hdir_lock(struct au_pin *p);
 +int au_pin_hdir_relock(struct au_pin *p);
 +void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task);
 +void au_pin_hdir_acquire_nest(struct au_pin *p);
@@ -16275,6 +16430,29 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +         unsigned int udba, unsigned char flags) __must_check;
 +int au_do_pin(struct au_pin *pin) __must_check;
 +void au_unpin(struct au_pin *pin);
++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen);
++
++#define AuIcpup_DID_CPUP      1
++#define au_ftest_icpup(flags, name)   ((flags) & AuIcpup_##name)
++#define au_fset_icpup(flags, name) \
++      do { (flags) |= AuIcpup_##name; } while (0)
++#define au_fclr_icpup(flags, name) \
++      do { (flags) &= ~AuIcpup_##name; } while (0)
++
++struct au_icpup_args {
++      unsigned char flags;
++      unsigned char pin_flags;
++      aufs_bindex_t btgt;
++      unsigned int udba;
++      struct au_pin pin;
++      struct path h_path;
++      struct inode *h_inode;
++};
++
++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
++                   struct au_icpup_args *a);
++
++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path);
 +
 +/* i_op_add.c */
 +int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
@@ -16365,6 +16543,56 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
 +#endif /* CONFIG_PROC_FS */
 +
++#ifdef CONFIG_AUFS_XATTR
++/* xattr.c */
++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags);
++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size);
++ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value,
++                    size_t size);
++int aufs_setxattr(struct dentry *dentry, const char *name, const void *value,
++                size_t size, int flags);
++int aufs_removexattr(struct dentry *dentry, const char *name);
++
++/* void au_xattr_init(struct super_block *sb); */
++#else
++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src,
++         int ignore_flags);
++/* AuStubVoid(au_xattr_init, struct super_block *sb); */
++#endif
++
++#ifdef CONFIG_FS_POSIX_ACL
++struct posix_acl *aufs_get_acl(struct inode *inode, int type);
++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
++#endif
++
++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
++enum {
++      AU_XATTR_SET,
++      AU_XATTR_REMOVE,
++      AU_ACL_SET
++};
++
++struct au_srxattr {
++      int type;
++      union {
++              struct {
++                      const char      *name;
++                      const void      *value;
++                      size_t          size;
++                      int             flags;
++              } set;
++              struct {
++                      const char      *name;
++              } remove;
++              struct {
++                      struct posix_acl *acl;
++                      int             type;
++              } acl_set;
++      } u;
++};
++ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg);
++#endif
++
 +/* ---------------------------------------------------------------------- */
 +
 +/* lock subclass for iinfo */
@@ -16637,18 +16865,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +}
 +
 +#else
-+static inline
-+int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
-+              struct inode *inode __maybe_unused)
-+{
-+      return -EOPNOTSUPP;
-+}
-+
-+static inline struct au_hnotify *au_hn(struct au_hinode *hinode)
-+{
-+      return NULL;
-+}
-+
++AuStub(int, au_hn_alloc, return -EOPNOTSUPP,
++       struct au_hinode *hinode __maybe_unused,
++       struct inode *inode __maybe_unused)
++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode)
 +AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused)
 +AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
 +         int do_set __maybe_unused)
@@ -16698,8 +16918,8 @@ 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      2014-08-14 10:15:45.128609525 +0200
-@@ -0,0 +1,214 @@
++++ linux/fs/aufs/ioctl.c      2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,219 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -16824,6 +17044,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
 +{
 +      long err;
++      struct dentry *dentry;
 +
 +      switch (cmd) {
 +      case AUFS_CTL_RDU:
@@ -16844,7 +17065,11 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +              break;
 +
 +      case AUFS_CTL_FHSM_FD:
-+              err = au_fhsm_fd(file->f_dentry->d_sb, arg);
++              dentry = file->f_dentry;
++              if (IS_ROOT(dentry))
++                      err = au_fhsm_fd(dentry->d_sb, arg);
++              else
++                      err = -ENOTTY;
 +              break;
 +
 +      default:
@@ -16916,8 +17141,8 @@ 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   2014-08-14 10:15:45.121942630 +0200
-@@ -0,0 +1,885 @@
++++ linux/fs/aufs/i_op_add.c   2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,891 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -17462,7 +17687,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +                            dget(au_h_dptr(src_dentry, a->bsrc)));
 +              dget(a->h_path.dentry);
 +              au_set_h_dptr(dentry, a->bdst, NULL);
++              AuDbg("temporary d_inode...\n");
++              spin_lock(&dentry->d_lock);
 +              dentry->d_inode = src_dentry->d_inode; /* tmp */
++              spin_unlock(&dentry->d_lock);
 +              h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0);
 +              if (IS_ERR(h_file))
 +                      err = PTR_ERR(h_file);
@@ -17484,7 +17712,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +                              au_set_h_dptr(dentry, a->bdst,
 +                                            a->h_path.dentry);
 +              }
++              spin_lock(&dentry->d_lock);
 +              dentry->d_inode = NULL; /* restore */
++              spin_unlock(&dentry->d_lock);
++              AuDbg("temporary d_inode...done\n");
 +              au_set_h_dptr(dentry, a->bsrc, NULL);
 +              au_set_dbend(dentry, bend);
 +      } else {
@@ -17805,8 +18036,8 @@ 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       2014-08-14 10:15:45.121942630 +0200
-@@ -0,0 +1,1142 @@
++++ linux/fs/aufs/i_op.c       2015-01-25 13:00:38.631047076 +0100
+@@ -0,0 +1,1306 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -18012,14 +18243,25 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +      if (npositive) {
 +              inode = au_new_inode(dentry, /*must_new*/0);
-+              ret = (void *)inode;
-+      }
-+      if (IS_ERR(inode)) {
-+              inode = NULL;
-+              goto out_unlock;
++              if (IS_ERR(inode)) {
++                      ret = (void *)inode;
++                      inode = NULL;
++                      goto out_unlock;
++              }
 +      }
 +
++      if (inode)
++              atomic_inc(&inode->i_count);
 +      ret = d_splice_alias(inode, dentry);
++      if (IS_ERR(ret)
++          && PTR_ERR(ret) == -EIO
++          && inode
++          && S_ISDIR(inode->i_mode)) {
++              atomic_inc(&inode->i_count);
++              ret = d_materialise_unique(dentry, inode);
++              if (!IS_ERR(ret))
++                      ii_write_unlock(inode);
++      }
 +#if 0
 +      if (unlikely(d_need_lookup(dentry))) {
 +              spin_lock(&dentry->d_lock);
@@ -18027,10 +18269,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              spin_unlock(&dentry->d_lock);
 +      } else
 +#endif
-+      if (unlikely(IS_ERR(ret) && inode)) {
-+              ii_write_unlock(inode);
-+              iput(inode);
-+              inode = NULL;
++      if (inode) {
++              if (!IS_ERR(ret))
++                      iput(inode);
++              else {
++                      ii_write_unlock(inode);
++                      iput(inode);
++                      inode = NULL;
++              }
 +      }
 +
 +out_unlock:
@@ -18191,7 +18437,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              au_hn_imtx_unlock(p->hdir);
 +}
 +
-+static int au_pin_hdir_lock(struct au_pin *p)
++int au_pin_hdir_lock(struct au_pin *p)
 +{
 +      int err;
 +
@@ -18405,7 +18651,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 + * for ->setattr(), ia->ia_file is passed from ftruncate only.
 + */
 +/* todo: consolidate with do_refresh() and simple_reval_dpath() */
-+static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
 +{
 +      int err;
 +      struct inode *inode;
@@ -18425,25 +18671,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      return err;
 +}
 +
-+#define AuIcpup_DID_CPUP      1
-+#define au_ftest_icpup(flags, name)   ((flags) & AuIcpup_##name)
-+#define au_fset_icpup(flags, name) \
-+      do { (flags) |= AuIcpup_##name; } while (0)
-+#define au_fclr_icpup(flags, name) \
-+      do { (flags) &= ~AuIcpup_##name; } while (0)
-+
-+struct au_icpup_args {
-+      unsigned char flags;
-+      unsigned char pin_flags;
-+      aufs_bindex_t btgt;
-+      unsigned int udba;
-+      struct au_pin pin;
-+      struct path h_path;
-+      struct inode *h_inode;
-+};
-+
-+static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
-+                          struct au_icpup_args *a)
++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
++                   struct au_icpup_args *a)
 +{
 +      int err;
 +      loff_t sz;
@@ -18485,11 +18714,13 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +      a->h_path.dentry = au_h_dptr(dentry, bstart);
 +      a->h_inode = a->h_path.dentry->d_inode;
-+      mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
 +      sz = -1;
-+      if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode))
-+              sz = ia->ia_size;
-+      mutex_unlock(&a->h_inode->i_mutex);
++      if (ia && (ia->ia_valid & ATTR_SIZE)) {
++              mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++              if (ia->ia_size < i_size_read(a->h_inode))
++                      sz = ia->ia_size;
++              mutex_unlock(&a->h_inode->i_mutex);
++      }
 +
 +      hi_wh = NULL;
 +      if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) {
@@ -18671,6 +18902,99 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      return err;
 +}
 +
++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
++static int au_h_path_to_set_attr(struct dentry *dentry,
++                               struct au_icpup_args *a, struct path *h_path)
++{
++      int err;
++      struct super_block *sb;
++
++      sb = dentry->d_sb;
++      a->udba = au_opt_udba(sb);
++      /* no d_unlinked(), to set UDBA_NONE for root */
++      if (d_unhashed(dentry))
++              a->udba = AuOpt_UDBA_NONE;
++      if (a->udba != AuOpt_UDBA_NONE) {
++              AuDebugOn(IS_ROOT(dentry));
++              err = au_reval_for_attr(dentry, au_sigen(sb));
++              if (unlikely(err))
++                      goto out;
++      }
++      err = au_pin_and_icpup(dentry, /*ia*/NULL, a);
++      if (unlikely(err < 0))
++              goto out;
++
++      h_path->dentry = a->h_path.dentry;
++      h_path->mnt = au_sbr_mnt(sb, a->btgt);
++
++out:
++      return err;
++}
++
++ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg)
++{
++      int err;
++      struct path h_path;
++      struct super_block *sb;
++      struct au_icpup_args *a;
++      struct inode *inode, *h_inode;
++
++      inode = dentry->d_inode;
++      IMustLock(inode);
++
++      err = -ENOMEM;
++      a = kzalloc(sizeof(*a), GFP_NOFS);
++      if (unlikely(!a))
++              goto out;
++
++      sb = dentry->d_sb;
++      err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++      if (unlikely(err))
++              goto out_kfree;
++
++      h_path.dentry = NULL;   /* silence gcc */
++      di_write_lock_child(dentry);
++      err = au_h_path_to_set_attr(dentry, a, &h_path);
++      if (unlikely(err))
++              goto out_di;
++
++      mutex_unlock(&a->h_inode->i_mutex);
++      switch (arg->type) {
++      case AU_XATTR_SET:
++              err = vfsub_setxattr(h_path.dentry,
++                                   arg->u.set.name, arg->u.set.value,
++                                   arg->u.set.size, arg->u.set.flags);
++              break;
++      case AU_XATTR_REMOVE:
++              err = vfsub_removexattr(h_path.dentry, arg->u.remove.name);
++              break;
++      case AU_ACL_SET:
++              err = -EOPNOTSUPP;
++              h_inode = h_path.dentry->d_inode;
++              if (h_inode->i_op->set_acl)
++                      err = h_inode->i_op->set_acl(h_inode,
++                                                   arg->u.acl_set.acl,
++                                                   arg->u.acl_set.type);
++              break;
++      }
++      if (!err)
++              au_cpup_attr_timesizes(inode);
++
++      au_unpin(&a->pin);
++      if (unlikely(err))
++              au_update_dbstart(dentry);
++
++out_di:
++      di_write_unlock(dentry);
++      si_read_unlock(sb);
++out_kfree:
++      kfree(a);
++out:
++      AuTraceErr(err);
++      return err;
++}
++#endif
++
 +static void au_refresh_iattr(struct inode *inode, struct kstat *st,
 +                           unsigned int nlink)
 +{
@@ -18700,22 +19024,25 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      spin_unlock(&inode->i_lock);
 +}
 +
-+static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
-+                      struct dentry *dentry, struct kstat *st)
++/*
++ * common routine for aufs_getattr() and aufs_getxattr().
++ * returns zero or negative (an error).
++ * @dentry will be read-locked in success.
++ */
++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path)
 +{
 +      int err;
 +      unsigned int mnt_flags, sigen;
++      unsigned char udba_none;
 +      aufs_bindex_t bindex;
-+      unsigned char udba_none, positive;
 +      struct super_block *sb, *h_sb;
 +      struct inode *inode;
-+      struct path h_path;
 +
++      h_path->mnt = NULL;
++      h_path->dentry = NULL;
++
++      err = 0;
 +      sb = dentry->d_sb;
-+      inode = dentry->d_inode;
-+      err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
-+      if (unlikely(err))
-+              goto out;
 +      mnt_flags = au_mntflags(sb);
 +      udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
 +
@@ -18726,43 +19053,74 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              if (!err) {
 +                      di_read_lock_child(dentry, AuLock_IR);
 +                      err = au_dbrange_test(dentry);
-+                      if (unlikely(err))
-+                              goto out_unlock;
++                      if (unlikely(err)) {
++                              di_read_unlock(dentry, AuLock_IR);
++                              goto out;
++                      }
 +              } else {
 +                      AuDebugOn(IS_ROOT(dentry));
 +                      di_write_lock_child(dentry);
 +                      err = au_dbrange_test(dentry);
 +                      if (!err)
 +                              err = au_reval_for_attr(dentry, sigen);
-+                      di_downgrade_lock(dentry, AuLock_IR);
-+                      if (unlikely(err))
-+                              goto out_unlock;
++                      if (!err)
++                              di_downgrade_lock(dentry, AuLock_IR);
++                      else {
++                              di_write_unlock(dentry);
++                              goto out;
++                      }
 +              }
 +      } else
 +              di_read_lock_child(dentry, AuLock_IR);
 +
++      inode = dentry->d_inode;
 +      bindex = au_ibstart(inode);
-+      h_path.mnt = au_sbr_mnt(sb, bindex);
-+      h_sb = h_path.mnt->mnt_sb;
-+      if (!au_test_fs_bad_iattr(h_sb) && udba_none)
-+              goto out_fill; /* success */
++      h_path->mnt = au_sbr_mnt(sb, bindex);
++      h_sb = h_path->mnt->mnt_sb;
++      if (!force
++          && !au_test_fs_bad_iattr(h_sb)
++          && udba_none)
++              goto out; /* success */
 +
-+      h_path.dentry = NULL;
 +      if (au_dbstart(dentry) == bindex)
-+              h_path.dentry = dget(au_h_dptr(dentry, bindex));
++              h_path->dentry = au_h_dptr(dentry, bindex);
 +      else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) {
-+              h_path.dentry = au_plink_lkup(inode, bindex);
-+              if (IS_ERR(h_path.dentry))
-+                      goto out_fill; /* pretending success */
++              h_path->dentry = au_plink_lkup(inode, bindex);
++              if (IS_ERR(h_path->dentry))
++                      /* pretending success */
++                      h_path->dentry = NULL;
++              else
++                      dput(h_path->dentry);
 +      }
-+      /* illegally overlapped or something */
++
++out:
++      return err;
++}
++
++static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
++                      struct dentry *dentry, struct kstat *st)
++{
++      int err;
++      unsigned char positive;
++      struct path h_path;
++      struct inode *inode;
++      struct super_block *sb;
++
++      inode = dentry->d_inode;
++      sb = dentry->d_sb;
++      err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++      if (unlikely(err))
++              goto out;
++      err = au_h_path_getattr(dentry, /*force*/0, &h_path);
++      if (unlikely(err))
++              goto out_si;
 +      if (unlikely(!h_path.dentry))
++              /* illegally overlapped or something */
 +              goto out_fill; /* pretending success */
 +
 +      positive = !!h_path.dentry->d_inode;
 +      if (positive)
 +              err = vfs_getattr(&h_path, st);
-+      dput(h_path.dentry);
 +      if (!err) {
 +              if (positive)
 +                      au_refresh_iattr(inode, st,
@@ -18770,12 +19128,13 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              goto out_fill; /* success */
 +      }
 +      AuTraceErr(err);
-+      goto out_unlock;
++      goto out_di;
 +
 +out_fill:
 +      generic_fillattr(inode, st);
-+out_unlock:
++out_di:
 +      di_read_unlock(dentry, AuLock_IR);
++out_si:
 +      si_read_unlock(sb);
 +out:
 +      AuTraceErr(err);
@@ -18911,9 +19270,21 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +struct inode_operations aufs_symlink_iop = {
 +      .permission     = aufs_permission,
++#ifdef CONFIG_FS_POSIX_ACL
++      .get_acl        = aufs_get_acl,
++      .set_acl        = aufs_set_acl, /* unsupport for symlink? */
++#endif
++
 +      .setattr        = aufs_setattr,
 +      .getattr        = aufs_getattr,
 +
++#ifdef CONFIG_AUFS_XATTR
++      .setxattr       = aufs_setxattr,
++      .getxattr       = aufs_getxattr,
++      .listxattr      = aufs_listxattr,
++      .removexattr    = aufs_removexattr,
++#endif
++
 +      .readlink       = aufs_readlink,
 +      .follow_link    = aufs_follow_link,
 +      .put_link       = aufs_put_link,
@@ -18933,9 +19304,21 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      .rename         = aufs_rename,
 +
 +      .permission     = aufs_permission,
++#ifdef CONFIG_FS_POSIX_ACL
++      .get_acl        = aufs_get_acl,
++      .set_acl        = aufs_set_acl,
++#endif
++
 +      .setattr        = aufs_setattr,
 +      .getattr        = aufs_getattr,
 +
++#ifdef CONFIG_AUFS_XATTR
++      .setxattr       = aufs_setxattr,
++      .getxattr       = aufs_getxattr,
++      .listxattr      = aufs_listxattr,
++      .removexattr    = aufs_removexattr,
++#endif
++
 +      .update_time    = aufs_update_time,
 +      /* no support for atomic_open() */
 +
@@ -18944,14 +19327,26 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +struct inode_operations aufs_iop = {
 +      .permission     = aufs_permission,
++#ifdef CONFIG_FS_POSIX_ACL
++      .get_acl        = aufs_get_acl,
++      .set_acl        = aufs_set_acl,
++#endif
++
 +      .setattr        = aufs_setattr,
 +      .getattr        = aufs_getattr,
 +
++#ifdef CONFIG_AUFS_XATTR
++      .setxattr       = aufs_setxattr,
++      .getxattr       = aufs_getxattr,
++      .listxattr      = aufs_listxattr,
++      .removexattr    = aufs_removexattr,
++#endif
++
 +      .update_time    = aufs_update_time
 +};
 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   2014-08-14 10:15:45.121942630 +0200
++++ linux/fs/aufs/i_op_del.c   2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,507 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -19462,7 +19857,7 @@ 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   2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/i_op_ren.c   2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,1034 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -20500,8 +20895,8 @@ 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      2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,177 @@
++++ linux/fs/aufs/Kconfig      2015-01-25 13:00:38.627713742 +0100
+@@ -0,0 +1,185 @@
 +config AUFS_FS
 +      tristate "Aufs (Advanced multi layered unification filesystem) support"
 +      help
@@ -20591,6 +20986,14 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig
 +      /* typedef unsigned long/int __kernel_ino_t */
 +      /* alpha and s390x are int */
 +
++config AUFS_XATTR
++      bool "support for XATTR/EA (including Security Labels)"
++      help
++      If your branch fs supports XATTR/EA and you want to make them
++      available in aufs too, then enable this opsion and specify the
++      branch attributes for EA.
++      See detail in aufs.5.
++
 +config AUFS_FHSM
 +      bool "File-based Hierarchical Storage Management"
 +      help
@@ -20681,7 +21084,7 @@ 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       2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/loop.c       2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,145 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -20830,7 +21233,7 @@ 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       2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/loop.h       2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,52 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -20886,7 +21289,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     2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/magic.mk     2015-01-25 13:00:38.631047076 +0100
 @@ -0,0 +1,54 @@
 +
 +# defined in ${srctree}/fs/fuse/inode.c
@@ -20944,8 +21347,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     2014-08-14 10:15:45.118609182 +0200
-@@ -0,0 +1,42 @@
++++ linux/fs/aufs/Makefile     2015-01-25 13:00:38.627713742 +0100
+@@ -0,0 +1,44 @@
 +
 +include ${src}/magic.mk
 +ifeq (${CONFIG_AUFS_FS},m)
@@ -20982,6 +21385,8 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
 +aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
 +aufs-$(CONFIG_AUFS_EXPORT) += export.o
++aufs-$(CONFIG_AUFS_XATTR) += xattr.o
++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o
 +aufs-$(CONFIG_AUFS_FHSM) += fhsm.o
 +aufs-$(CONFIG_AUFS_POLL) += poll.o
 +aufs-$(CONFIG_AUFS_RDU) += rdu.o
@@ -20990,7 +21395,7 @@ 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     2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/module.c     2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,210 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -21204,7 +21609,7 @@ 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     2014-01-30 21:10:02.850815069 +0100
++++ linux/fs/aufs/module.h     2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,104 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -21312,8 +21717,8 @@ 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/mvdown.c linux/fs/aufs/mvdown.c
 --- /usr/share/empty/fs/aufs/mvdown.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/mvdown.c     2014-08-14 10:15:45.128609525 +0200
-@@ -0,0 +1,657 @@
++++ linux/fs/aufs/mvdown.c     2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,694 @@
 +/*
 + * Copyright (C) 2011-2014 Junjiro R. Okajima
 + *
@@ -21343,6 +21748,7 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +              struct dentry *h_parent;
 +              struct au_hinode *hdir;
 +              struct inode *h_dir, *h_inode;
++              struct au_pin pin;
 +      } info[AUFS_MVDOWN_NARRAY];
 +
 +      struct aufs_mvdown mvdown;
@@ -21351,7 +21757,6 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +      struct super_block *sb;
 +      aufs_bindex_t bopq, bwh, bfound;
 +      unsigned char rename_lock;
-+      struct au_pin pin;
 +};
 +
 +#define mvd_errno             mvdown.au_errno
@@ -21365,12 +21770,14 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +#define mvd_hdir_src          info[AUFS_MVDOWN_UPPER].hdir
 +#define mvd_h_src_dir         info[AUFS_MVDOWN_UPPER].h_dir
 +#define mvd_h_src_inode               info[AUFS_MVDOWN_UPPER].h_inode
++#define mvd_pin_src           info[AUFS_MVDOWN_UPPER].pin
 +
 +#define mvd_h_dst_sb          info[AUFS_MVDOWN_LOWER].h_sb
 +#define mvd_h_dst_parent      info[AUFS_MVDOWN_LOWER].h_parent
 +#define mvd_hdir_dst          info[AUFS_MVDOWN_LOWER].hdir
 +#define mvd_h_dst_dir         info[AUFS_MVDOWN_LOWER].h_dir
 +#define mvd_h_dst_inode               info[AUFS_MVDOWN_LOWER].h_inode
++#define mvd_pin_dst           info[AUFS_MVDOWN_LOWER].pin
 +
 +#define AU_MVD_PR(flag, ...) do {                     \
 +              if (flag)                               \
@@ -21447,22 +21854,44 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +
 +      a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc);
 +      a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst);
++      err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst,
++                   au_opt_udba(a->sb),
++                   AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++      AuTraceErr(err);
++      if (unlikely(err)) {
++              AU_MVD_PR(dmsg, "pin_dst failed\n");
++              goto out;
++      }
++
 +      if (a->mvd_h_src_sb != a->mvd_h_dst_sb) {
 +              a->rename_lock = 0;
-+              err = au_pin(&a->pin, a->dentry, a->mvd_bdst,
-+                           au_opt_udba(a->sb),
-+                           AuPin_MNT_WRITE | AuPin_DI_LOCKED);
-+              if (!err) {
-+                      a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
-+                      mutex_lock_nested(&a->mvd_h_src_dir->i_mutex,
-+                                        AuLsc_I_PARENT3);
-+              } else
-+                      AU_MVD_PR(dmsg, "pin failed\n");
-+              goto out;
++              au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
++                          AuLsc_DI_PARENT, AuLsc_I_PARENT3,
++                          au_opt_udba(a->sb),
++                          AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++              err = au_do_pin(&a->mvd_pin_src);
++              AuTraceErr(err);
++              a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
++              if (unlikely(err)) {
++                      AU_MVD_PR(dmsg, "pin_src failed\n");
++                      goto out_dst;
++              }
++              goto out; /* success */
 +      }
 +
-+      err = 0;
 +      a->rename_lock = 1;
++      au_pin_hdir_unlock(&a->mvd_pin_dst);
++      err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
++                   au_opt_udba(a->sb),
++                   AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++      AuTraceErr(err);
++      a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
++      if (unlikely(err)) {
++              AU_MVD_PR(dmsg, "pin_src failed\n");
++              au_pin_hdir_lock(&a->mvd_pin_dst);
++              goto out_dst;
++      }
++      au_pin_hdir_unlock(&a->mvd_pin_src);
 +      h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
 +                                 a->mvd_h_dst_parent, a->mvd_hdir_dst);
 +      if (h_trap) {
@@ -21471,7 +21900,20 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +                      err = (h_trap != a->mvd_h_dst_parent);
 +      }
 +      BUG_ON(err); /* it should never happen */
++      if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) {
++              err = -EBUSY;
++              AuTraceErr(err);
++              vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
++                                  a->mvd_h_dst_parent, a->mvd_hdir_dst);
++              au_pin_hdir_lock(&a->mvd_pin_src);
++              au_unpin(&a->mvd_pin_src);
++              au_pin_hdir_lock(&a->mvd_pin_dst);
++              goto out_dst;
++      }
++      goto out; /* success */
 +
++out_dst:
++      au_unpin(&a->mvd_pin_dst);
 +out:
 +      AuTraceErr(err);
 +      return err;
@@ -21479,12 +21921,16 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +
 +static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a)
 +{
-+      if (!a->rename_lock) {
-+              mutex_unlock(&a->mvd_h_src_dir->i_mutex);
-+              au_unpin(&a->pin);
-+      } else
++      if (!a->rename_lock)
++              au_unpin(&a->mvd_pin_src);
++      else {
 +              vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
 +                                  a->mvd_h_dst_parent, a->mvd_hdir_dst);
++              au_pin_hdir_lock(&a->mvd_pin_src);
++              au_unpin(&a->mvd_pin_src);
++              au_pin_hdir_lock(&a->mvd_pin_dst);
++      }
++      au_unpin(&a->mvd_pin_dst);
 +}
 +
 +/* copy-down the file */
@@ -21496,7 +21942,7 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +              .bdst   = a->mvd_bdst,
 +              .bsrc   = a->mvd_bsrc,
 +              .len    = -1,
-+              .pin    = &a->pin,
++              .pin    = &a->mvd_pin_dst,
 +              .flags  = AuCpup_DTIME | AuCpup_HOPEN
 +      };
 +
@@ -21555,8 +22001,6 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +
 +/*
 + * unlink the topmost h_dentry
-+ * Note: the target file MAY be modified by UDBA between this mutex_unlock() and
-+ *    mutex_lock() in vfs_unlink(). in this case, such changes may be lost.
 + */
 +static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a)
 +{
@@ -21629,6 +22073,8 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +      if (unlikely(err))
 +              goto out_unlock;
 +
++      AuDbg("%pd2, 0x%x, %d --> %d\n",
++            a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst);
 +      if (find_lower_writable(a) < 0)
 +              a->mvdown.flags |= AUFS_MVDOWN_BOTTOM;
 +
@@ -21664,7 +22110,7 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +      err = 0;
 +      plinked = !!au_opt_test(au_mntflags(a->sb), PLINK);
 +      if (au_dbstart(a->dentry) == a->mvd_bsrc
-+          && d_count(a->dentry) == 1
++          && au_dcount(a->dentry) == 1
 +          && atomic_read(&a->inode->i_count) == 1
 +          /* && a->mvd_h_src_inode->i_nlink == 1 */
 +          && (!plinked || !au_plink_test(a->inode))
@@ -21673,8 +22119,8 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +
 +      err = -EBUSY;
 +      AU_MVD_PR(dmsg,
-+                "b%d, d{b%d, c%u?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n",
-+                a->mvd_bsrc, au_dbstart(a->dentry), d_count(a->dentry),
++                "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n",
++                a->mvd_bsrc, au_dbstart(a->dentry), au_dcount(a->dentry),
 +                atomic_read(&a->inode->i_count), a->inode->i_nlink,
 +                a->mvd_h_src_inode->i_nlink,
 +                plinked, plinked ? au_plink_test(a->inode) : 0);
@@ -21942,13 +22388,9 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +      if (unlikely(err))
 +              goto out_parent;
 +
-+      AuDbgDentry(dentry);
-+      AuDbgInode(args->inode);
 +      err = au_do_mvdown(dmsg, args);
 +      if (unlikely(err))
 +              goto out_parent;
-+      AuDbgDentry(dentry);
-+      AuDbgInode(args->inode);
 +
 +      au_cpup_attr_timesizes(args->dir);
 +      au_cpup_attr_timesizes(args->inode);
@@ -21973,8 +22415,8 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +}
 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       2014-08-14 10:15:45.128609525 +0200
-@@ -0,0 +1,1790 @@
++++ linux/fs/aufs/opts.c       2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,1850 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -22027,6 +22469,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      Opt_verbose, Opt_noverbose,
 +      Opt_sum, Opt_nosum, Opt_wsum,
 +      Opt_dirperm1, Opt_nodirperm1,
++      Opt_acl, Opt_noacl,
 +      Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
 +};
 +
@@ -22134,6 +22577,15 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      {Opt_wbr_copyup, "copyup=%s"},
 +      {Opt_wbr_copyup, "copyup_policy=%s"},
 +
++      /* generic VFS flag */
++#ifdef CONFIG_FS_POSIX_ACL
++      {Opt_acl, "acl"},
++      {Opt_noacl, "noacl"},
++#else
++      {Opt_ignore_silent, "acl"},
++      {Opt_ignore_silent, "noacl"},
++#endif
++
 +      /* internal use for the scripts */
 +      {Opt_ignore_silent, "si=%s"},
 +
@@ -22195,8 +22647,15 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      /* general */
 +      {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG},
 +      {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL},
++      /* 'unpin' attrib is meaningless since linux-3.18-rc1 */
 +      {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN},
 +      {AuBrAttr_FHSM, AUFS_BRATTR_FHSM},
++      {AuBrAttr_ICEX, AUFS_BRATTR_ICEX},
++      {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC},
++      {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS},
++      {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR},
++      {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR},
++      {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH},
 +
 +      /* ro/rr branch */
 +      {AuBrRAttr_WH, AUFS_BRRATTR_WH},
@@ -22242,7 +22701,6 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      const char *p;
 +      char *q;
 +
-+      sz = 0;
 +      q = str->a;
 +      *q = 0;
 +      p = au_optstr(&perm, brattr);
@@ -22264,7 +22722,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +      } while (p);
 +
 +out:
-+      return sz;
++      return q - str->a;
 +}
 +
 +static int noinline_for_stack br_perm_val(char *perm)
@@ -22302,6 +22760,17 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              val &= ~AuBrRAttr_Mask;
 +              break;
 +      }
++
++      /*
++       * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs
++       * does not treat it as an error, just warning.
++       * this is a tiny guard for the user operation.
++       */
++      if (val & AuBrAttr_UNPIN) {
++              bad |= AuBrAttr_UNPIN;
++              val &= ~AuBrAttr_UNPIN;
++      }
++
 +      if (unlikely(bad)) {
 +              sz = au_do_optstr_br_attr(&attr, bad);
 +              AuDebugOn(!sz);
@@ -22691,6 +23160,12 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              case Opt_fhsm_sec:
 +                      AuDbg("fhsm_sec %u\n", opt->fhsm_second);
 +                      break;
++              case Opt_acl:
++                      AuLabel(acl);
++                      break;
++              case Opt_noacl:
++                      AuLabel(noacl);
++                      break;
 +              default:
 +                      BUG();
 +              }
@@ -23137,6 +23612,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              case Opt_wsum:
 +              case Opt_rdblk_def:
 +              case Opt_rdhash_def:
++              case Opt_acl:
++              case Opt_noacl:
 +                      err = 0;
 +                      opt->type = token;
 +                      break;
@@ -23406,6 +23883,13 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              au_fclr_opts(opts->flags, TRUNC_XIB);
 +              break;
 +
++      case Opt_acl:
++              sb->s_flags |= MS_POSIXACL;
++              break;
++      case Opt_noacl:
++              sb->s_flags &= ~MS_POSIXACL;
++              break;
++
 +      default:
 +              err = 0;
 +              break;
@@ -23556,8 +24040,17 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              skip = 0;
 +              h_dir = au_h_iptr(dir, bindex);
 +              br = au_sbr(sb, bindex);
-+              do_free = 0;
 +
++              if ((br->br_perm & AuBrAttr_ICEX)
++                  && !h_dir->i_op->listxattr)
++                      br->br_perm &= ~AuBrAttr_ICEX;
++#if 0
++              if ((br->br_perm & AuBrAttr_ICEX_SEC)
++                  && (au_br_sb(br)->s_flags & MS_NOSEC))
++                      br->br_perm &= ~AuBrAttr_ICEX_SEC;
++#endif
++
++              do_free = 0;
 +              wbr = br->br_wbr;
 +              if (wbr)
 +                      wbr_wh_read_lock(wbr);
@@ -23613,10 +24106,19 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
 +              }
 +      }
 +
-+      if (fhsm >= 2)
++      if (fhsm >= 2) {
 +              au_fset_si(sbinfo, FHSM);
-+      else
++              for (bindex = bend; bindex >= 0; bindex--) {
++                      br = au_sbr(sb, bindex);
++                      if (au_br_fhsm(br->br_perm)) {
++                              au_fhsm_set_bottom(sb, bindex);
++                              break;
++                      }
++              }
++      } else {
 +              au_fclr_si(sbinfo, FHSM);
++              au_fhsm_set_bottom(sb, -1);
++      }
 +
 +      return err;
 +}
@@ -23767,7 +24269,7 @@ 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       2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/opts.h       2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,213 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -23984,7 +24486,7 @@ 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      2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/plink.c      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,532 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -24520,7 +25022,7 @@ 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       2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/poll.c       2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,55 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -24577,9 +25079,112 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c
 +      AuTraceErr((int)mask);
 +      return mask;
 +}
+diff -urN /usr/share/empty/fs/aufs/posix_acl.c linux/fs/aufs/posix_acl.c
+--- /usr/share/empty/fs/aufs/posix_acl.c       1970-01-01 01:00:00.000000000 +0100
++++ linux/fs/aufs/posix_acl.c  2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,99 @@
++/*
++ * Copyright (C) 2014 Junjiro R. Okajima
++ *
++ * This program, aufs is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * posix acl operations
++ */
++
++#include <linux/fs.h>
++#include <linux/posix_acl.h>
++#include "aufs.h"
++
++struct posix_acl *aufs_get_acl(struct inode *inode, int type)
++{
++      struct posix_acl *acl;
++      int err;
++      aufs_bindex_t bindex;
++      struct inode *h_inode;
++      struct super_block *sb;
++
++      acl = NULL;
++      sb = inode->i_sb;
++      si_read_lock(sb, AuLock_FLUSH);
++      ii_read_lock_child(inode);
++      if (!(sb->s_flags & MS_POSIXACL))
++              goto out;
++
++      bindex = au_ibstart(inode);
++      h_inode = au_h_iptr(inode, bindex);
++      if (unlikely(!h_inode
++                   || ((h_inode->i_mode & S_IFMT)
++                       != (inode->i_mode & S_IFMT)))) {
++              err = au_busy_or_stale();
++              acl = ERR_PTR(err);
++              goto out;
++      }
++
++      /* always topmost only */
++      acl = get_acl(h_inode, type);
++
++out:
++      ii_read_unlock(inode);
++      si_read_unlock(sb);
++
++      AuTraceErrPtr(acl);
++      return acl;
++}
++
++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
++{
++      int err;
++      ssize_t ssz;
++      struct dentry *dentry;
++      struct au_srxattr arg = {
++              .type = AU_ACL_SET,
++              .u.acl_set = {
++                      .acl    = acl,
++                      .type   = type
++              },
++      };
++
++      mutex_lock(&inode->i_mutex);
++      if (inode->i_ino == AUFS_ROOT_INO)
++              dentry = dget(inode->i_sb->s_root);
++      else {
++              dentry = d_find_alias(inode);
++              if (!dentry)
++                      dentry = d_find_any_alias(inode);
++              if (!dentry) {
++                      pr_warn("cannot handle this inode, "
++                              "please report to aufs-users ML\n");
++                      err = -ENOENT;
++                      goto out;
++              }
++      }
++
++      ssz = au_srxattr(dentry, &arg);
++      dput(dentry);
++      err = ssz;
++      if (ssz >= 0)
++              err = 0;
++
++out:
++      mutex_unlock(&inode->i_mutex);
++      return err;
++}
 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     2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/procfs.c     2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,169 @@
 +/*
 + * Copyright (C) 2010-2014 Junjiro R. Okajima
@@ -24752,7 +25357,7 @@ 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        2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/rdu.c        2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,388 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -25144,7 +25749,7 @@ 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      2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/rwsem.h      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,191 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -25339,7 +25944,7 @@ 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     2014-08-14 10:15:45.128609525 +0200
++++ linux/fs/aufs/sbinfo.c     2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,353 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -25696,7 +26301,7 @@ 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        2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/spl.h        2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,111 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -25811,8 +26416,8 @@ 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      2014-08-14 10:15:45.131942973 +0200
-@@ -0,0 +1,1004 @@
++++ linux/fs/aufs/super.c      2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,1009 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -26052,8 +26657,11 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +              seq_printf(m, "," #str "=%u", val); \
 +} while (0)
 +
-+      /* lock free root dinfo */
 +      sb = dentry->d_sb;
++      if (sb->s_flags & MS_POSIXACL)
++              seq_puts(m, ",acl");
++
++      /* lock free root dinfo */
 +      si_noflush_read_lock(sb);
 +      sbinfo = au_sbi(sb);
 +      seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
@@ -26711,7 +27319,9 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +      sb->s_d_op = &aufs_dop;
 +      sb->s_magic = AUFS_SUPER_MAGIC;
 +      sb->s_maxbytes = 0;
++      sb->s_stack_depth = 1;
 +      au_export_init(sb);
++      /* au_xattr_init(sb); */
 +
 +      err = alloc_root(sb);
 +      if (unlikely(err)) {
@@ -26819,8 +27429,8 @@ 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      2014-08-14 10:15:45.131942973 +0200
-@@ -0,0 +1,642 @@
++++ linux/fs/aufs/super.h      2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,641 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -26907,8 +27517,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +      wait_queue_head_t       fhsm_wqh;
 +      atomic_t                fhsm_readable;
 +
-+      /* only this is protected by si_rwsem */
++      /* these are protected by si_rwsem */
 +      unsigned long           fhsm_expire;
++      aufs_bindex_t           fhsm_bottom;
 +#endif
 +};
 +
@@ -27155,6 +27766,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +void au_fhsm_wrote_all(struct super_block *sb, int force);
 +int au_fhsm_fd(struct super_block *sb, int oflags);
 +int au_fhsm_br_alloc(struct au_branch *br);
++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex);
 +void au_fhsm_fin(struct super_block *sb);
 +void au_fhsm_init(struct au_sbinfo *sbinfo);
 +void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec);
@@ -27164,8 +27776,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +         int force)
 +AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force)
 +AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags)
-+AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm);
-+AuStubInt0(au_fhsm_br_alloc, struct au_branch *br);
++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm)
++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br)
++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex)
 +AuStubVoid(au_fhsm_fin, struct super_block *sb)
 +AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo)
 +AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec)
@@ -27202,10 +27815,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +AuStubInt0(au_xigen_new, struct inode *inode)
 +AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
 +AuStubVoid(au_xigen_clr, struct super_block *sb)
-+static inline int au_busy_or_stale(void)
-+{
-+      return -EBUSY;
-+}
++AuStub(int, au_busy_or_stale, return -EBUSY, void)
 +#endif /* CONFIG_AUFS_EXPORT */
 +
 +/* ---------------------------------------------------------------------- */
@@ -27247,8 +27857,8 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
 +#else
 +AuStubVoid(au_sbilist_init, void)
-+AuStubVoid(au_sbilist_add, struct super_block*)
-+AuStubVoid(au_sbilist_del, struct super_block*)
++AuStubVoid(au_sbilist_add, struct super_block *sb)
++AuStubVoid(au_sbilist_del, struct super_block *sb)
 +AuStubVoid(au_sbilist_lock, void)
 +AuStubVoid(au_sbilist_unlock, void)
 +#define AuGFP_SBILIST GFP_NOFS
@@ -27259,7 +27869,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
 +{
 +      /*
-+       * This function is a dynamic '__init' fucntion actually,
++       * This function is a dynamic '__init' function actually,
 +       * so the tiny check for si_rwsem is unnecessary.
 +       */
 +      /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
@@ -27288,8 +27898,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +      bit = si_pid_bit();
 +      if (bit < PID_MAX_DEFAULT)
 +              return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
-+      else
-+              return si_pid_test_slow(sb);
++      return si_pid_test_slow(sb);
 +}
 +
 +static inline void si_pid_set(struct super_block *sb)
@@ -27465,7 +28074,7 @@ 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    2014-01-30 21:10:02.857481956 +0100
++++ linux/fs/aufs/sysaufs.c    2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,104 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -27573,8 +28182,8 @@ 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    2014-08-14 10:15:45.131942973 +0200
-@@ -0,0 +1,107 @@
++++ linux/fs/aufs/sysaufs.h    2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,101 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -27661,14 +28270,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h
 +#define sysaufs_attr_group    NULL
 +
 +AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb)
-+
-+static inline
-+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
-+                       char *buf)
-+{
-+      return 0;
-+}
-+
++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj,
++       struct attribute *attr, char *buf)
 +AuStubVoid(sysaufs_br_init, struct au_branch *br)
 +AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
 +AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
@@ -27684,7 +28287,7 @@ 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      2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/sysfs.c      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,372 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -28060,7 +28663,7 @@ 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      2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/sysrq.c      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,157 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -28221,7 +28824,7 @@ 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       2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/vdir.c       2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,889 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -29114,8 +29717,8 @@ 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      2014-08-14 10:16:04.515942371 +0200
-@@ -0,0 +1,782 @@
++++ linux/fs/aufs/vfsub.c      2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,796 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -29276,7 +29879,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      if (unlikely(err))
 +              goto out;
 +
++      lockdep_off();
 +      err = vfs_create(dir, path->dentry, mode, want_excl);
++      lockdep_on();
 +      if (!err) {
 +              struct path tmp = *path;
 +              int did;
@@ -29307,7 +29912,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      if (unlikely(err))
 +              goto out;
 +
++      lockdep_off();
 +      err = vfs_symlink(dir, path->dentry, symname);
++      lockdep_on();
 +      if (!err) {
 +              struct path tmp = *path;
 +              int did;
@@ -29338,7 +29945,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      if (unlikely(err))
 +              goto out;
 +
++      lockdep_off();
 +      err = vfs_mknod(dir, path->dentry, mode, dev);
++      lockdep_on();
 +      if (!err) {
 +              struct path tmp = *path;
 +              int did;
@@ -29464,7 +30073,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      if (unlikely(err))
 +              goto out;
 +
++      lockdep_off();
 +      err = vfs_mkdir(dir, path->dentry, mode);
++      lockdep_on();
 +      if (!err) {
 +              struct path tmp = *path;
 +              int did;
@@ -29710,9 +30321,11 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      int err, do_sio, wkq_err;
 +
 +      do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
-+      if (!do_sio)
++      if (!do_sio) {
++              lockdep_off();
 +              err = vfsub_mkdir(dir, path, mode);
-+      else {
++              lockdep_on();
++      } else {
 +              struct au_vfsub_mkdir_args args = {
 +                      .errp   = &err,
 +                      .dir    = dir,
@@ -29744,9 +30357,11 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      int err, do_sio, wkq_err;
 +
 +      do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
-+      if (!do_sio)
++      if (!do_sio) {
++              lockdep_off();
 +              err = vfsub_rmdir(dir, path);
-+      else {
++              lockdep_on();
++      } else {
 +              struct au_vfsub_rmdir_args args = {
 +                      .errp   = &err,
 +                      .dir    = dir,
@@ -29779,8 +30394,10 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +
 +      *a->errp = -EPERM;
 +      if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
++              lockdep_off();
 +              *a->errp = notify_change(a->path->dentry, a->ia,
 +                                       a->delegated_inode);
++              lockdep_on();
 +              if (!*a->errp)
 +                      vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
 +      }
@@ -29836,7 +30453,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +      struct dentry *d = a->path->dentry;
 +      struct inode *h_inode;
 +      const int stop_sillyrename = (au_test_nfs(d->d_sb)
-+                                    && d_count(d) == 1);
++                                    && au_dcount(d) == 1);
 +
 +      IMustLock(a->dir);
 +
@@ -29900,8 +30517,8 @@ 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      2014-08-14 10:15:45.131942973 +0200
-@@ -0,0 +1,284 @@
++++ linux/fs/aufs/vfsub.h      2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,310 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -29931,6 +30548,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +#include <linux/fs.h>
 +#include <linux/lglock.h>
 +#include <linux/mount.h>
++#include <linux/xattr.h>
 +#include "debug.h"
 +
 +/* copied from linux/fs/internal.h */
@@ -29944,7 +30562,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
 +/* reduce? gave up. */
 +enum {
-+      AuLsc_I_Begin = I_MUTEX_NONDIR2, /* 4 */
++      AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */
 +      AuLsc_I_PARENT,         /* lower inode, parent first */
 +      AuLsc_I_PARENT2,        /* copyup dirs */
 +      AuLsc_I_PARENT3,        /* copyup wh */
@@ -30184,11 +30802,36 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +int vfsub_unlink(struct inode *dir, struct path *path,
 +               struct inode **delegated_inode, int force);
 +
++/* ---------------------------------------------------------------------- */
++
++static inline int vfsub_setxattr(struct dentry *dentry, const char *name,
++                               const void *value, size_t size, int flags)
++{
++      int err;
++
++      lockdep_off();
++      err = vfs_setxattr(dentry, name, value, size, flags);
++      lockdep_on();
++
++      return err;
++}
++
++static inline int vfsub_removexattr(struct dentry *dentry, const char *name)
++{
++      int err;
++
++      lockdep_off();
++      err = vfs_removexattr(dentry, name);
++      lockdep_on();
++
++      return err;
++}
++
 +#endif /* __KERNEL__ */
 +#endif /* __AUFS_VFSUB_H__ */
 diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 --- /usr/share/empty/fs/aufs/wbr_policy.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wbr_policy.c 2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/wbr_policy.c 2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,765 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -30957,7 +31600,7 @@ 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      2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/whout.c      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,1056 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -31303,9 +31946,9 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +
 +/*
 + * returns tri-state,
-+ * minus: error, caller should print the mesage
++ * minus: error, caller should print the message
 + * zero: succuess
-+ * plus: error, caller should NOT print the mesage
++ * plus: error, caller should NOT print the message
 + */
 +static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr,
 +                              int do_plink, struct au_wh_base base[],
@@ -32017,7 +32660,7 @@ 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      2014-08-14 10:15:45.131942973 +0200
++++ linux/fs/aufs/whout.h      2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,85 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -32106,7 +32749,7 @@ 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        2014-08-14 10:16:04.515942371 +0200
++++ linux/fs/aufs/wkq.c        2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,213 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -32323,7 +32966,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +}
 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        2014-01-30 21:10:02.860815399 +0100
++++ linux/fs/aufs/wkq.h        2015-01-25 13:00:38.634380408 +0100
 @@ -0,0 +1,91 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -32416,10 +33059,348 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
 +
 +#endif /* __KERNEL__ */
 +#endif /* __AUFS_WKQ_H__ */
+diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c
+--- /usr/share/empty/fs/aufs/xattr.c   1970-01-01 01:00:00.000000000 +0100
++++ linux/fs/aufs/xattr.c      2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,334 @@
++/*
++ * Copyright (C) 2014 Junjiro R. Okajima
++ *
++ * This program, aufs is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * handling xattr functions
++ */
++
++#include <linux/xattr.h>
++#include "aufs.h"
++
++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags)
++{
++      if (!ignore_flags)
++              goto out;
++      switch (err) {
++      case -ENOMEM:
++      case -EDQUOT:
++              goto out;
++      }
++
++      if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) {
++              err = 0;
++              goto out;
++      }
++
++#define cmp(brattr, prefix) do {                                      \
++              if (!strncmp(name, XATTR_##prefix##_PREFIX,             \
++                           XATTR_##prefix##_PREFIX_LEN)) {            \
++                      if (ignore_flags & AuBrAttr_ICEX_##brattr)      \
++                              err = 0;                                \
++                      goto out;                                       \
++              }                                                       \
++      } while (0)
++
++      cmp(SEC, SECURITY);
++      cmp(SYS, SYSTEM);
++      cmp(TR, TRUSTED);
++      cmp(USR, USER);
++#undef cmp
++
++      if (ignore_flags & AuBrAttr_ICEX_OTH)
++              err = 0;
++
++out:
++      return err;
++}
++
++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
++
++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
++                          char *name, char **buf, unsigned int ignore_flags)
++{
++      int err;
++      ssize_t ssz;
++      struct inode *h_idst;
++
++      ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS);
++      err = ssz;
++      if (unlikely(err <= 0)) {
++              AuTraceErr(err);
++              if (err == -ENODATA
++                  || (err == -EOPNOTSUPP
++                      && (ignore_flags & au_xattr_out_of_list)))
++                      err = 0;
++              goto out;
++      }
++
++      /* unlock it temporary */
++      h_idst = h_dst->d_inode;
++      mutex_unlock(&h_idst->i_mutex);
++      err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0);
++      mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2);
++      if (unlikely(err)) {
++              AuDbg("%s, err %d\n", name, err);
++              err = au_xattr_ignore(err, name, ignore_flags);
++      }
++
++out:
++      return err;
++}
++
++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags)
++{
++      int err, unlocked, acl_access, acl_default;
++      ssize_t ssz;
++      struct inode *h_isrc, *h_idst;
++      char *value, *p, *o, *e;
++
++      /* try stopping to update the source inode while we are referencing */
++      /* there should not be the parent-child relation ship between them */
++      h_isrc = h_src->d_inode;
++      h_idst = h_dst->d_inode;
++      mutex_unlock(&h_idst->i_mutex);
++      mutex_lock_nested(&h_isrc->i_mutex, AuLsc_I_CHILD);
++      mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2);
++      unlocked = 0;
++
++      /* some filesystems don't list POSIX ACL, for example tmpfs */
++      ssz = vfs_listxattr(h_src, NULL, 0);
++      err = ssz;
++      if (unlikely(err < 0)) {
++              AuTraceErr(err);
++              if (err == -ENODATA
++                  || err == -EOPNOTSUPP)
++                      err = 0;        /* ignore */
++              goto out;
++      }
++
++      err = 0;
++      p = NULL;
++      o = NULL;
++      if (ssz) {
++              err = -ENOMEM;
++              p = kmalloc(ssz, GFP_NOFS);
++              o = p;
++              if (unlikely(!p))
++                      goto out;
++              err = vfs_listxattr(h_src, p, ssz);
++      }
++      mutex_unlock(&h_isrc->i_mutex);
++      unlocked = 1;
++      AuDbg("err %d, ssz %zd\n", err, ssz);
++      if (unlikely(err < 0))
++              goto out_free;
++
++      err = 0;
++      e = p + ssz;
++      value = NULL;
++      acl_access = 0;
++      acl_default = 0;
++      while (!err && p < e) {
++              acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS,
++                                     sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1);
++              acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT,
++                                      sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)
++                                      - 1);
++              err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags);
++              p += strlen(p) + 1;
++      }
++      AuTraceErr(err);
++      ignore_flags |= au_xattr_out_of_list;
++      if (!err && !acl_access) {
++              err = au_do_cpup_xattr(h_dst, h_src,
++                                     XATTR_NAME_POSIX_ACL_ACCESS, &value,
++                                     ignore_flags);
++              AuTraceErr(err);
++      }
++      if (!err && !acl_default) {
++              err = au_do_cpup_xattr(h_dst, h_src,
++                                     XATTR_NAME_POSIX_ACL_DEFAULT, &value,
++                                     ignore_flags);
++              AuTraceErr(err);
++      }
++
++      kfree(value);
++
++out_free:
++      kfree(o);
++out:
++      if (!unlocked)
++              mutex_unlock(&h_isrc->i_mutex);
++      AuTraceErr(err);
++      return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++enum {
++      AU_XATTR_LIST,
++      AU_XATTR_GET
++};
++
++struct au_lgxattr {
++      int type;
++      union {
++              struct {
++                      char    *list;
++                      size_t  size;
++              } list;
++              struct {
++                      const char      *name;
++                      void            *value;
++                      size_t          size;
++              } get;
++      } u;
++};
++
++static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg)
++{
++      ssize_t err;
++      struct path h_path;
++      struct super_block *sb;
++
++      sb = dentry->d_sb;
++      err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
++      if (unlikely(err))
++              goto out;
++      err = au_h_path_getattr(dentry, /*force*/1, &h_path);
++      if (unlikely(err))
++              goto out_si;
++      if (unlikely(!h_path.dentry))
++              /* illegally overlapped or something */
++              goto out_di; /* pretending success */
++
++      /* always topmost entry only */
++      switch (arg->type) {
++      case AU_XATTR_LIST:
++              err = vfs_listxattr(h_path.dentry,
++                                  arg->u.list.list, arg->u.list.size);
++              break;
++      case AU_XATTR_GET:
++              err = vfs_getxattr(h_path.dentry,
++                                 arg->u.get.name, arg->u.get.value,
++                                 arg->u.get.size);
++              break;
++      }
++
++out_di:
++      di_read_unlock(dentry, AuLock_IR);
++out_si:
++      si_read_unlock(sb);
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size)
++{
++      struct au_lgxattr arg = {
++              .type = AU_XATTR_LIST,
++              .u.list = {
++                      .list   = list,
++                      .size   = size
++              },
++      };
++
++      return au_lgxattr(dentry, &arg);
++}
++
++ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value,
++                    size_t size)
++{
++      struct au_lgxattr arg = {
++              .type = AU_XATTR_GET,
++              .u.get = {
++                      .name   = name,
++                      .value  = value,
++                      .size   = size
++              },
++      };
++
++      return au_lgxattr(dentry, &arg);
++}
++
++int aufs_setxattr(struct dentry *dentry, const char *name, const void *value,
++                size_t size, int flags)
++{
++      struct au_srxattr arg = {
++              .type = AU_XATTR_SET,
++              .u.set = {
++                      .name   = name,
++                      .value  = value,
++                      .size   = size,
++                      .flags  = flags
++              },
++      };
++
++      return au_srxattr(dentry, &arg);
++}
++
++int aufs_removexattr(struct dentry *dentry, const char *name)
++{
++      struct au_srxattr arg = {
++              .type = AU_XATTR_REMOVE,
++              .u.remove = {
++                      .name   = name
++              },
++      };
++
++      return au_srxattr(dentry, &arg);
++}
++
++/* ---------------------------------------------------------------------- */
++
++#if 0
++static size_t au_xattr_list(struct dentry *dentry, char *list, size_t list_size,
++                          const char *name, size_t name_len, int type)
++{
++      return aufs_listxattr(dentry, list, list_size);
++}
++
++static int au_xattr_get(struct dentry *dentry, const char *name, void *buffer,
++                      size_t size, int type)
++{
++      return aufs_getxattr(dentry, name, buffer, size);
++}
++
++static int au_xattr_set(struct dentry *dentry, const char *name,
++                      const void *value, size_t size, int flags, int type)
++{
++      return aufs_setxattr(dentry, name, value, size, flags);
++}
++
++static const struct xattr_handler au_xattr_handler = {
++      /* no prefix, no flags */
++      .list   = au_xattr_list,
++      .get    = au_xattr_get,
++      .set    = au_xattr_set
++      /* why no remove? */
++};
++
++static const struct xattr_handler *au_xattr_handlers[] = {
++      &au_xattr_handler
++};
++
++void au_xattr_init(struct super_block *sb)
++{
++      /* sb->s_xattr = au_xattr_handlers; */
++}
++#endif
 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       2014-08-14 10:16:04.515942371 +0200
-@@ -0,0 +1,1316 @@
++++ linux/fs/aufs/xino.c       2015-01-25 13:00:38.634380408 +0100
+@@ -0,0 +1,1318 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -33648,6 +34629,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +
 +      /* reset all */
 +      AuIOErr("failed creating xino(%d).\n", err);
++      au_xigen_clr(sb);
++      xino_clear_xib(sb);
 +
 +out:
 +      dput(parent);
@@ -33738,8 +34721,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +}
 diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/linux/aufs_type.h
 --- /usr/share/empty/include/uapi/linux/aufs_type.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/uapi/linux/aufs_type.h       2014-08-14 10:16:04.522609267 +0200
-@@ -0,0 +1,380 @@
++++ linux/include/uapi/linux/aufs_type.h       2015-01-25 13:00:38.637713742 +0100
+@@ -0,0 +1,419 @@
 +/*
 + * Copyright (C) 2005-2014 Junjiro R. Okajima
 + *
@@ -33781,7 +34764,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +
 +#include <linux/limits.h>
 +
-+#define AUFS_VERSION  "3.16-20140811"
++#define AUFS_VERSION  "3.18.1+-20150119"
 +
 +/* todo? move this to linux-2.6.19/include/magic.h */
 +#define AUFS_SUPER_MAGIC      ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -33863,6 +34846,12 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +#define AUFS_BRATTR_COO_ALL   "coo_all"
 +#define AUFS_BRATTR_FHSM      "fhsm"
 +#define AUFS_BRATTR_UNPIN     "unpin"
++#define AUFS_BRATTR_ICEX      "icex"
++#define AUFS_BRATTR_ICEX_SEC  "icexsec"
++#define AUFS_BRATTR_ICEX_SYS  "icexsys"
++#define AUFS_BRATTR_ICEX_TR   "icextr"
++#define AUFS_BRATTR_ICEX_USR  "icexusr"
++#define AUFS_BRATTR_ICEX_OTH  "icexoth"
 +#define AUFS_BRRATTR_WH               "wh"
 +#define AUFS_BRWATTR_NLWH     "nolwh"
 +#define AUFS_BRWATTR_MOO      "moo"
@@ -33878,29 +34867,62 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +
 +#define AuBrAttr_FHSM         (1 << 5)        /* file-based hsm */
 +#define AuBrAttr_UNPIN                (1 << 6)        /* rename-able top dir of
-+                                                 branch */
-+
-+#define AuBrRAttr_WH          (1 << 7)        /* whiteout-able */
++                                                 branch. meaningless since
++                                                 linux-3.18-rc1 */
++
++/* ignore error in copying XATTR */
++#define AuBrAttr_ICEX_SEC     (1 << 7)
++#define AuBrAttr_ICEX_SYS     (1 << 8)
++#define AuBrAttr_ICEX_TR      (1 << 9)
++#define AuBrAttr_ICEX_USR     (1 << 10)
++#define AuBrAttr_ICEX_OTH     (1 << 11)
++#define AuBrAttr_ICEX         (AuBrAttr_ICEX_SEC      \
++                               | AuBrAttr_ICEX_SYS    \
++                               | AuBrAttr_ICEX_TR     \
++                               | AuBrAttr_ICEX_USR    \
++                               | AuBrAttr_ICEX_OTH)
++
++#define AuBrRAttr_WH          (1 << 12)       /* whiteout-able */
 +#define AuBrRAttr_Mask                AuBrRAttr_WH
 +
-+#define AuBrWAttr_NoLinkWH    (1 << 8)        /* un-hardlinkable whiteouts */
-+#define AuBrWAttr_MOO         (1 << 9)        /* move-up on open */
++#define AuBrWAttr_NoLinkWH    (1 << 13)       /* un-hardlinkable whiteouts */
++#define AuBrWAttr_MOO         (1 << 14)       /* move-up on open */
 +#define AuBrWAttr_Mask                (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO)
 +
 +#define AuBrAttr_CMOO_Mask    (AuBrAttr_COO_Mask | AuBrWAttr_MOO)
 +
++/* #warning test userspace */
 +#ifdef __KERNEL__
 +#ifndef CONFIG_AUFS_FHSM
 +#undef AuBrAttr_FHSM
 +#define AuBrAttr_FHSM         0
 +#endif
++#ifndef CONFIG_AUFS_XATTR
++#undef        AuBrAttr_ICEX
++#define AuBrAttr_ICEX         0
++#undef        AuBrAttr_ICEX_SEC
++#define AuBrAttr_ICEX_SEC     0
++#undef        AuBrAttr_ICEX_SYS
++#define AuBrAttr_ICEX_SYS     0
++#undef        AuBrAttr_ICEX_TR
++#define AuBrAttr_ICEX_TR      0
++#undef        AuBrAttr_ICEX_USR
++#define AuBrAttr_ICEX_USR     0
++#undef        AuBrAttr_ICEX_OTH
++#define AuBrAttr_ICEX_OTH     0
++#endif
 +#endif
 +
 +/* the longest combination */
-+#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW           \
-+                             "+" AUFS_BRATTR_COO_REG  \
-+                             "+" AUFS_BRATTR_FHSM     \
-+                             "+" AUFS_BRATTR_UNPIN    \
++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */
++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW                   \
++                             "+" AUFS_BRATTR_COO_REG          \
++                             "+" AUFS_BRATTR_FHSM             \
++                             "+" AUFS_BRATTR_UNPIN            \
++                             "+" AUFS_BRATTR_ICEX_SEC \
++                             "+" AUFS_BRATTR_ICEX_SYS \
++                             "+" AUFS_BRATTR_ICEX_USR \
++                             "+" AUFS_BRATTR_ICEX_OTH \
 +                             "+" AUFS_BRWATTR_NLWH)
 +
 +typedef struct {
@@ -34120,7 +35142,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +#define AUFS_CTL_FHSM_FD      _IOW(AuCtlType, AuCtl_FHSM_FD, int)
 +
 +#endif /* __AUFS_TYPE_H__ */
-aufs3.16 loopback patch
+aufs3.18.1+ loopback patch
 
 diff --git a/drivers/block/loop.c b/drivers/block/loop.c
 index 30efd68..77b31b4 100644
@@ -34318,7 +35340,7 @@ index 90df5d6..cb91822 100644
        unsigned        lo_blocksize;
        void            *key_data; 
 diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
-index 24ced51..69fa5cc 100644
+index 3dd9138..63a424c 100644
 --- a/fs/aufs/f_op.c
 +++ b/fs/aufs/f_op.c
 @@ -367,7 +367,7 @@ static ssize_t aufs_splice_read(struct file *file, loff_t *ppos,
@@ -34380,10 +35402,10 @@ index da8b756..28cb7ea 100644
  
  #endif /* __KERNEL__ */
 diff --git a/fs/aufs/super.c b/fs/aufs/super.c
-index 45146eb..fccd7d6 100644
+index 2ec0b4f..65a6781 100644
 --- a/fs/aufs/super.c
 +++ b/fs/aufs/super.c
-@@ -809,7 +809,10 @@ static const struct super_operations aufs_sop = {
+@@ -812,7 +812,10 @@ static const struct super_operations aufs_sop = {
        .statfs         = aufs_statfs,
        .put_super      = aufs_put_super,
        .sync_fs        = aufs_sync_fs,
@@ -34396,10 +35418,10 @@ index 45146eb..fccd7d6 100644
  
  /* ---------------------------------------------------------------------- */
 diff --git a/include/linux/fs.h b/include/linux/fs.h
-index 2f32b35..f94f0e6 100644
+index aabcbba..1a634f5 100644
 --- a/include/linux/fs.h
 +++ b/include/linux/fs.h
-@@ -1561,6 +1561,10 @@ struct super_operations {
+@@ -1594,6 +1594,10 @@ struct super_operations {
        int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
        long (*nr_cached_objects)(struct super_block *, int);
        long (*free_cached_objects)(struct super_block *, long, int);
@@ -34410,3 +35432,259 @@ index 2f32b35..f94f0e6 100644
  };
  
  /*
+diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
+index 50777b5..f9c6b3d 100644
+--- a/include/linux/shmem_fs.h
++++ b/include/linux/shmem_fs.h
+@@ -26,10 +26,13 @@ struct shmem_inode_info {
+ };
+ struct shmem_sb_info {
++      struct mutex idr_lock;
++      bool idr_nouse;
++      struct idr idr;             /* manages inode-number */
+       unsigned long max_blocks;   /* How many blocks are allowed */
+       struct percpu_counter used_blocks;  /* How many are allocated */
+-      unsigned long max_inodes;   /* How many inodes are allowed */
+-      unsigned long free_inodes;  /* How many are left for allocation */
++      int max_inodes;             /* How many inodes are allowed */
++      int free_inodes;            /* How many are left for allocation */
+       spinlock_t stat_lock;       /* Serialize shmem_sb_info changes */
+       kuid_t uid;                 /* Mount uid for root directory */
+       kgid_t gid;                 /* Mount gid for root directory */
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 185836b..ac7f9fb 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -110,9 +110,13 @@ static unsigned long shmem_default_max_blocks(void)
+       return totalram_pages / 2;
+ }
+-static unsigned long shmem_default_max_inodes(void)
++static int shmem_default_max_inodes(void)
+ {
+-      return min(totalram_pages - totalhigh_pages, totalram_pages / 2);
++      unsigned long ul;
++
++      ul = INT_MAX;
++      ul = min3(ul, totalram_pages - totalhigh_pages, totalram_pages / 2);
++      return ul;
+ }
+ #endif
+@@ -592,6 +596,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
+ static void shmem_evict_inode(struct inode *inode)
+ {
+       struct shmem_inode_info *info = SHMEM_I(inode);
++      struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+       if (inode->i_mapping->a_ops == &shmem_aops) {
+               shmem_unacct_size(info->flags, inode->i_size);
+@@ -607,6 +612,11 @@ static void shmem_evict_inode(struct inode *inode)
+       simple_xattrs_free(&info->xattrs);
+       WARN_ON(inode->i_blocks);
++      if (!sbinfo->idr_nouse && inode->i_ino) {
++              mutex_lock(&sbinfo->idr_lock);
++              idr_remove(&sbinfo->idr, inode->i_ino);
++              mutex_unlock(&sbinfo->idr_lock);
++      }
+       shmem_free_inode(inode->i_sb);
+       clear_inode(inode);
+ }
+@@ -1406,13 +1416,13 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
+       struct inode *inode;
+       struct shmem_inode_info *info;
+       struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
++      int ino;
+       if (shmem_reserve_inode(sb))
+               return NULL;
+       inode = new_inode(sb);
+       if (inode) {
+-              inode->i_ino = get_next_ino();
+               inode_init_owner(inode, dir, mode);
+               inode->i_blocks = 0;
+               inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
+@@ -1454,6 +1464,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
+                       mpol_shared_policy_init(&info->policy, NULL);
+                       break;
+               }
++
++              if (!sbinfo->idr_nouse) {
++                      /* inum 0 and 1 are unused */
++                      mutex_lock(&sbinfo->idr_lock);
++                      ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX,
++                                      GFP_NOFS);
++                      if (ino > 0) {
++                              inode->i_ino = ino;
++                              mutex_unlock(&sbinfo->idr_lock);
++                              __insert_inode_hash(inode, inode->i_ino);
++                      } else {
++                              inode->i_ino = 0;
++                              mutex_unlock(&sbinfo->idr_lock);
++                              iput(inode);
++                              /* shmem_free_inode() will be called */
++                              inode = NULL;
++                      }
++              } else
++                      inode->i_ino = get_next_ino();
+       } else
+               shmem_free_inode(sb);
+       return inode;
+@@ -2674,8 +2703,7 @@ static struct dentry *shmem_get_parent(struct dentry *child)
+ static int shmem_match(struct inode *ino, void *vfh)
+ {
+       __u32 *fh = vfh;
+-      __u64 inum = fh[2];
+-      inum = (inum << 32) | fh[1];
++      __u64 inum = fh[1];
+       return ino->i_ino == inum && fh[0] == ino->i_generation;
+ }
+@@ -2686,14 +2714,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
+       struct dentry *dentry = NULL;
+       u64 inum;
+-      if (fh_len < 3)
++      if (fh_len < 2)
+               return NULL;
+-      inum = fid->raw[2];
+-      inum = (inum << 32) | fid->raw[1];
+-
+-      inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
+-                      shmem_match, fid->raw);
++      inum = fid->raw[1];
++      inode = ilookup5(sb, inum, shmem_match, fid->raw);
+       if (inode) {
+               dentry = d_find_alias(inode);
+               iput(inode);
+@@ -2705,30 +2730,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
+ static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
+                               struct inode *parent)
+ {
+-      if (*len < 3) {
+-              *len = 3;
++      if (*len < 2) {
++              *len = 2;
+               return FILEID_INVALID;
+       }
+-      if (inode_unhashed(inode)) {
+-              /* Unfortunately insert_inode_hash is not idempotent,
+-               * so as we hash inodes here rather than at creation
+-               * time, we need a lock to ensure we only try
+-               * to do it once
+-               */
+-              static DEFINE_SPINLOCK(lock);
+-              spin_lock(&lock);
+-              if (inode_unhashed(inode))
+-                      __insert_inode_hash(inode,
+-                                          inode->i_ino + inode->i_generation);
+-              spin_unlock(&lock);
+-      }
+-
+       fh[0] = inode->i_generation;
+       fh[1] = inode->i_ino;
+-      fh[2] = ((__u64)inode->i_ino) >> 32;
+-      *len = 3;
++      *len = 2;
+       return 1;
+ }
+@@ -2793,7 +2803,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
+                               goto bad_val;
+               } else if (!strcmp(this_char,"nr_inodes")) {
+                       sbinfo->max_inodes = memparse(value, &rest);
+-                      if (*rest)
++                      if (*rest || sbinfo->max_inodes < 2)
+                               goto bad_val;
+               } else if (!strcmp(this_char,"mode")) {
+                       if (remount)
+@@ -2846,7 +2856,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
+ {
+       struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+       struct shmem_sb_info config = *sbinfo;
+-      unsigned long inodes;
++      int inodes;
+       int error = -EINVAL;
+       config.mpol = NULL;
+@@ -2894,7 +2904,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
+               seq_printf(seq, ",size=%luk",
+                       sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10));
+       if (sbinfo->max_inodes != shmem_default_max_inodes())
+-              seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
++              seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes);
+       if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
+               seq_printf(seq, ",mode=%03ho", sbinfo->mode);
+       if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
+@@ -2983,6 +2993,8 @@ static void shmem_put_super(struct super_block *sb)
+ {
+       struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
++      if (!sbinfo->idr_nouse)
++              idr_destroy(&sbinfo->idr);
+       percpu_counter_destroy(&sbinfo->used_blocks);
+       mpol_put(sbinfo->mpol);
+       kfree(sbinfo);
+@@ -3001,6 +3013,8 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
+       if (!sbinfo)
+               return -ENOMEM;
++      mutex_init(&sbinfo->idr_lock);
++      idr_init(&sbinfo->idr);
+       sbinfo->mode = S_IRWXUGO | S_ISVTX;
+       sbinfo->uid = current_fsuid();
+       sbinfo->gid = current_fsgid();
+@@ -3104,6 +3118,15 @@ static void shmem_destroy_inodecache(void)
+       kmem_cache_destroy(shmem_inode_cachep);
+ }
++static __init void shmem_no_idr(struct super_block *sb)
++{
++      struct shmem_sb_info *sbinfo;
++
++      sbinfo = SHMEM_SB(sb);
++      sbinfo->idr_nouse = true;
++      idr_destroy(&sbinfo->idr);
++}
++
+ static const struct address_space_operations shmem_aops = {
+       .writepage      = shmem_writepage,
+       .set_page_dirty = __set_page_dirty_no_writeback,
+@@ -3246,6 +3269,7 @@ int __init shmem_init(void)
+               printk(KERN_ERR "Could not kern_mount tmpfs\n");
+               goto out1;
+       }
++      shmem_no_idr(shm_mnt->mnt_sb);
+       return 0;
+ out1:
+diff --git a/fs/inode.c b/fs/inode.c
+index 26753ba..61e0af2 100644
+--- a/fs/inode.c
++++ b/fs/inode.c
+@@ -840,6 +840,8 @@ unsigned int get_next_ino(void)
+       unsigned int *p = &get_cpu_var(last_ino);
+       unsigned int res = *p;
++start:
++
+ #ifdef CONFIG_SMP
+       if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) {
+               static atomic_t shared_last_ino;
+@@ -849,7 +851,9 @@ unsigned int get_next_ino(void)
+       }
+ #endif
+-      *p = ++res;
++      if (unlikely(!++res))
++              goto start;     /* never zero */
++      *p = res;
+       put_cpu_var(last_ino);
+       return res;
+ }
This page took 0.482102 seconds and 4 git commands to generate.