]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- aufs updated but build still fails
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 23 Aug 2013 22:05:11 +0000 (00:05 +0200)
committerArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 23 Aug 2013 22:05:11 +0000 (00:05 +0200)
kernel-aufs3.patch
kernel.spec

index 653e14ba90563c978045f4930e6ca151ff82dd12..a93df4a68f7431228787a92cdb271f027eb31c2c 100644 (file)
@@ -661,8 +661,8 @@ 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   2013-07-06 13:20:47.730197761 +0200
-@@ -0,0 +1,226 @@
++++ linux/Documentation/filesystems/aufs/design/02struct.txt   2013-08-23 23:59:39.631583456 +0200
+@@ -0,0 +1,243 @@
 +
 +# Copyright (C) 2005-2013 Junjiro R. Okajima
 +# 
@@ -889,6 +889,23 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li
 +internally and makes change to the new file on the upper writable branch.
 +When the trigger systemcall does not update the timestamps of the parent
 +dir, aufs reverts it after copy-up.
++
++
++Move-down (aufs3.9 and later)
++----------------------------------------------------------------------
++"Copy-up" is one of the essential feature in aufs. It copies a file from
++the lower readonly branch to the upper writable branch when a user
++changes something about the file.
++"Move-down" is an opposite action of copy-up. Basically this action is
++ran manually instead of automatically and internally.
++
++Sometimes users want to move-down a file from the upper writable branch
++to the lower readonly or writable branch. For instance,
++- the free space of the upper writable branch is going to run out.
++- create a new intermediate branch between the upper and lower branch.
++- etc.
++
++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   2013-07-06 13:20:47.730197761 +0200
@@ -3404,8 +3421,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       2013-07-30 22:42:46.232612606 +0200
-@@ -0,0 +1,1247 @@
++++ linux/fs/aufs/cpup.c       2013-08-23 23:59:39.631583456 +0200
+@@ -0,0 +1,1255 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -3753,18 +3770,11 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      return err;
 +}
 +
-+/* internal use only */
-+struct au_cpup_basic {
-+      struct dentry *dentry;
-+      aufs_bindex_t bdst, bsrc;
-+      loff_t len;
-+};
-+
 +/*
 + * to support a sparse file which is opened with O_APPEND,
 + * we need to close the file.
 + */
-+static int au_cp_regular(struct au_cpup_basic *basic)
++static int au_cp_regular(struct au_cp_generic *cpg)
 +{
 +      int err, i;
 +      enum { SRC, DST };
@@ -3776,14 +3786,14 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              void *label, *label_file;
 +      } *f, file[] = {
 +              {
-+                      .bindex = basic->bsrc,
++                      .bindex = cpg->bsrc,
 +                      .flags = O_RDONLY | O_NOATIME | O_LARGEFILE,
 +                      .file = NULL,
 +                      .label = &&out,
 +                      .label_file = &&out_src
 +              },
 +              {
-+                      .bindex = basic->bdst,
++                      .bindex = cpg->bdst,
 +                      .flags = O_WRONLY | O_NOATIME | O_LARGEFILE,
 +                      .file = NULL,
 +                      .label = &&out_src,
@@ -3793,11 +3803,11 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      struct super_block *sb;
 +
 +      /* bsrc branch can be ro/rw. */
-+      sb = basic->dentry->d_sb;
++      sb = cpg->dentry->d_sb;
 +      f = file;
 +      for (i = 0; i < 2; i++, f++) {
-+              f->dentry = au_h_dptr(basic->dentry, f->bindex);
-+              f->file = au_h_open(basic->dentry, f->bindex, f->flags,
++              f->dentry = au_h_dptr(cpg->dentry, f->bindex);
++              f->file = au_h_open(cpg->dentry, f->bindex, f->flags,
 +                                  /*file*/NULL);
 +              err = PTR_ERR(f->file);
 +              if (IS_ERR(f->file))
@@ -3809,7 +3819,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +
 +      /* try stopping to update while we copyup */
 +      IMustLock(file[SRC].dentry->d_inode);
-+      err = au_copy_file(file[DST].file, file[SRC].file, basic->len);
++      err = au_copy_file(file[DST].file, file[SRC].file, cpg->len);
 +
 +out_dst:
 +      fput(file[DST].file);
@@ -3821,7 +3831,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      return err;
 +}
 +
-+static int au_do_cpup_regular(struct au_cpup_basic *basic, struct au_pin *pin,
++static int au_do_cpup_regular(struct au_cp_generic *cpg,
 +                            struct au_cpup_reg_attr *h_src_attr)
 +{
 +      int err, rerr;
@@ -3830,17 +3840,17 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      struct inode *h_src_inode;
 +
 +      err = 0;
-+      h_src_inode = au_h_iptr(basic->dentry->d_inode, basic->bsrc);
++      h_src_inode = au_h_iptr(cpg->dentry->d_inode, cpg->bsrc);
 +      l = i_size_read(h_src_inode);
-+      if (basic->len == -1 || l < basic->len)
-+              basic->len = l;
-+      if (basic->len) {
++      if (cpg->len == -1 || l < cpg->len)
++              cpg->len = l;
++      if (cpg->len) {
 +              /* try stopping to update while we are referencing */
 +              mutex_lock_nested(&h_src_inode->i_mutex, AuLsc_I_CHILD);
-+              au_pin_hdir_unlock(pin);
++              au_pin_hdir_unlock(cpg->pin);
 +
-+              h_path.dentry = au_h_dptr(basic->dentry, basic->bsrc);
-+              h_path.mnt = au_sbr_mnt(basic->dentry->d_sb, basic->bsrc);
++              h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc);
++              h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc);
 +              h_src_attr->iflags = h_src_inode->i_flags;
 +              err = vfs_getattr(&h_path, &h_src_attr->st);
 +              if (unlikely(err)) {
@@ -3848,9 +3858,9 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +                      goto out;
 +              }
 +              h_src_attr->valid = 1;
-+              err = au_cp_regular(basic);
++              err = au_cp_regular(cpg);
 +              mutex_unlock(&h_src_inode->i_mutex);
-+              rerr = au_pin_hdir_relock(pin);
++              rerr = au_pin_hdir_relock(cpg->pin);
 +              if (!err && rerr)
 +                      err = rerr;
 +      }
@@ -3896,15 +3906,14 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +}
 +
 +static noinline_for_stack
-+int cpup_entry(struct au_cpup_basic *basic, unsigned int flags,
-+             struct dentry *dst_parent, struct au_pin *pin,
++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent,
 +             struct au_cpup_reg_attr *h_src_attr)
 +{
 +      int err;
 +      umode_t mode;
 +      unsigned int mnt_flags;
 +      unsigned char isdir;
-+      const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME);
++      const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME);
 +      struct au_dtime dt;
 +      struct path h_path;
 +      struct dentry *h_src, *h_dst, *h_parent;
@@ -3912,13 +3921,13 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      struct super_block *sb;
 +
 +      /* bsrc branch can be ro/rw. */
-+      h_src = au_h_dptr(basic->dentry, basic->bsrc);
++      h_src = au_h_dptr(cpg->dentry, cpg->bsrc);
 +      h_inode = h_src->d_inode;
-+      AuDebugOn(h_inode != au_h_iptr(basic->dentry->d_inode, basic->bsrc));
++      AuDebugOn(h_inode != au_h_iptr(cpg->dentry->d_inode, cpg->bsrc));
 +
 +      /* try stopping to be referenced while we are creating */
-+      h_dst = au_h_dptr(basic->dentry, basic->bdst);
-+      if (au_ftest_cpup(flags, RENAME))
++      h_dst = au_h_dptr(cpg->dentry, cpg->bdst);
++      if (au_ftest_cpup(cpg->flags, RENAME))
 +              AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX,
 +                                AUFS_WH_PFX_LEN));
 +      h_parent = h_dst->d_parent; /* dir inode is locked */
@@ -3926,8 +3935,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      IMustLock(h_dir);
 +      AuDebugOn(h_parent != h_dst->d_parent);
 +
-+      sb = basic->dentry->d_sb;
-+      h_path.mnt = au_sbr_mnt(sb, basic->bdst);
++      sb = cpg->dentry->d_sb;
++      h_path.mnt = au_sbr_mnt(sb, cpg->bdst);
 +      if (do_dt) {
 +              h_path.dentry = h_parent;
 +              au_dtime_store(&dt, dst_parent, &h_path);
@@ -3941,7 +3950,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              err = vfsub_create(h_dir, &h_path, mode | S_IWUSR,
 +                                 /*want_excl*/true);
 +              if (!err)
-+                      err = au_do_cpup_regular(basic, pin, h_src_attr);
++                      err = au_do_cpup_regular(cpg, h_src_attr);
 +              break;
 +      case S_IFDIR:
 +              isdir = 1;
@@ -3951,10 +3960,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +                       * strange behaviour from the users view,
 +                       * particularry setattr case
 +                       */
-+                      if (au_ibstart(dst_parent->d_inode) == basic->bdst)
++                      if (au_ibstart(dst_parent->d_inode) == cpg->bdst)
 +                              au_cpup_attr_nlink(dst_parent->d_inode,
 +                                                 /*force*/1);
-+                      au_cpup_attr_nlink(basic->dentry->d_inode, /*force*/1);
++                      au_cpup_attr_nlink(cpg->dentry->d_inode, /*force*/1);
 +              }
 +              break;
 +      case S_IFLNK:
@@ -3979,10 +3988,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +          && au_opt_test(mnt_flags, XINO)
 +          && h_inode->i_nlink == 1
 +          /* todo: unnecessary? */
-+          /* && basic->dentry->d_inode->i_nlink == 1 */
-+          && basic->bdst < basic->bsrc
-+          && !au_ftest_cpup(flags, KEEPLINO))
-+              au_xino_write(sb, basic->bsrc, h_inode->i_ino, /*ino*/0);
++          /* && cpg->dentry->d_inode->i_nlink == 1 */
++          && cpg->bdst < cpg->bsrc
++          && !au_ftest_cpup(cpg->flags, KEEPLINO))
++              au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0);
 +              /* ignore this error */
 +
 +      if (do_dt)
@@ -4023,82 +4032,87 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 + * the caller must set the both of lower dentries.
 + * @len is for truncating when it is -1 copyup the entire file.
 + * in link/rename cases, @dst_parent may be different from the real one.
++ * basic->bsrc can be larger than basic->bdst.
 + */
-+static int au_cpup_single(struct au_cpup_basic *basic, unsigned int flags,
-+                        struct dentry *dst_parent, struct au_pin *pin)
++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
 +{
 +      int err, rerr;
 +      aufs_bindex_t old_ibstart;
 +      unsigned char isdir, plink;
-+      struct au_dtime dt;
-+      struct path h_path;
 +      struct dentry *h_src, *h_dst, *h_parent;
 +      struct inode *dst_inode, *h_dir, *inode;
 +      struct super_block *sb;
 +      struct au_branch *br;
-+      struct au_cpup_reg_attr h_src_attr = {
-+              .valid = 0
-+      };
++      /* to reuduce stack size */
++      struct {
++              struct au_dtime dt;
++              struct path h_path;
++              struct au_cpup_reg_attr h_src_attr;
++      } *a;
 +
-+      AuDebugOn(basic->bsrc <= basic->bdst);
++      err = -ENOMEM;
++      a = kmalloc(sizeof(*a), GFP_NOFS);
++      if (unlikely(!a))
++              goto out;
++      a->h_src_attr.valid = 0;
 +
-+      sb = basic->dentry->d_sb;
-+      br = au_sbr(sb, basic->bdst);
-+      h_path.mnt = au_br_mnt(br);
-+      h_dst = au_h_dptr(basic->dentry, basic->bdst);
++      sb = cpg->dentry->d_sb;
++      br = au_sbr(sb, cpg->bdst);
++      a->h_path.mnt = au_br_mnt(br);
++      h_dst = au_h_dptr(cpg->dentry, cpg->bdst);
 +      h_parent = h_dst->d_parent; /* dir inode is locked */
 +      h_dir = h_parent->d_inode;
 +      IMustLock(h_dir);
 +
-+      h_src = au_h_dptr(basic->dentry, basic->bsrc);
-+      inode = basic->dentry->d_inode;
++      h_src = au_h_dptr(cpg->dentry, cpg->bsrc);
++      inode = cpg->dentry->d_inode;
 +
 +      if (!dst_parent)
-+              dst_parent = dget_parent(basic->dentry);
++              dst_parent = dget_parent(cpg->dentry);
 +      else
 +              dget(dst_parent);
 +
 +      plink = !!au_opt_test(au_mntflags(sb), PLINK);
-+      dst_inode = au_h_iptr(inode, basic->bdst);
++      dst_inode = au_h_iptr(inode, cpg->bdst);
 +      if (dst_inode) {
 +              if (unlikely(!plink)) {
 +                      err = -EIO;
 +                      AuIOErr("hi%lu(i%lu) exists on b%d "
 +                              "but plink is disabled\n",
-+                              dst_inode->i_ino, inode->i_ino, basic->bdst);
-+                      goto out;
++                              dst_inode->i_ino, inode->i_ino, cpg->bdst);
++                      goto out_parent;
 +              }
 +
 +              if (dst_inode->i_nlink) {
-+                      const int do_dt = au_ftest_cpup(flags, DTIME);
++                      const int do_dt = au_ftest_cpup(cpg->flags, DTIME);
 +
-+                      h_src = au_plink_lkup(inode, basic->bdst);
++                      h_src = au_plink_lkup(inode, cpg->bdst);
 +                      err = PTR_ERR(h_src);
 +                      if (IS_ERR(h_src))
-+                              goto out;
++                              goto out_parent;
 +                      if (unlikely(!h_src->d_inode)) {
 +                              err = -EIO;
 +                              AuIOErr("i%lu exists on a upper branch "
 +                                      "but not pseudo-linked\n",
 +                                      inode->i_ino);
 +                              dput(h_src);
-+                              goto out;
++                              goto out_parent;
 +                      }
 +
 +                      if (do_dt) {
-+                              h_path.dentry = h_parent;
-+                              au_dtime_store(&dt, dst_parent, &h_path);
++                              a->h_path.dentry = h_parent;
++                              au_dtime_store(&a->dt, dst_parent, &a->h_path);
 +                      }
 +
-+                      h_path.dentry = h_dst;
-+                      err = vfsub_link(h_src, h_dir, &h_path);
-+                      if (!err && au_ftest_cpup(flags, RENAME))
++                      a->h_path.dentry = h_dst;
++                      err = vfsub_link(h_src, h_dir, &a->h_path);
++                      if (!err && au_ftest_cpup(cpg->flags, RENAME))
 +                              err = au_do_ren_after_cpup
-+                                      (basic->dentry, basic->bdst, &h_path);
++                                      (cpg->dentry, cpg->bdst, &a->h_path);
 +                      if (do_dt)
-+                              au_dtime_revert(&dt);
++                              au_dtime_revert(&a->dt);
 +                      dput(h_src);
-+                      goto out;
++                      goto out_parent;
 +              } else
 +                      /* todo: cpup_wh_file? */
 +                      /* udba work */
@@ -4107,38 +4121,40 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +
 +      isdir = S_ISDIR(inode->i_mode);
 +      old_ibstart = au_ibstart(inode);
-+      err = cpup_entry(basic, flags, dst_parent, pin, &h_src_attr);
++      err = cpup_entry(cpg, dst_parent, &a->h_src_attr);
 +      if (unlikely(err))
 +              goto out_rev;
 +      dst_inode = h_dst->d_inode;
 +      mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2);
 +      /* todo: necessary? */
-+      /* au_pin_hdir_unlock(pin); */
++      /* au_pin_hdir_unlock(cpg->pin); */
 +
-+      err = cpup_iattr(basic->dentry, basic->bdst, h_src, &h_src_attr);
++      err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr);
 +      if (unlikely(err)) {
 +              /* todo: necessary? */
-+              /* au_pin_hdir_relock(pin); */ /* ignore an error */
++              /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */
 +              mutex_unlock(&dst_inode->i_mutex);
 +              goto out_rev;
 +      }
 +
-+      if (basic->bdst < old_ibstart) {
++      if (cpg->bdst < old_ibstart) {
 +              if (S_ISREG(inode->i_mode)) {
-+                      err = au_dy_iaop(inode, basic->bdst, dst_inode);
++                      err = au_dy_iaop(inode, cpg->bdst, dst_inode);
 +                      if (unlikely(err)) {
-+                              /* au_pin_hdir_relock(pin); ignore an error */
++                              /* ignore an error */
++                              /* au_pin_hdir_relock(cpg->pin); */
 +                              mutex_unlock(&dst_inode->i_mutex);
 +                              goto out_rev;
 +                      }
 +              }
-+              au_set_ibstart(inode, basic->bdst);
-+      }
-+      au_set_h_iptr(inode, basic->bdst, au_igrab(dst_inode),
++              au_set_ibstart(inode, cpg->bdst);
++      } else
++              au_set_ibend(inode, cpg->bdst);
++      au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode),
 +                    au_hi_flags(inode, isdir));
 +
 +      /* todo: necessary? */
-+      /* err = au_pin_hdir_relock(pin); */
++      /* err = au_pin_hdir_relock(cpg->pin); */
 +      mutex_unlock(&dst_inode->i_mutex);
 +      if (unlikely(err))
 +              goto out_rev;
@@ -4146,53 +4162,55 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      if (!isdir
 +          && h_src->d_inode->i_nlink > 1
 +          && plink)
-+              au_plink_append(inode, basic->bdst, h_dst);
++              au_plink_append(inode, cpg->bdst, h_dst);
 +
-+      if (au_ftest_cpup(flags, RENAME)) {
-+              h_path.dentry = h_dst;
-+              err = au_do_ren_after_cpup(basic->dentry, basic->bdst, &h_path);
++      if (au_ftest_cpup(cpg->flags, RENAME)) {
++              a->h_path.dentry = h_dst;
++              err = au_do_ren_after_cpup(cpg->dentry, cpg->bdst, &a->h_path);
 +      }
 +      if (!err)
-+              goto out; /* success */
++              goto out_parent; /* success */
 +
 +      /* revert */
 +out_rev:
-+      h_path.dentry = h_parent;
-+      au_dtime_store(&dt, dst_parent, &h_path);
-+      h_path.dentry = h_dst;
++      a->h_path.dentry = h_parent;
++      au_dtime_store(&a->dt, dst_parent, &a->h_path);
++      a->h_path.dentry = h_dst;
 +      rerr = 0;
 +      if (h_dst->d_inode) {
 +              if (!isdir)
-+                      rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++                      rerr = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +              else
-+                      rerr = vfsub_rmdir(h_dir, &h_path);
++                      rerr = vfsub_rmdir(h_dir, &a->h_path);
 +      }
-+      au_dtime_revert(&dt);
++      au_dtime_revert(&a->dt);
 +      if (rerr) {
 +              AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
 +              err = -EIO;
 +      }
-+out:
++out_parent:
 +      dput(dst_parent);
++      kfree(a);
++out:
 +      return err;
 +}
 +
++#if 0 /* unused */
 +struct au_cpup_single_args {
 +      int *errp;
-+      struct au_cpup_basic *basic;
-+      unsigned int flags;
++      struct au_cp_generic *cpg;
 +      struct dentry *dst_parent;
-+      struct au_pin *pin;
 +};
 +
 +static void au_call_cpup_single(void *args)
 +{
 +      struct au_cpup_single_args *a = args;
 +
-+      au_pin_hdir_acquire_nest(a->pin);
-+      *a->errp = au_cpup_single(a->basic, a->flags, a->dst_parent, a->pin);
-+      au_pin_hdir_release(a->pin);
++      au_pin_hdir_acquire_nest(a->cpg->pin);
++      *a->errp = au_cpup_single(a->cpg, a->dst_parent);
++      au_pin_hdir_release(a->cpg->pin);
 +}
++#endif
 +
 +/*
 + * prevent SIGXFSZ in copy-up.
@@ -4233,29 +4251,20 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      return do_sio;
 +}
 +
-+int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
-+                     aufs_bindex_t bsrc, loff_t len, unsigned int flags,
-+                     struct dentry *dst_parent, struct au_pin *pin)
++#if 0 /* unused */
++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
 +{
 +      int err, wkq_err;
 +      struct dentry *h_dentry;
-+      struct au_cpup_basic basic = {
-+              .dentry = dentry,
-+              .bdst   = bdst,
-+              .bsrc   = bsrc,
-+              .len    = len
-+      };
 +
-+      h_dentry = au_h_dptr(dentry, bsrc);
++      h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc);
 +      if (!au_cpup_sio_test(pin, h_dentry->d_inode->i_mode))
-+              err = au_cpup_single(&basic, flags, dst_parent, pin);
++              err = au_cpup_single(cpg, dst_parent);
 +      else {
 +              struct au_cpup_single_args args = {
 +                      .errp           = &err,
-+                      .basic          = &basic,
-+                      .flags          = flags,
-+                      .dst_parent     = dst_parent,
-+                      .pin            = pin
++                      .cpg            = cpg,
++                      .dst_parent     = dst_parent
 +              };
 +              wkq_err = au_wkq_wait(au_call_cpup_single, &args);
 +              if (unlikely(wkq_err))
@@ -4264,44 +4273,35 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +
 +      return err;
 +}
++#endif
 +
 +/*
 + * copyup the @dentry from the first active lower branch to @bdst,
 + * using au_cpup_single().
 + */
-+static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                        unsigned int flags, struct au_pin *pin)
++static int au_cpup_simple(struct au_cp_generic *cpg)
 +{
 +      int err;
-+      aufs_bindex_t bsrc, bend;
-+      struct dentry *h_dentry;
++      unsigned int flags_orig;
++      struct dentry *dentry;
++
++      AuDebugOn(cpg->bsrc < 0);
 +
++      dentry = cpg->dentry;
 +      DiMustWriteLock(dentry);
-+      bend = au_dbend(dentry);
-+      for (bsrc = bdst + 1; bsrc <= bend; bsrc++) {
-+              h_dentry = au_h_dptr(dentry, bsrc);
-+              if (h_dentry) {
-+                      AuDebugOn(!h_dentry->d_inode);
-+                      break;
-+              }
-+      }
-+      AuDebugOn(bsrc > bend);
 +
-+      err = au_lkup_neg(dentry, bdst, /*wh*/1);
++      err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1);
 +      if (!err) {
-+              struct au_cpup_basic basic = {
-+                      .dentry = dentry,
-+                      .bdst   = bdst,
-+                      .bsrc   = bsrc,
-+                      .len    = len
-+              };
-+              err = au_cpup_single(&basic, flags | AuCpup_RENAME, NULL, pin);
++              flags_orig = cpg->flags;
++              au_fset_cpup(cpg->flags, RENAME);
++              err = au_cpup_single(cpg, NULL);
++              cpg->flags = flags_orig;
 +              if (!err)
 +                      return 0; /* success */
 +
 +              /* revert */
-+              au_set_h_dptr(dentry, bdst, NULL);
-+              au_set_dbstart(dentry, bsrc);
++              au_set_h_dptr(dentry, cpg->bdst, NULL);
++              au_set_dbstart(dentry, cpg->bsrc);
 +      }
 +
 +      return err;
@@ -4309,42 +4309,44 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +
 +struct au_cpup_simple_args {
 +      int *errp;
-+      struct dentry *dentry;
-+      aufs_bindex_t bdst;
-+      loff_t len;
-+      unsigned int flags;
-+      struct au_pin *pin;
++      struct au_cp_generic *cpg;
 +};
 +
 +static void au_call_cpup_simple(void *args)
 +{
 +      struct au_cpup_simple_args *a = args;
 +
-+      au_pin_hdir_acquire_nest(a->pin);
-+      *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags, a->pin);
-+      au_pin_hdir_release(a->pin);
++      au_pin_hdir_acquire_nest(a->cpg->pin);
++      *a->errp = au_cpup_simple(a->cpg);
++      au_pin_hdir_release(a->cpg->pin);
 +}
 +
-+int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                     unsigned int flags, struct au_pin *pin)
++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
 +{
 +      int err, wkq_err;
-+      struct dentry *parent;
++      struct dentry *dentry, *parent;
++      struct file *h_file;
 +      struct inode *h_dir;
 +
++      dentry = cpg->dentry;
++      h_file = NULL;
++      if (au_ftest_cpup(cpg->flags, HOPEN)) {
++              AuDebugOn(cpg->bsrc < 0);
++              h_file = au_h_open_pre(dentry, cpg->bsrc);
++              err = PTR_ERR(h_file);
++              if (IS_ERR(h_file))
++                      goto out;
++      }
++
 +      parent = dget_parent(dentry);
-+      h_dir = au_h_iptr(parent->d_inode, bdst);
++      h_dir = au_h_iptr(parent->d_inode, cpg->bdst);
 +      if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE)
-+          && !au_cpup_sio_test(pin, dentry->d_inode->i_mode))
-+              err = au_cpup_simple(dentry, bdst, len, flags, pin);
++          && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode))
++              err = au_cpup_simple(cpg);
 +      else {
 +              struct au_cpup_simple_args args = {
 +                      .errp           = &err,
-+                      .dentry         = dentry,
-+                      .bdst           = bdst,
-+                      .len            = len,
-+                      .flags          = flags,
-+                      .pin            = pin
++                      .cpg            = cpg
 +              };
 +              wkq_err = au_wkq_wait(au_call_cpup_simple, &args);
 +              if (unlikely(wkq_err))
@@ -4352,26 +4354,39 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      }
 +
 +      dput(parent);
++      if (h_file)
++              au_h_open_post(dentry, cpg->bsrc, h_file);
++
++out:
 +      return err;
 +}
 +
-+/* generalized cpup_simple() with h_open_pre/post() calls */
-+int au_sio_cpup_simple_h_open(struct dentry *dentry, aufs_bindex_t bdst,
-+                            loff_t len, unsigned int flags,
-+                            struct au_pin *pin, aufs_bindex_t bsrc)
++int au_sio_cpup_simple(struct au_cp_generic *cpg)
 +{
-+      int err;
-+      struct file *h_file;
++      aufs_bindex_t bsrc, bend;
++      struct dentry *dentry, *h_dentry;
 +
-+      h_file = au_h_open_pre(dentry, bsrc);
-+      if (IS_ERR(h_file))
-+              err = PTR_ERR(h_file);
-+      else {
-+              err = au_sio_cpup_simple(dentry, bdst, len, flags, pin);
-+              au_h_open_post(dentry, bsrc, h_file);
++      if (cpg->bsrc < 0) {
++              dentry = cpg->dentry;
++              bend = au_dbend(dentry);
++              for (bsrc = cpg->bdst + 1; bsrc <= bend; bsrc++) {
++                      h_dentry = au_h_dptr(dentry, bsrc);
++                      if (h_dentry) {
++                              AuDebugOn(!h_dentry->d_inode);
++                              break;
++                      }
++              }
++              AuDebugOn(bsrc > bend);
++              cpg->bsrc = bsrc;
 +      }
++      AuDebugOn(cpg->bsrc <= cpg->bdst);
++      return au_do_sio_cpup_simple(cpg);
++}
 +
-+      return err;
++int au_sio_cpdown_simple(struct au_cp_generic *cpg)
++{
++      AuDebugOn(cpg->bdst <= cpg->bsrc);
++      return au_do_sio_cpup_simple(cpg);
 +}
 +
 +/* ---------------------------------------------------------------------- */
@@ -4379,55 +4394,57 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +/*
 + * copyup the deleted file for writing.
 + */
-+static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
-+                       struct dentry *wh_dentry, struct file *file,
-+                       loff_t len, struct au_pin *pin)
++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry,
++                       struct file *file)
 +{
 +      int err;
-+      struct au_cpup_basic basic = {
-+              .dentry = dentry,
-+              .bdst   = bdst,
-+              .bsrc   = -1,
-+              .len    = len
-+      };
-+      struct au_dinfo *dinfo;
++      unsigned int flags_orig;
++      aufs_bindex_t bsrc_orig;
 +      struct dentry *h_d_dst, *h_d_start;
++      struct au_dinfo *dinfo;
 +      struct au_hdentry *hdp;
 +
-+      dinfo = au_di(dentry);
++      dinfo = au_di(cpg->dentry);
 +      AuRwMustWriteLock(&dinfo->di_rwsem);
 +
-+      basic.bsrc = dinfo->di_bstart;
++      bsrc_orig = cpg->bsrc;
++      cpg->bsrc = dinfo->di_bstart;
 +      hdp = dinfo->di_hdentry;
-+      h_d_dst = hdp[0 + bdst].hd_dentry;
-+      dinfo->di_bstart = bdst;
-+      hdp[0 + bdst].hd_dentry = wh_dentry;
++      h_d_dst = hdp[0 + cpg->bdst].hd_dentry;
++      dinfo->di_bstart = cpg->bdst;
++      hdp[0 + cpg->bdst].hd_dentry = wh_dentry;
 +      h_d_start = NULL;
 +      if (file) {
-+              h_d_start = hdp[0 + basic.bsrc].hd_dentry;
-+              hdp[0 + basic.bsrc].hd_dentry = au_hf_top(file)->f_dentry;
++              h_d_start = hdp[0 + cpg->bsrc].hd_dentry;
++              hdp[0 + cpg->bsrc].hd_dentry = au_hf_top(file)->f_dentry;
 +      }
-+      err = au_cpup_single(&basic, !AuCpup_DTIME, /*h_parent*/NULL, pin);
++      flags_orig = cpg->flags;
++      cpg->flags = !AuCpup_DTIME;
++      err = au_cpup_single(cpg, /*h_parent*/NULL);
++      cpg->flags = flags_orig;
 +      if (file) {
 +              if (!err)
 +                      err = au_reopen_nondir(file);
-+              hdp[0 + basic.bsrc].hd_dentry = h_d_start;
++              hdp[0 + cpg->bsrc].hd_dentry = h_d_start;
 +      }
-+      hdp[0 + bdst].hd_dentry = h_d_dst;
-+      dinfo->di_bstart = basic.bsrc;
++      hdp[0 + cpg->bdst].hd_dentry = h_d_dst;
++      dinfo->di_bstart = cpg->bsrc;
++      cpg->bsrc = bsrc_orig;
 +
 +      return err;
 +}
 +
-+static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                    struct file *file, struct au_pin *pin)
++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file)
 +{
 +      int err;
++      aufs_bindex_t bdst;
 +      struct au_dtime dt;
-+      struct dentry *parent, *h_parent, *wh_dentry;
++      struct dentry *dentry, *parent, *h_parent, *wh_dentry;
 +      struct au_branch *br;
 +      struct path h_path;
 +
++      dentry = cpg->dentry;
++      bdst = cpg->bdst;
 +      br = au_sbr(dentry->d_sb, bdst);
 +      parent = dget_parent(dentry);
 +      h_parent = au_h_dptr(parent, bdst);
@@ -4439,7 +4456,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +      h_path.dentry = h_parent;
 +      h_path.mnt = au_br_mnt(br);
 +      au_dtime_store(&dt, parent, &h_path);
-+      err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len, pin);
++      err = au_do_cpup_wh(cpg, wh_dentry, file);
 +      if (unlikely(err))
 +              goto out_wh;
 +
@@ -4466,37 +4483,37 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +
 +struct au_cpup_wh_args {
 +      int *errp;
-+      struct dentry *dentry;
-+      aufs_bindex_t bdst;
-+      loff_t len;
++      struct au_cp_generic *cpg;
 +      struct file *file;
-+      struct au_pin *pin;
 +};
 +
 +static void au_call_cpup_wh(void *args)
 +{
 +      struct au_cpup_wh_args *a = args;
 +
-+      au_pin_hdir_acquire_nest(a->pin);
-+      *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file, a->pin);
-+      au_pin_hdir_release(a->pin);
++      au_pin_hdir_acquire_nest(a->cpg->pin);
++      *a->errp = au_cpup_wh(a->cpg, a->file);
++      au_pin_hdir_release(a->cpg->pin);
 +}
 +
-+int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                 struct file *file, struct au_pin *pin)
++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
 +{
 +      int err, wkq_err;
-+      struct dentry *parent, *h_orph, *h_parent, *h_dentry;
++      aufs_bindex_t bdst;
++      struct dentry *dentry, *parent, *h_orph, *h_parent, *h_dentry;
 +      struct inode *dir, *h_dir, *h_tmpdir;
 +      struct au_wbr *wbr;
-+      struct au_pin wh_pin;
++      struct au_pin wh_pin, *pin_orig;
 +
++      dentry = cpg->dentry;
++      bdst = cpg->bdst;
 +      parent = dget_parent(dentry);
 +      dir = parent->d_inode;
 +      h_orph = NULL;
 +      h_parent = NULL;
 +      h_dir = au_igrab(au_h_iptr(dir, bdst));
 +      h_tmpdir = h_dir;
++      pin_orig = NULL;
 +      if (!h_dir->i_nlink) {
 +              wbr = au_sbr(dentry->d_sb, bdst)->br_wbr;
 +              h_orph = wbr->wbr_orph;
@@ -4513,22 +4530,20 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
 +              /* todo: au_h_open_pre()? */
 +
++              pin_orig = cpg->pin;
 +              au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT,
-+                          AuLsc_I_PARENT3, pin->udba, AuPin_DI_LOCKED);
-+              pin = &wh_pin;
++                          AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED);
++              cpg->pin = &wh_pin;
 +      }
 +
 +      if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)
-+          && !au_cpup_sio_test(pin, dentry->d_inode->i_mode))
-+              err = au_cpup_wh(dentry, bdst, len, file, pin);
++          && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode))
++              err = au_cpup_wh(cpg, file);
 +      else {
 +              struct au_cpup_wh_args args = {
 +                      .errp   = &err,
-+                      .dentry = dentry,
-+                      .bdst   = bdst,
-+                      .len    = len,
-+                      .file   = file,
-+                      .pin    = pin
++                      .cpg    = cpg,
++                      .file   = file
 +              };
 +              wkq_err = au_wkq_wait(au_call_cpup_wh, &args);
 +              if (unlikely(wkq_err))
@@ -4540,6 +4555,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +              /* todo: au_h_open_post()? */
 +              au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
 +              au_set_h_dptr(parent, bdst, h_parent);
++              AuDebugOn(!pin_orig);
++              cpg->pin = pin_orig;
 +      }
 +      iput(h_dir);
 +      dput(parent);
@@ -4622,7 +4639,15 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +                     struct dentry *h_parent __maybe_unused ,
 +                     void *arg __maybe_unused)
 +{
-+      return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME, pin);
++      struct au_cp_generic cpg = {
++              .dentry = dentry,
++              .bdst   = bdst,
++              .bsrc   = -1,
++              .len    = 0,
++              .pin    = pin,
++              .flags  = AuCpup_DTIME
++      };
++      return au_sio_cpup_simple(&cpg);
 +}
 +
 +int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
@@ -4655,8 +4680,8 @@ 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       2013-07-30 22:42:46.232612606 +0200
-@@ -0,0 +1,87 @@
++++ linux/fs/aufs/cpup.h       2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,90 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -4699,11 +4724,21 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
 +
 +/* ---------------------------------------------------------------------- */
 +
++struct au_cp_generic {
++      struct dentry   *dentry;
++      aufs_bindex_t   bdst, bsrc;
++      loff_t          len;
++      struct au_pin   *pin;
++      unsigned int    flags;
++};
++
 +/* cpup flags */
 +#define AuCpup_DTIME  1               /* do dtime_store/revert */
 +#define AuCpup_KEEPLINO       (1 << 1)        /* do not clear the lower xino,
 +                                         for link(2) */
 +#define AuCpup_RENAME (1 << 2)        /* rename after cpup */
++#define AuCpup_HOPEN  (1 << 3)        /* call h_open_pre/post() in cpup */
++
 +#define au_ftest_cpup(flags, name)    ((flags) & AuCpup_##name)
 +#define au_fset_cpup(flags, name) \
 +      do { (flags) |= AuCpup_##name; } while (0)
@@ -4711,16 +4746,9 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
 +      do { (flags) &= ~AuCpup_##name; } while (0)
 +
 +int au_copy_file(struct file *dst, struct file *src, loff_t len);
-+int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
-+                     aufs_bindex_t bsrc, loff_t len, unsigned int flags,
-+                     struct dentry *dst_parent, struct au_pin *pin);
-+int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                     unsigned int flags, struct au_pin *pin);
-+int au_sio_cpup_simple_h_open(struct dentry *dentry, aufs_bindex_t bdst,
-+                            loff_t len, unsigned int flags,
-+                            struct au_pin *pin, aufs_bindex_t bsrc);
-+int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
-+                 struct file *file, struct au_pin *pin);
++int au_sio_cpup_simple(struct au_cp_generic *cpg);
++int au_sio_cpdown_simple(struct au_cp_generic *cpg);
++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file);
 +
 +int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
 +             int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
@@ -5581,7 +5609,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
 +#endif /* __AUFS_DCSUB_H__ */
 diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 --- /usr/share/empty/fs/aufs/debug.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/debug.c      2013-07-30 22:42:55.839613269 +0200
++++ linux/fs/aufs/debug.c      2013-08-23 23:59:39.634916914 +0200
 @@ -0,0 +1,491 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
@@ -5672,7 +5700,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
 +              return -1;
 +      }
 +
-+      /* the type of i_blocks depends upon CONFIG_LSF */
++      /* the type of i_blocks depends upon CONFIG_LBDAF */
 +      BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long)
 +                   && sizeof(inode->i_blocks) != sizeof(u64));
 +      if (wh) {
@@ -10246,8 +10274,8 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 +}
 diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 --- /usr/share/empty/fs/aufs/file.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.c       2013-07-30 22:42:55.842946719 +0200
-@@ -0,0 +1,689 @@
++++ linux/fs/aufs/file.c       2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,708 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -10472,28 +10500,35 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +{
 +      int err;
 +      struct inode *inode, *h_inode;
-+      struct dentry *dentry, *h_dentry, *hi_wh;
++      struct dentry *h_dentry, *hi_wh;
++      struct au_cp_generic cpg = {
++              .dentry = file->f_dentry,
++              .bdst   = bcpup,
++              .bsrc   = -1,
++              .len    = len,
++              .pin    = pin
++      };
 +
-+      dentry = file->f_dentry;
-+      au_update_dbstart(dentry);
-+      inode = dentry->d_inode;
++      au_update_dbstart(cpg.dentry);
++      inode = cpg.dentry->d_inode;
 +      h_inode = NULL;
-+      if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
-+              h_dentry = au_h_dptr(dentry, bcpup);
++      if (au_dbstart(cpg.dentry) <= bcpup
++          && au_dbend(cpg.dentry) >= bcpup) {
++              h_dentry = au_h_dptr(cpg.dentry, bcpup);
 +              if (h_dentry)
 +                      h_inode = h_dentry->d_inode;
 +      }
 +      hi_wh = au_hi_wh(inode, bcpup);
 +      if (!hi_wh && !h_inode)
-+              err = au_sio_cpup_wh(dentry, bcpup, len, file, pin);
++              err = au_sio_cpup_wh(&cpg, file);
 +      else
 +              /* already copied-up after unlink */
 +              err = au_reopen_wh(file, bcpup, hi_wh);
 +
 +      if (!err
 +          && inode->i_nlink > 1
-+          && au_opt_test(au_mntflags(dentry->d_sb), PLINK))
-+              au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
++          && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
++              au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));
 +
 +      return err;
 +}
@@ -10504,72 +10539,79 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
 +{
 +      int err;
-+      aufs_bindex_t bstart, bcpup, dbstart;
-+      struct dentry *dentry, *parent, *h_dentry;
++      aufs_bindex_t dbstart;
++      struct dentry *parent, *h_dentry;
 +      struct inode *inode;
 +      struct super_block *sb;
 +      struct file *h_file;
++      struct au_cp_generic cpg = {
++              .dentry = file->f_dentry,
++              .bdst   = -1,
++              .bsrc   = -1,
++              .len    = len,
++              .pin    = pin,
++              .flags  = AuCpup_DTIME
++      };
 +
-+      dentry = file->f_dentry;
-+      sb = dentry->d_sb;
-+      inode = dentry->d_inode;
++      sb = cpg.dentry->d_sb;
++      inode = cpg.dentry->d_inode;
 +      AuDebugOn(au_special_file(inode->i_mode));
-+      bstart = au_fbstart(file);
-+      err = au_test_ro(sb, bstart, inode);
++      cpg.bsrc = au_fbstart(file);
++      err = au_test_ro(sb, cpg.bsrc, inode);
 +      if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
-+              err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
++              err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE,
++                           /*flags*/0);
 +              goto out;
 +      }
 +
 +      /* need to cpup or reopen */
-+      parent = dget_parent(dentry);
++      parent = dget_parent(cpg.dentry);
 +      di_write_lock_parent(parent);
-+      err = AuWbrCopyup(au_sbi(sb), dentry);
-+      bcpup = err;
++      err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
++      cpg.bdst = err;
 +      if (unlikely(err < 0))
 +              goto out_dgrade;
 +      err = 0;
 +
-+      if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
-+              err = au_cpup_dirs(dentry, bcpup);
++      if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) {
++              err = au_cpup_dirs(cpg.dentry, cpg.bdst);
 +              if (unlikely(err))
 +                      goto out_dgrade;
 +      }
 +
-+      err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
++      err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
 +                   AuPin_DI_LOCKED | AuPin_MNT_WRITE);
 +      if (unlikely(err))
 +              goto out_dgrade;
 +
 +      h_dentry = au_hf_top(file)->f_dentry;
-+      dbstart = au_dbstart(dentry);
-+      if (dbstart <= bcpup) {
-+              h_dentry = au_h_dptr(dentry, bcpup);
++      dbstart = au_dbstart(cpg.dentry);
++      if (dbstart <= cpg.bdst) {
++              h_dentry = au_h_dptr(cpg.dentry, cpg.bdst);
 +              AuDebugOn(!h_dentry);
-+              bstart = bcpup;
++              cpg.bsrc = cpg.bdst;
 +      }
 +
-+      if (dbstart <= bcpup            /* just reopen */
-+          || !d_unhashed(dentry)      /* copyup and reopen */
++      if (dbstart <= cpg.bdst         /* just reopen */
++          || !d_unhashed(cpg.dentry)  /* copyup and reopen */
 +              ) {
-+              h_file = au_h_open_pre(dentry, bstart);
++              h_file = au_h_open_pre(cpg.dentry, cpg.bsrc);
 +              if (IS_ERR(h_file))
 +                      err = PTR_ERR(h_file);
 +              else {
 +                      di_downgrade_lock(parent, AuLock_IR);
-+                      if (dbstart > bcpup)
-+                              err = au_sio_cpup_simple(dentry, bcpup, len,
-+                                                       AuCpup_DTIME, pin);
++                      if (dbstart > cpg.bdst)
++                              err = au_sio_cpup_simple(&cpg);
 +                      if (!err)
 +                              err = au_reopen_nondir(file);
-+                      au_h_open_post(dentry, bstart, h_file);
++                      au_h_open_post(cpg.dentry, cpg.bsrc, h_file);
 +              }
 +      } else {                        /* copyup as wh and reopen */
 +              /*
 +               * since writable hfsplus branch is not supported,
 +               * h_open_pre/post() are unnecessary.
 +               */
-+              err = au_ready_to_write_wh(file, len, bcpup, pin);
++              err = au_ready_to_write_wh(file, len, cpg.bdst, pin);
 +              di_downgrade_lock(parent, AuLock_IR);
 +      }
 +
@@ -10619,29 +10661,35 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
 +{
 +      int err;
-+      aufs_bindex_t bstart;
 +      struct au_pin pin;
 +      struct au_finfo *finfo;
-+      struct dentry *dentry, *parent, *hi_wh;
++      struct dentry *parent, *hi_wh;
 +      struct inode *inode;
 +      struct super_block *sb;
++      struct au_cp_generic cpg = {
++              .dentry = file->f_dentry,
++              .bdst   = -1,
++              .bsrc   = -1,
++              .len    = -1,
++              .pin    = &pin,
++              .flags  = AuCpup_DTIME
++      };
 +
 +      FiMustWriteLock(file);
 +
 +      err = 0;
 +      finfo = au_fi(file);
-+      dentry = file->f_dentry;
-+      sb = dentry->d_sb;
-+      inode = dentry->d_inode;
-+      bstart = au_ibstart(inode);
-+      if (bstart == finfo->fi_btop || IS_ROOT(dentry))
++      sb = cpg.dentry->d_sb;
++      inode = cpg.dentry->d_inode;
++      cpg.bdst = au_ibstart(inode);
++      if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry))
 +              goto out;
 +
-+      parent = dget_parent(dentry);
-+      if (au_test_ro(sb, bstart, inode)) {
++      parent = dget_parent(cpg.dentry);
++      if (au_test_ro(sb, cpg.bdst, inode)) {
 +              di_read_lock_parent(parent, !AuLock_IR);
-+              err = AuWbrCopyup(au_sbi(sb), dentry);
-+              bstart = err;
++              err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
++              cpg.bdst = err;
 +              di_read_unlock(parent, !AuLock_IR);
 +              if (unlikely(err < 0))
 +                      goto out_parent;
@@ -10649,27 +10697,26 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +      }
 +
 +      di_read_lock_parent(parent, AuLock_IR);
-+      hi_wh = au_hi_wh(inode, bstart);
++      hi_wh = au_hi_wh(inode, cpg.bdst);
 +      if (!S_ISDIR(inode->i_mode)
 +          && au_opt_test(au_mntflags(sb), PLINK)
 +          && au_plink_test(inode)
-+          && !d_unhashed(dentry)
-+          && bstart < au_dbstart(dentry)) {
-+              err = au_test_and_cpup_dirs(dentry, bstart);
++          && !d_unhashed(cpg.dentry)
++          && cpg.bdst < au_dbstart(cpg.dentry)) {
++              err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst);
 +              if (unlikely(err))
 +                      goto out_unlock;
 +
 +              /* always superio. */
-+              err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE,
++              err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
 +                           AuPin_DI_LOCKED | AuPin_MNT_WRITE);
 +              if (!err) {
-+                      err = au_sio_cpup_simple(dentry, bstart, -1,
-+                                               AuCpup_DTIME, &pin);
++                      err = au_sio_cpup_simple(&cpg);
 +                      au_unpin(&pin);
 +              }
 +      } else if (hi_wh) {
 +              /* already copied-up after unlink */
-+              err = au_reopen_wh(file, bstart, hi_wh);
++              err = au_reopen_wh(file, cpg.bdst, hi_wh);
 +              *need_reopen = 0;
 +      }
 +
@@ -10939,8 +10986,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       2013-07-06 13:20:47.750198454 +0200
-@@ -0,0 +1,308 @@
++++ linux/fs/aufs/file.h       2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,310 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -11086,6 +11133,8 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +#ifdef CONFIG_COMPAT
 +long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
 +                         unsigned long arg);
++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
++                            unsigned long arg);
 +#endif
 +
 +/* ---------------------------------------------------------------------- */
@@ -11412,7 +11461,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       2013-07-30 22:42:55.839613269 +0200
++++ linux/fs/aufs/f_op.c       2013-08-23 23:59:39.634916914 +0200
 @@ -0,0 +1,721 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
@@ -12118,7 +12167,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +#endif
 +      .unlocked_ioctl = aufs_ioctl_nondir,
 +#ifdef CONFIG_COMPAT
-+      .compat_ioctl   = aufs_ioctl_nondir, /* same */
++      .compat_ioctl   = aufs_compat_ioctl_nondir,
 +#endif
 +      .mmap           = aufs_mmap,
 +      .open           = aufs_open_nondir,
@@ -12137,8 +12186,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +};
 diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 --- /usr/share/empty/fs/aufs/f_op_sp.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/f_op_sp.c    2013-07-06 13:20:47.750198454 +0200
-@@ -0,0 +1,376 @@
++++ linux/fs/aufs/f_op_sp.c    2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,383 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -12178,7 +12227,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 +
 +struct au_finfo_sp {
 +      struct hlist_node       hlist;
-+      struct file             *file;
++      struct file             *file;
 +      struct au_finfo         *finfo;
 +};
 +
@@ -12388,12 +12437,19 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 +static int au_cpup_sp(struct dentry *dentry)
 +{
 +      int err;
-+      aufs_bindex_t bcpup;
 +      struct au_pin pin;
 +      struct au_wr_dir_args wr_dir_args = {
 +              .force_btgt     = -1,
 +              .flags          = 0
 +      };
++      struct au_cp_generic cpg = {
++              .dentry = dentry,
++              .bdst   = -1,
++              .bsrc   = -1,
++              .len    = -1,
++              .pin    = &pin,
++              .flags  = AuCpup_DTIME
++      };
 +
 +      AuDbg("%.*s\n", AuDLNPair(dentry));
 +
@@ -12402,15 +12458,15 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 +      err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
 +      if (unlikely(err < 0))
 +              goto out;
-+      bcpup = err;
++      cpg.bdst = err;
 +      err = 0;
-+      if (bcpup == au_dbstart(dentry))
++      if (cpg.bdst == au_dbstart(dentry))
 +              goto out; /* success */
 +
-+      err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb),
++      err = au_pin(&pin, dentry, cpg.bdst, au_opt_udba(dentry->d_sb),
 +                   AuPin_MNT_WRITE);
 +      if (!err) {
-+              err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME, &pin);
++              err = au_sio_cpup_simple(&cpg);
 +              au_unpin(&pin);
 +      }
 +
@@ -12517,8 +12573,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op_sp.c linux/fs/aufs/f_op_sp.c
 +}
 diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 --- /usr/share/empty/fs/aufs/fstype.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/fstype.h     2013-07-06 13:20:47.750198454 +0200
-@@ -0,0 +1,480 @@
++++ linux/fs/aufs/fstype.h     2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,470 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -12631,15 +12687,6 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 +#endif
 +}
 +
-+static inline int au_test_smbfs(struct super_block *sb __maybe_unused)
-+{
-+#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE)
-+      return sb->s_magic == SMB_SUPER_MAGIC;
-+#else
-+      return 0;
-+#endif
-+}
-+
 +static inline int au_test_ocfs2(struct super_block *sb __maybe_unused)
 +{
 +#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE)
@@ -12678,7 +12725,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 +
 +static inline int au_test_ext4(struct super_block *sb __maybe_unused)
 +{
-+#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE)
++#if defined(CONFIG_EXT4_FS) || defined(CONFIG_EXT4_FS_MODULE)
 +      return sb->s_magic == EXT4_SUPER_MAGIC;
 +#else
 +      return 0;
@@ -12886,7 +12933,6 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
 +{
 +      return au_test_nfs(sb)
 +              || au_test_fuse(sb)
-+              /* || au_test_smbfs(sb) */      /* untested */
 +              /* || au_test_ocfs2(sb) */      /* untested */
 +              /* || au_test_btrfs(sb) */      /* untested */
 +              /* || au_test_coda(sb) */       /* untested */
@@ -15457,8 +15503,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      2013-07-06 13:20:47.750198454 +0200
-@@ -0,0 +1,196 @@
++++ linux/fs/aufs/ioctl.c      2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,202 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -15481,8 +15527,11 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 + * ioctl
 + * plink-management and readdir in userspace.
 + * assist the pathconf(3) wrapper library.
++ * move-down
 + */
 +
++#include <linux/compat.h>
++#include <linux/file.h>
 +#include "aufs.h"
 +
 +static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg)
@@ -15609,6 +15658,11 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +      long err;
 +
 +      switch (cmd) {
++      case AUFS_CTL_MVDOWN:
++              WARN_ONCE(1, "move-down is still testing...\n");
++              err = au_mvdown(file->f_dentry, (void __user *)arg);
++              break;
++
 +      case AUFS_CTL_WBR_FD:
 +              err = au_wbr_fd(&file->f_path, (void __user *)arg);
 +              break;
@@ -15647,18 +15701,16 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +      return err;
 +}
 +
-+#if 0 /* unused yet */
 +long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
 +                            unsigned long arg)
 +{
 +      return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg));
 +}
 +#endif
-+#endif
 diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 --- /usr/share/empty/fs/aufs/i_op_add.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_add.c   2013-07-30 22:42:46.235946055 +0200
-@@ -0,0 +1,716 @@
++++ linux/fs/aufs/i_op_add.c   2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,739 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -15895,47 +15947,55 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      int err;
 +      aufs_bindex_t bstart;
 +      unsigned char created;
-+      struct au_dtime dt;
-+      struct au_pin pin;
-+      struct path h_path;
 +      struct dentry *wh_dentry, *parent;
 +      struct inode *h_dir;
-+      struct au_wr_dir_args wr_dir_args = {
-+              .force_btgt     = -1,
-+              .flags          = AuWrDir_ADD_ENTRY
-+      };
++      /* to reuduce stack size */
++      struct {
++              struct au_dtime dt;
++              struct au_pin pin;
++              struct path h_path;
++              struct au_wr_dir_args wr_dir_args;
++      } *a;
 +
 +      AuDbg("%.*s\n", AuDLNPair(dentry));
 +      IMustLock(dir);
 +
++      err = -ENOMEM;
++      a = kmalloc(sizeof(*a), GFP_NOFS);
++      if (unlikely(!a))
++              goto out;
++      a->wr_dir_args.force_btgt = -1;
++      a->wr_dir_args.flags = AuWrDir_ADD_ENTRY;
++
 +      parent = dentry->d_parent; /* dir inode is locked */
 +      err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
 +      if (unlikely(err))
-+              goto out;
++              goto out_free;
 +      err = au_d_may_add(dentry);
 +      if (unlikely(err))
 +              goto out_unlock;
 +      di_write_lock_parent(parent);
-+      wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
-+                                    &wr_dir_args);
++      wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
++                                    &a->pin, &a->wr_dir_args);
 +      err = PTR_ERR(wh_dentry);
 +      if (IS_ERR(wh_dentry))
 +              goto out_parent;
 +
 +      bstart = au_dbstart(dentry);
-+      h_path.dentry = au_h_dptr(dentry, bstart);
-+      h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
-+      h_dir = au_pinned_h_dir(&pin);
++      a->h_path.dentry = au_h_dptr(dentry, bstart);
++      a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++      h_dir = au_pinned_h_dir(&a->pin);
 +      switch (arg->type) {
 +      case Creat:
-+              err = vfsub_create(h_dir, &h_path, arg->u.c.mode,
++              err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode,
 +                                 arg->u.c.want_excl);
 +              break;
 +      case Symlink:
-+              err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname);
++              err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname);
 +              break;
 +      case Mknod:
-+              err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev);
++              err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode,
++                                arg->u.m.dev);
 +              break;
 +      default:
 +              BUG();
@@ -15945,18 +16005,18 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +              err = epilog(dir, bstart, wh_dentry, dentry);
 +
 +      /* revert */
-+      if (unlikely(created && err && h_path.dentry->d_inode)) {
++      if (unlikely(created && err && a->h_path.dentry->d_inode)) {
 +              int rerr;
-+              rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++              rerr = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +              if (rerr) {
 +                      AuIOErr("%.*s revert failure(%d, %d)\n",
 +                              AuDLNPair(dentry), err, rerr);
 +                      err = -EIO;
 +              }
-+              au_dtime_revert(&dt);
++              au_dtime_revert(&a->dt);
 +      }
 +
-+      au_unpin(&pin);
++      au_unpin(&a->pin);
 +      dput(wh_dentry);
 +
 +out_parent:
@@ -15967,6 +16027,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +              d_drop(dentry);
 +      }
 +      aufs_read_unlock(dentry, AuLock_DW);
++out_free:
++      kfree(a);
 +out:
 +      return err;
 +}
@@ -16020,6 +16082,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +{
 +      int err;
 +      struct dentry *h_src_dentry;
++      struct au_cp_generic cpg = {
++              .dentry = src_dentry,
++              .bdst   = a->bdst,
++              .bsrc   = a->bsrc,
++              .len    = -1,
++              .pin    = &a->pin,
++              .flags  = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */
++      };
 +
 +      di_read_lock_parent(a->src_parent, AuLock_IR);
 +      err = au_test_and_cpup_dirs(src_dentry, a->bdst);
@@ -16033,9 +16103,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +      if (unlikely(err))
 +              goto out;
 +
-+      err = au_sio_cpup_simple_h_open(src_dentry, a->bdst, -1,
-+                                      AuCpup_DTIME /* | AuCpup_KEEPLINO */,
-+                                      &a->pin, a->bsrc);
++      err = au_sio_cpup_simple(&cpg);
 +      au_unpin(&a->pin);
 +
 +out:
@@ -16074,8 +16142,15 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +              if (IS_ERR(h_file))
 +                      err = PTR_ERR(h_file);
 +              else {
-+                      err = au_sio_cpup_simple(dentry, a->bdst, -1,
-+                                               AuCpup_KEEPLINO, &a->pin);
++                      struct au_cp_generic cpg = {
++                              .dentry = dentry,
++                              .bdst   = a->bdst,
++                              .bsrc   = -1,
++                              .len    = -1,
++                              .pin    = &a->pin,
++                              .flags  = AuCpup_KEEPLINO
++                      };
++                      err = au_sio_cpup_simple(&cpg);
 +                      au_h_open_post(dentry, a->bsrc, h_file);
 +                      if (!err) {
 +                              dput(a->h_path.dentry);
@@ -16377,8 +16452,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       2013-07-30 22:42:46.235946055 +0200
-@@ -0,0 +1,1100 @@
++++ linux/fs/aufs/i_op.c       2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,1115 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -16641,10 +16716,12 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +
 +      err = 0;
 +      if (!au_h_dptr(parent, bcpup)) {
-+              if (bstart < bcpup)
++              if (bstart > bcpup)
++                      err = au_cpup_dirs(dentry, bcpup);
++              else if (bstart < bcpup)
 +                      err = au_cpdown_dirs(dentry, bcpup);
 +              else
-+                      err = au_cpup_dirs(dentry, bcpup);
++                      BUG();
 +      }
 +      if (!err && add_entry) {
 +              h_parent = au_h_dptr(parent, bcpup);
@@ -17056,8 +17133,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +      if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) {
 +              hi_wh = au_hi_wh(inode, a->btgt);
 +              if (!hi_wh) {
-+                      err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL,
-+                                           &a->pin);
++                      struct au_cp_generic cpg = {
++                              .dentry = dentry,
++                              .bdst   = a->btgt,
++                              .bsrc   = -1,
++                              .len    = sz,
++                              .pin    = &a->pin
++                      };
++                      err = au_sio_cpup_wh(&cpg, /*file*/NULL);
 +                      if (unlikely(err))
 +                              goto out_unlock;
 +                      hi_wh = au_hi_wh(inode, a->btgt);
@@ -17075,8 +17158,15 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +              goto out; /* success */
 +
 +      if (!d_unhashed(dentry)) {
-+              err = au_sio_cpup_simple_h_open(dentry, a->btgt, sz,
-+                                              AuCpup_DTIME, &a->pin, bstart);
++              struct au_cp_generic cpg = {
++                      .dentry = dentry,
++                      .bdst   = a->btgt,
++                      .bsrc   = bstart,
++                      .len    = sz,
++                      .pin    = &a->pin,
++                      .flags  = AuCpup_DTIME | AuCpup_HOPEN
++              };
++              err = au_sio_cpup_simple(&cpg);
 +              if (!err)
 +                      a->h_path.dentry = au_h_dptr(dentry, a->btgt);
 +      } else if (!hi_wh)
@@ -17481,8 +17571,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +};
 diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 --- /usr/share/empty/fs/aufs/i_op_del.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_del.c   2013-07-06 13:20:47.750198454 +0200
-@@ -0,0 +1,477 @@
++++ linux/fs/aufs/i_op_del.c   2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,502 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -17784,17 +17874,25 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +{
 +      int err;
 +      aufs_bindex_t bwh, bindex, bstart;
-+      struct au_dtime dt;
-+      struct au_pin pin;
-+      struct path h_path;
 +      struct inode *inode, *h_dir;
 +      struct dentry *parent, *wh_dentry;
++      /* to reuduce stack size */
++      struct {
++              struct au_dtime dt;
++              struct au_pin pin;
++              struct path h_path;
++      } *a;
 +
 +      IMustLock(dir);
 +
++      err = -ENOMEM;
++      a = kmalloc(sizeof(*a), GFP_NOFS);
++      if (unlikely(!a))
++              goto out;
++
 +      err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
 +      if (unlikely(err))
-+              goto out;
++              goto out_free;
 +      err = au_d_hashed_positive(dentry);
 +      if (unlikely(err))
 +              goto out_unlock;
@@ -17809,17 +17907,18 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +      bindex = -1;
 +      parent = dentry->d_parent; /* dir inode is locked */
 +      di_write_lock_parent(parent);
-+      wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
++      wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt,
++                                      &a->pin);
 +      err = PTR_ERR(wh_dentry);
 +      if (IS_ERR(wh_dentry))
 +              goto out_parent;
 +
-+      h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
-+      h_path.dentry = au_h_dptr(dentry, bstart);
-+      dget(h_path.dentry);
++      a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++      a->h_path.dentry = au_h_dptr(dentry, bstart);
++      dget(a->h_path.dentry);
 +      if (bindex == bstart) {
-+              h_dir = au_pinned_h_dir(&pin);
-+              err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++              h_dir = au_pinned_h_dir(&a->pin);
++              err = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +      } else {
 +              /* dir inode is locked */
 +              h_dir = wh_dentry->d_parent->d_inode;
@@ -17833,8 +17932,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +
 +              /* update target timestamps */
 +              if (bindex == bstart) {
-+                      vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
-+                      inode->i_ctime = h_path.dentry->d_inode->i_ctime;
++                      vfsub_update_h_iattr(&a->h_path, /*did*/NULL);
++                      /*ignore*/
++                      inode->i_ctime = a->h_path.dentry->d_inode->i_ctime;
 +              } else
 +                      /* todo: this timestamp may be reverted later */
 +                      inode->i_ctime = h_dir->i_ctime;
@@ -17845,19 +17945,22 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +      if (wh_dentry) {
 +              int rerr;
 +
-+              rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++              rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry,
++                               &a->dt);
 +              if (rerr)
 +                      err = rerr;
 +      }
 +
 +out_unpin:
-+      au_unpin(&pin);
++      au_unpin(&a->pin);
 +      dput(wh_dentry);
-+      dput(h_path.dentry);
++      dput(a->h_path.dentry);
 +out_parent:
 +      di_write_unlock(parent);
 +out_unlock:
 +      aufs_read_unlock(dentry, AuLock_DW);
++out_free:
++      kfree(a);
 +out:
 +      return err;
 +}
@@ -17866,17 +17969,25 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +{
 +      int err, rmdir_later;
 +      aufs_bindex_t bwh, bindex, bstart;
-+      struct au_dtime dt;
-+      struct au_pin pin;
 +      struct inode *inode;
 +      struct dentry *parent, *wh_dentry, *h_dentry;
 +      struct au_whtmp_rmdir *args;
++      /* to reuduce stack size */
++      struct {
++              struct au_dtime dt;
++              struct au_pin pin;
++      } *a;
 +
 +      IMustLock(dir);
 +
++      err = -ENOMEM;
++      a = kmalloc(sizeof(*a), GFP_NOFS);
++      if (unlikely(!a))
++              goto out;
++
 +      err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
 +      if (unlikely(err))
-+              goto out;
++              goto out_free;
 +      err = au_alive_dir(dentry);
 +      if (unlikely(err))
 +              goto out_unlock;
@@ -17900,7 +18011,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +      bstart = au_dbstart(dentry);
 +      bwh = au_dbwh(dentry);
 +      bindex = -1;
-+      wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
++      wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt,
++                                      &a->pin);
 +      err = PTR_ERR(wh_dentry);
 +      if (IS_ERR(wh_dentry))
 +              goto out_parent;
@@ -17941,13 +18053,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +      if (wh_dentry) {
 +              int rerr;
 +
-+              rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
++              rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry,
++                               &a->dt);
 +              if (rerr)
 +                      err = rerr;
 +      }
 +
 +out_unpin:
-+      au_unpin(&pin);
++      au_unpin(&a->pin);
 +      dput(wh_dentry);
 +      dput(h_dentry);
 +out_parent:
@@ -17956,14 +18069,16 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +              au_whtmp_rmdir_free(args);
 +out_unlock:
 +      aufs_read_unlock(dentry, AuLock_DW);
++out_free:
++      kfree(a);
 +out:
 +      AuTraceErr(err);
 +      return err;
 +}
 diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 --- /usr/share/empty/fs/aufs/i_op_ren.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_ren.c   2013-07-30 22:42:46.235946055 +0200
-@@ -0,0 +1,1045 @@
++++ linux/fs/aufs/i_op_ren.c   2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,1009 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -18174,33 +18289,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +              AuDebugOn(au_dbstart(d) != a->btgt);
 +              err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
 +                                 a->dst_h_dir, &a->h_path);
-+      } else {
-+#if 1
++      } else
 +              BUG();
-+#else
-+              struct file *h_file;
 +
-+              au_fset_ren(a->flags, CPUP);
-+              au_set_dbstart(d, a->btgt);
-+              au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
-+              h_file = au_h_open_pre(d, a->src_bstart);
-+              if (IS_ERR(h_file))
-+                      err = PTR_ERR(h_file);
-+              else {
-+                      err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
-+                                               !AuCpup_DTIME, a->dst_parent);
-+                      au_h_open_post(d, a->src_bstart, h_file);
-+              }
-+              if (!err) {
-+                      d = a->dst_dentry;
-+                      au_set_h_dptr(d, a->btgt, NULL);
-+                      au_update_dbstart(d);
-+              } else {
-+                      au_set_h_dptr(d, a->btgt, NULL);
-+                      au_set_dbstart(d, a->src_bstart);
-+              }
-+#endif
-+      }
 +      if (!err && a->h_dst)
 +              /* it will be set to dinfo later */
 +              dget(a->h_dst);
@@ -18307,25 +18398,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +              a->dst_h_dentry = au_h_dptr(d, a->btgt);
 +      }
 +
-+      /* cpup src */
-+      if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) {
-+#if 1
-+              BUG();
-+#else
-+              struct file *h_file;
-+
-+              h_file = au_h_open_pre(a->src_dentry, a->src_bstart);
-+              if (IS_ERR(h_file))
-+                      err = PTR_ERR(h_file);
-+              else {
-+                      err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
-+                                               !AuCpup_DTIME);
-+                      au_h_open_post(a->src_dentry, a->src_bstart, h_file);
-+              }
-+              if (unlikely(err))
-+                      goto out_whtmp;
-+#endif
-+      }
++      BUG_ON(a->dst_h_dentry->d_inode && a->src_bstart != a->btgt);
 +
 +      /* rename by vfs_rename or cpup */
 +      d = a->dst_dentry;
@@ -18933,10 +19006,16 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +                           au_opt_udba(a->src_dentry->d_sb),
 +                           AuPin_DI_LOCKED | AuPin_MNT_WRITE);
 +              if (!err) {
++                      struct au_cp_generic cpg = {
++                              .dentry = a->src_dentry,
++                              .bdst   = a->btgt,
++                              .bsrc   = a->src_bstart,
++                              .len    = -1,
++                              .pin    = &pin,
++                              .flags  = AuCpup_DTIME | AuCpup_HOPEN
++                      };
 +                      AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart);
-+                      err = au_sio_cpup_simple_h_open(a->src_dentry, a->btgt,
-+                                                      -1, AuCpup_DTIME, &pin,
-+                                                      a->src_bstart);
++                      err = au_sio_cpup_simple(&cpg);
 +                      au_unpin(&pin);
 +              }
 +              if (unlikely(err))
@@ -19468,7 +19547,7 @@ 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     2013-07-06 13:20:47.736864659 +0200
++++ linux/fs/aufs/Makefile     2013-08-23 23:59:39.631583456 +0200
 @@ -0,0 +1,42 @@
 +
 +include ${src}/magic.mk
@@ -19496,7 +19575,7 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +      finfo.o file.o f_op.o \
 +      dir.o vdir.o \
 +      iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
-+      ioctl.o
++      mvdown.o ioctl.o
 +
 +# all are boolean
 +aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
@@ -19828,8 +19907,545 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 +
 +#endif /* __KERNEL__ */
 +#endif /* __AUFS_MODULE_H__ */
-diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
---- /usr/share/empty/fs/aufs/opts.c    1970-01-01 01:00:00.000000000 +0100
+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     2013-08-23 23:59:39.634916914 +0200
+@@ -0,0 +1,533 @@
++/*
++ * Copyright (C) 2011-2013 Junjiro R. Okajima
++ *
++ * This program, aufs is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include "aufs.h"
++
++enum {
++      AUFS_MVDOWN_SRC,
++      AUFS_MVDOWN_DST,
++      AUFS_MVDOWN_NARRAY
++};
++
++struct au_mvd_args {
++      struct {
++              aufs_bindex_t bindex;
++              struct super_block *h_sb;
++              struct dentry *h_parent;
++              struct au_hinode *hdir;
++              struct inode *h_dir;
++      } info[AUFS_MVDOWN_NARRAY];
++
++      struct aufs_mvdown mvdown;
++      struct dentry *dentry, *parent;
++      struct inode *inode, *dir;
++      struct super_block *sb;
++      aufs_bindex_t bopq, bwh, bfound;
++      unsigned char rename_lock;
++      struct au_pin pin;
++};
++
++#define mvd_bsrc              info[AUFS_MVDOWN_SRC].bindex
++#define mvd_h_src_sb          info[AUFS_MVDOWN_SRC].h_sb
++#define mvd_h_src_parent      info[AUFS_MVDOWN_SRC].h_parent
++#define mvd_hdir_src          info[AUFS_MVDOWN_SRC].hdir
++#define mvd_h_src_dir         info[AUFS_MVDOWN_SRC].h_dir
++
++#define mvd_bdst              info[AUFS_MVDOWN_DST].bindex
++#define mvd_h_dst_sb          info[AUFS_MVDOWN_DST].h_sb
++#define mvd_h_dst_parent      info[AUFS_MVDOWN_DST].h_parent
++#define mvd_hdir_dst          info[AUFS_MVDOWN_DST].hdir
++#define mvd_h_dst_dir         info[AUFS_MVDOWN_DST].h_dir
++
++#define AU_MVD_PR(flag, ...) do {                     \
++              if (flag)                               \
++                      pr_err(__VA_ARGS__);            \
++      } while (0)
++
++/* make the parent dir on bdst */
++static int au_do_mkdir(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++
++      err = 0;
++      a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc);
++      a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst);
++      a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc);
++      a->mvd_h_dst_parent = NULL;
++      if (au_dbend(a->parent) >= a->mvd_bdst)
++              a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
++      if (!a->mvd_h_dst_parent) {
++              err = au_cpdown_dirs(a->dentry, a->mvd_bdst);
++              if (unlikely(err)) {
++                      AU_MVD_PR(verbose, "cpdown_dirs failed\n");
++                      goto out;
++              }
++              a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
++      }
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++/* lock them all */
++static int au_do_lock(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++      struct dentry *h_trap;
++
++      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);
++      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(verbose, "pin failed\n");
++              goto out;
++      }
++
++      err = 0;
++      a->rename_lock = 1;
++      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) {
++              err = (h_trap != a->mvd_h_src_parent);
++              if (err)
++                      err = (h_trap != a->mvd_h_dst_parent);
++      }
++      BUG_ON(err); /* it should never happen */
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++static void au_do_unlock(const unsigned char verbose, struct au_mvd_args *a)
++{
++      if (!a->rename_lock) {
++              mutex_unlock(&a->mvd_h_src_dir->i_mutex);
++              au_unpin(&a->pin);
++      } else
++              vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
++                                  a->mvd_h_dst_parent, a->mvd_hdir_dst);
++}
++
++/* copy-down the file */
++static int au_do_cpdown(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++      struct au_cp_generic cpg = {
++              .dentry = a->dentry,
++              .bdst   = a->mvd_bdst,
++              .bsrc   = a->mvd_bsrc,
++              .len    = -1,
++              .pin    = &a->pin,
++              .flags  = AuCpup_DTIME | AuCpup_HOPEN
++      };
++
++      AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst);
++      err = au_sio_cpdown_simple(&cpg);
++      if (unlikely(err))
++              AU_MVD_PR(verbose, "cpdown failed\n");
++
++      AuTraceErr(err);
++      return err;
++}
++
++/*
++ * unlink the whiteout on bdst if exist which may be created by UDBA while we
++ * were sleeping
++ */
++static int au_do_unlink_wh(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++      struct path h_path;
++      struct au_branch *br;
++
++      br = au_sbr(a->sb, a->mvd_bdst);
++      h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br);
++      err = PTR_ERR(h_path.dentry);
++      if (IS_ERR(h_path.dentry)) {
++              AU_MVD_PR(verbose, "wh_lkup failed\n");
++              goto out;
++      }
++
++      err = 0;
++      if (h_path.dentry->d_inode) {
++              h_path.mnt = au_br_mnt(br);
++              err = vfsub_unlink(a->mvd_h_dst_parent->d_inode, &h_path,
++                                 /*force*/0);
++              if (unlikely(err))
++                      AU_MVD_PR(verbose, "wh_unlink failed\n");
++      }
++      dput(h_path.dentry);
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++/*
++ * 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 verbose, struct au_mvd_args *a)
++{
++      int err;
++      struct path h_path;
++
++      h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc);
++      h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc);
++      err = vfsub_unlink(a->mvd_h_src_dir, &h_path, /*force*/0);
++      if (unlikely(err))
++              AU_MVD_PR(verbose, "unlink failed\n");
++
++      AuTraceErr(err);
++      return err;
++}
++
++/*
++ * copy-down the file and unlink the bsrc file.
++ * - unlink the bdst whout if exist
++ * - copy-down the file (with whtmp name and rename)
++ * - unlink the bsrc file
++ */
++static int au_do_mvdown(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++
++      err = au_do_mkdir(verbose, a);
++      if (!err)
++              err = au_do_lock(verbose, a);
++      if (unlikely(err))
++              goto out;
++
++      /*
++       * do not revert the activities we made on bdst since they should be
++       * harmless in aufs.
++       */
++
++      err = au_do_cpdown(verbose, a);
++      if (!err)
++              err = au_do_unlink_wh(verbose, a);
++      if (!err)
++              err = au_do_unlink(verbose, a);
++      if (unlikely(err))
++              goto out_unlock;
++
++      /* maintain internal array */
++      au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL);
++      au_set_dbstart(a->dentry, a->mvd_bdst);
++      if (au_dbend(a->dentry) < a->mvd_bdst)
++              au_set_dbend(a->dentry, a->mvd_bdst);
++      au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0);
++      au_set_ibstart(a->inode, a->mvd_bdst);
++      if (au_ibend(a->inode) < a->mvd_bdst)
++              au_set_ibend(a->inode, a->mvd_bdst);
++
++out_unlock:
++      au_do_unlock(verbose, a);
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int find_lower_writable(struct super_block *sb, aufs_bindex_t bindex)
++{
++      aufs_bindex_t bend;
++      struct au_branch *br;
++
++      bend = au_sbend(sb);
++      for (bindex++; bindex <= bend; bindex++) {
++              br = au_sbr(sb, bindex);
++              if (!au_br_rdonly(br))
++                      return bindex;
++      }
++
++      return -1;
++}
++
++/* make sure the file is idle */
++static int au_mvd_args_busy(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err, plinked;
++      struct inode *h_src_inode;
++
++      err = 0;
++      h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc);
++      plinked = !!au_opt_test(au_mntflags(a->sb), PLINK);
++      if (au_dbstart(a->dentry) == a->mvd_bsrc
++          && a->dentry->d_count == 1
++          && atomic_read(&a->inode->i_count) == 1
++          /* && h_src_inode->i_nlink == 1 */
++          && (!plinked || !au_plink_test(a->inode))
++          && a->inode->i_nlink == 1)
++              goto out;
++
++      err = -EBUSY;
++      AU_MVD_PR(verbose,
++                "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), a->dentry->d_count,
++                atomic_read(&a->inode->i_count), a->inode->i_nlink,
++                h_src_inode->i_nlink,
++                plinked, plinked ? au_plink_test(a->inode) : 0);
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++/* make sure the parent dir is fine */
++static int au_mvd_args_parent(const unsigned char verbose,
++                            struct au_mvd_args *a)
++{
++      int err;
++      aufs_bindex_t bindex;
++
++      err = 0;
++      if (unlikely(au_alive_dir(a->parent))) {
++              err = -ENOENT;
++              AU_MVD_PR(verbose, "parent dir is dead\n");
++              goto out;
++      }
++
++      a->bopq = au_dbdiropq(a->parent);
++      bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst);
++      AuDbg("b%d\n", bindex);
++      if (unlikely((bindex >= 0 && bindex < a->mvd_bdst)
++                   || (a->bopq != -1 && a->bopq < a->mvd_bdst))) {
++              err = -EINVAL;
++              AU_MVD_PR(verbose, "parent dir is opaque b%d, b%d\n",
++                        a->bopq, a->mvd_bdst);
++      }
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++static int au_mvd_args_intermediate(const unsigned char verbose,
++                                  struct au_mvd_args *a)
++{
++      int err;
++      struct au_dinfo *dinfo, *tmp;
++
++      /* lookup the next lower positive entry */
++      err = -ENOMEM;
++      tmp = au_di_alloc(a->sb, AuLsc_DI_TMP);
++      if (unlikely(!tmp))
++              goto out;
++
++      a->bfound = -1;
++      a->bwh = -1;
++      dinfo = au_di(a->dentry);
++      au_di_cp(tmp, dinfo);
++      au_di_swap(tmp, dinfo);
++
++      /* returns the number of positive dentries */
++      err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0);
++      if (!err)
++              a->bwh = au_dbwh(a->dentry);
++      else if (err > 0)
++              a->bfound = au_dbstart(a->dentry);
++
++      au_di_swap(tmp, dinfo);
++      au_rw_write_unlock(&tmp->di_rwsem);
++      au_di_free(tmp);
++      if (unlikely(err < 0))
++              AU_MVD_PR(verbose, "failed look-up lower\n");
++
++      /*
++       * here, we have these cases.
++       * bfound == -1
++       *      no positive dentry under bsrc. there are more sub-cases.
++       *      bwh < 0
++       *              there no whiteout, we can safely move-down.
++       *      bwh <= bsrc
++       *              impossible
++       *      bsrc < bwh && bwh < bdst
++       *              there is a whiteout on RO branch. cannot proceed.
++       *      bwh == bdst
++       *              there is a whiteout on the RW target branch. it should
++       *              be removed.
++       *      bdst < bwh
++       *              there is a whiteout somewhere unrelated branch.
++       * -1 < bfound && bfound <= bsrc
++       *      impossible.
++       * bfound < bdst
++       *      found, but it is on RO branch between bsrc and bdst. cannot
++       *      proceed.
++       * bfound == bdst
++       *      found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return
++       *      error.
++       * bdst < bfound
++       *      found, after we create the file on bdst, it will be hidden.
++       */
++
++      AuDebugOn(a->bfound == -1
++                && a->bwh != -1
++                && a->bwh <= a->mvd_bsrc);
++      AuDebugOn(-1 < a->bfound
++                && a->bfound <= a->mvd_bsrc);
++
++      err = -EINVAL;
++      if (a->bfound == -1
++          && a->mvd_bsrc < a->bwh
++          && a->bwh != -1
++          && a->bwh < a->mvd_bdst) {
++              AU_MVD_PR(verbose, "bsrc %d, bdst %d, bfound %d, bwh %d\n",
++                        a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh);
++              goto out;
++      } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) {
++              AU_MVD_PR(verbose, "bdst %d, bfound %d\n",
++                        a->mvd_bdst, a->bfound);
++              goto out;
++      }
++
++      err = 0; /* success */
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++static int au_mvd_args_exist(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++
++      err = (a->bfound != a->mvd_bdst) ? 0 : -EEXIST;
++      AuTraceErr(err);
++      return err;
++}
++
++static int au_mvd_args(const unsigned char verbose, struct au_mvd_args *a)
++{
++      int err;
++      struct au_branch *br;
++
++      err = -EISDIR;
++      if (unlikely(S_ISDIR(a->inode->i_mode)))
++              goto out;
++
++      err = -EINVAL;
++      a->mvd_bsrc = au_ibstart(a->inode);
++      if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) {
++              AU_MVD_PR(verbose, "on the bottom\n");
++              goto out;
++      }
++      br = au_sbr(a->sb, a->mvd_bsrc);
++      err = au_br_rdonly(br);
++      if (unlikely(err))
++              goto out;
++
++      err = -EINVAL;
++      a->mvd_bdst = find_lower_writable(a->sb, a->mvd_bsrc);
++      if (unlikely(a->mvd_bdst < 0)) {
++              AU_MVD_PR(verbose, "no writable lower branch\n");
++              goto out;
++      }
++
++      err = au_mvd_args_busy(verbose, a);
++      if (!err)
++              err = au_mvd_args_parent(verbose, a);
++      if (!err)
++              err = au_mvd_args_intermediate(verbose, a);
++      if (!err)
++              err = au_mvd_args_exist(verbose, a);
++      if (!err)
++              AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst);
++
++out:
++      AuTraceErr(err);
++      return err;
++}
++
++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg)
++{
++      int err;
++      unsigned char verbose;
++      struct au_mvd_args args = {
++              .dentry = dentry,
++              .inode  = dentry->d_inode,
++              .sb     = dentry->d_sb
++      };
++
++      err = -EPERM;
++      if (unlikely(!capable(CAP_SYS_ADMIN)))
++              goto out;
++
++      err = copy_from_user(&args.mvdown, uarg, sizeof(args.mvdown));
++      if (unlikely(err)) {
++              err = -EFAULT;
++              goto out;
++      }
++      AuDbg("flags 0x%x\n", args.mvdown.flags);
++
++      err = -EBUSY;
++      verbose = !!(args.mvdown.flags & AUFS_MVDOWN_VERBOSE);
++      args.parent = dget_parent(dentry);
++      args.dir = args.parent->d_inode;
++      mutex_lock_nested(&args.dir->i_mutex, I_MUTEX_PARENT);
++      dput(args.parent);
++      if (unlikely(args.parent != dentry->d_parent)) {
++              AU_MVD_PR(verbose, "parent dir is moved\n");
++              goto out_dir;
++      }
++
++      mutex_lock_nested(&args.inode->i_mutex, I_MUTEX_CHILD);
++      err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
++      if (unlikely(err))
++              goto out_inode;
++
++      di_write_lock_parent(args.parent);
++      err = au_mvd_args(verbose, &args);
++      if (unlikely(err))
++              goto out_parent;
++
++      AuDbgDentry(dentry);
++      AuDbgInode(args.inode);
++      err = au_do_mvdown(verbose, &args);
++      if (unlikely(err))
++              goto out_parent;
++      AuDbgDentry(dentry);
++      AuDbgInode(args.inode);
++
++      au_cpup_attr_timesizes(args.dir);
++      au_cpup_attr_timesizes(args.inode);
++      au_cpup_igen(args.inode, au_h_iptr(args.inode, args.mvd_bdst));
++      /* au_digen_dec(dentry); */
++
++out_parent:
++      di_write_unlock(args.parent);
++      aufs_read_unlock(dentry, AuLock_DW);
++out_inode:
++      mutex_unlock(&args.inode->i_mutex);
++out_dir:
++      mutex_unlock(&args.dir->i_mutex);
++out:
++      AuTraceErr(err);
++      return err;
++}
+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       2013-07-06 13:20:47.753531903 +0200
 @@ -0,0 +1,1697 @@
 +/*
@@ -23548,7 +24164,7 @@ 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      2013-07-06 13:20:47.753531903 +0200
++++ linux/fs/aufs/super.c      2013-08-23 23:59:39.634916914 +0200
 @@ -0,0 +1,992 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
@@ -23683,14 +24299,14 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +
 +      AuRwMustAnyLock(&sbinfo->si_rwsem);
 +
-+      seq_printf(m, ",create=");
++      seq_puts(m, ",create=");
 +      pat = au_optstr_wbr_create(v);
 +      switch (v) {
 +      case AuWbrCreate_TDP:
 +      case AuWbrCreate_RR:
 +      case AuWbrCreate_MFS:
 +      case AuWbrCreate_PMFS:
-+              seq_printf(m, pat);
++              seq_puts(m, pat);
 +              break;
 +      case AuWbrCreate_MFSV:
 +              seq_printf(m, /*pat*/"mfs:%lu",
@@ -24544,8 +25160,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      2013-07-06 13:20:47.753531903 +0200
-@@ -0,0 +1,555 @@
++++ linux/fs/aufs/super.h      2013-08-23 23:59:39.638250372 +0200
+@@ -0,0 +1,559 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -24819,6 +25435,10 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 +extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
 +extern struct au_wbr_create_operations au_wbr_create_ops[];
 +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex);
++
++/* mvdown.c */
++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg);
 +
 +/* ---------------------------------------------------------------------- */
 +
@@ -27689,8 +28309,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +#endif /* __AUFS_VFSUB_H__ */
 diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 --- /usr/share/empty/fs/aufs/wbr_policy.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wbr_policy.c 2013-07-06 13:20:47.753531903 +0200
-@@ -0,0 +1,701 @@
++++ linux/fs/aufs/wbr_policy.c 2013-08-23 23:59:39.638250372 +0200
+@@ -0,0 +1,693 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -27753,13 +28373,8 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +#define au_fclr_cpdown(flags, name) \
 +      do { (flags) &= ~AuCpdown_##name; } while (0)
 +
-+struct au_cpdown_dir_args {
-+      struct dentry *parent;
-+      unsigned int flags;
-+};
-+
 +static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
-+                           struct au_cpdown_dir_args *a)
++                           unsigned int *flags)
 +{
 +      int err;
 +      struct dentry *opq_dentry;
@@ -27769,7 +28384,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +      if (IS_ERR(opq_dentry))
 +              goto out;
 +      dput(opq_dentry);
-+      au_fset_cpdown(a->flags, DIROPQ);
++      au_fset_cpdown(*flags, DIROPQ);
 +
 +out:
 +      return err;
@@ -27809,7 +28424,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +      struct path h_path;
 +      struct dentry *parent;
 +      struct inode *h_dir, *h_inode, *inode, *dir;
-+      struct au_cpdown_dir_args *args = arg;
++      unsigned int *flags = arg;
 +
 +      bstart = au_dbstart(dentry);
 +      /* dentry is di-locked */
@@ -27828,19 +28443,19 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +                            S_IRWXU | S_IRUGO | S_IXUGO);
 +      if (unlikely(err))
 +              goto out_put;
-+      au_fset_cpdown(args->flags, MADE_DIR);
++      au_fset_cpdown(*flags, MADE_DIR);
 +
 +      bopq = au_dbdiropq(dentry);
-+      au_fclr_cpdown(args->flags, WHED);
-+      au_fclr_cpdown(args->flags, DIROPQ);
++      au_fclr_cpdown(*flags, WHED);
++      au_fclr_cpdown(*flags, DIROPQ);
 +      if (au_dbwh(dentry) == bdst)
-+              au_fset_cpdown(args->flags, WHED);
-+      if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
-+              au_fset_cpdown(args->flags, PARENT_OPQ);
++              au_fset_cpdown(*flags, WHED);
++      if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst)
++              au_fset_cpdown(*flags, PARENT_OPQ);
 +      h_inode = h_path.dentry->d_inode;
 +      mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
-+      if (au_ftest_cpdown(args->flags, WHED)) {
-+              err = au_cpdown_dir_opq(dentry, bdst, args);
++      if (au_ftest_cpdown(*flags, WHED)) {
++              err = au_cpdown_dir_opq(dentry, bdst, flags);
 +              if (unlikely(err)) {
 +                      mutex_unlock(&h_inode->i_mutex);
 +                      goto out_dir;
@@ -27852,7 +28467,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +      if (unlikely(err))
 +              goto out_opq;
 +
-+      if (au_ftest_cpdown(args->flags, WHED)) {
++      if (au_ftest_cpdown(*flags, WHED)) {
 +              err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
 +              if (unlikely(err))
 +                      goto out_opq;
@@ -27867,7 +28482,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +
 +      /* revert */
 +out_opq:
-+      if (au_ftest_cpdown(args->flags, DIROPQ)) {
++      if (au_ftest_cpdown(*flags, DIROPQ)) {
 +              mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
 +              rerr = au_diropq_remove(dentry, bdst);
 +              mutex_unlock(&h_inode->i_mutex);
@@ -27879,7 +28494,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +              }
 +      }
 +out_dir:
-+      if (au_ftest_cpdown(args->flags, MADE_DIR)) {
++      if (au_ftest_cpdown(*flags, MADE_DIR)) {
 +              rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
 +              if (unlikely(rerr)) {
 +                      AuIOErr("failed removing %.*s b%d (%d)\n",
@@ -27899,13 +28514,10 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
 +{
 +      int err;
-+      struct au_cpdown_dir_args args = {
-+              .parent = dget_parent(dentry),
-+              .flags  = 0
-+      };
++      unsigned int flags;
 +
-+      err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
-+      dput(args.parent);
++      flags = 0;
++      err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags);
 +
 +      return err;
 +}
@@ -27914,7 +28526,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +
 +/* policies for create */
 +
-+static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
 +{
 +      int err, i, j, ndentry;
 +      aufs_bindex_t bopq;
@@ -29511,7 +30123,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        2013-07-06 13:20:47.760198800 +0200
++++ linux/fs/aufs/wkq.c        2013-08-23 23:59:39.638250372 +0200
 @@ -0,0 +1,213 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
@@ -29577,7 +30189,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
 +/*
 + * Since struct completion is large, try allocating it dynamically.
 + */
-+#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS)
++#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */
 +#define AuWkqCompDeclare(name)        struct completion *comp = NULL
 +
 +static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
@@ -31115,8 +31727,8 @@ diff -urN /usr/share/empty/include/linux/aufs_type.h linux/include/linux/aufs_ty
 +#include <uapi/linux/aufs_type.h>
 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       2013-07-30 22:42:55.842946719 +0200
-@@ -0,0 +1,235 @@
++++ linux/include/uapi/linux/aufs_type.h       2013-08-23 23:59:39.638250372 +0200
+@@ -0,0 +1,251 @@
 +/*
 + * Copyright (C) 2005-2013 Junjiro R. Okajima
 + *
@@ -31159,7 +31771,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +
 +#include <linux/limits.h>
 +
-+#define AUFS_VERSION  "3.10-20130722"
++#define AUFS_VERSION  "3.10-20130819"
 +
 +/* todo? move this to linux-2.6.19/include/magic.h */
 +#define AUFS_SUPER_MAGIC      ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -31252,7 +31864,10 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +      AuCtl_WBR_FD,
 +
 +      /* busy inode */
-+      AuCtl_IBUSY
++      AuCtl_IBUSY,
++
++      /* move-down */
++      AuCtl_MVDOWN
 +};
 +
 +/* borrowed from linux/include/linux/kernel.h */
@@ -31344,12 +31959,24 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +
 +/* ---------------------------------------------------------------------- */
 +
++/* flags for move-down */
++#define AUFS_MVDOWN_VERBOSE   1
++/* will be added more */
++
++struct aufs_mvdown {
++      uint8_t         flags;
++      /* will be added more */
++} __aligned(8);
++
++/* ---------------------------------------------------------------------- */
++
 +#define AuCtlType             'A'
 +#define AUFS_CTL_RDU          _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
 +#define AUFS_CTL_RDU_INO      _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
 +#define AUFS_CTL_WBR_FD               _IOW(AuCtlType, AuCtl_WBR_FD, \
 +                                   struct aufs_wbr_fd)
 +#define AUFS_CTL_IBUSY                _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy)
++#define AUFS_CTL_MVDOWN               _IOR(AuCtlType, AuCtl_MVDOWN, \
++                                   struct aufs_mvdown)
 +
 +#endif /* __AUFS_TYPE_H__ */
-
index 19347b1e444f3f680df814bc9859ce547118f540..f3eabbdd56474770f3e15c5a5a16961db6cec01c 100644 (file)
@@ -188,7 +188,7 @@ Patch85:    kernel-hostap.patch
 # http://www.linuxtv.org/wiki/index.php/TechniSat_CableStar_Combo_HD_CI#Patch
 Patch90:       kernel-technisat-combo-hd-ci.patch
 
-# http://vserver.13thfloor.at/Experimental/patch-3.9.5-vs2.3.6.5.diff
+# http://vserver.13thfloor.at/Experimental/patch-3.10.9-vs2.3.6.6.diff
 # note there are additional patches from above url:
 # - *fix* are real fixes (we want these)
 # - *feat* are new features/tests (we don't want these)
This page took 0.337106 seconds and 4 git commands to generate.