[packages/kernel] - aufs updated but build still fails

arekm arekm at pld-linux.org
Sat Aug 24 00:05:18 CEST 2013


commit c2b27bf2e94b20b2576c4191ce00ad744682ca70
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Sat Aug 24 00:05:11 2013 +0200

    - aufs updated but build still fails

 kernel-aufs3.patch | 1565 ++++++++++++++++++++++++++++++++++++----------------
 kernel.spec        |    2 +-
 2 files changed, 1097 insertions(+), 470 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 19347b1..f3eabbd 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -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)
diff --git a/kernel-aufs3.patch b/kernel-aufs3.patch
index 653e14b..a93df4a 100644
--- a/kernel-aufs3.patch
+++ b/kernel-aufs3.patch
@@ -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__ */
-
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/c2b27bf2e94b20b2576c4191ce00ad744682ca70



More information about the pld-cvs-commit mailing list