aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <benh@debian.org>2014-09-08 01:24:43 +0000
committerBen Hutchings <benh@debian.org>2014-09-08 01:24:43 +0000
commit7f39df641306757b3deaf42ea196378c28dc98a0 (patch)
treecb253dbdce4d751c9c4716e7fc568ae94ca22e3e
parentee96a22642f49e23c0c1618128dfb98eaf6d0726 (diff)
downloadkernel_replicant_linux-7f39df641306757b3deaf42ea196378c28dc98a0.tar.gz
kernel_replicant_linux-7f39df641306757b3deaf42ea196378c28dc98a0.tar.bz2
kernel_replicant_linux-7f39df641306757b3deaf42ea196378c28dc98a0.zip
aufs: Update to aufs3.16-20140908
svn path=/dists/trunk/linux/; revision=21782
-rw-r--r--debian/changelog20
-rw-r--r--debian/config/config1
-rw-r--r--debian/patches/features/all/aufs3/aufs3-add.patch1807
-rw-r--r--debian/patches/features/all/aufs3/aufs3-base.patch33
-rw-r--r--debian/patches/features/all/aufs3/aufs3-kbuild.patch8
-rw-r--r--debian/patches/features/all/aufs3/aufs3-mmap.patch226
-rw-r--r--debian/patches/features/all/aufs3/aufs3-remove-circular-includes.patch222
-rw-r--r--debian/patches/features/all/aufs3/aufs3-standalone.patch12
-rw-r--r--debian/patches/series1
9 files changed, 1701 insertions, 629 deletions
diff --git a/debian/changelog b/debian/changelog
index dec9a9634ce7..da7e9a38def7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -44,6 +44,26 @@ linux (3.16.2-1) UNRELEASED; urgency=medium
- mnt: Add tests for unprivileged remount cases that have found to be
faulty
* [armel/kirkwood] mm: Enable HIGHMEM (Closes: #760786)
+ * aufs: Update to aufs3.16-20140908:
+ - bugfix, missing mnt_want_write in moo
+ - new ioctl BRINFO
+ - bugfix, restore the lost unlock in an error path
+ - allow deleting a branch who has an opened dir
+ - bugfix, stop passing an error code to dput()
+ - possible bugfix, ptr in an array
+ - implement fhsm (not enabled)
+ - si_files has all opened files
+ - bugfix, use id instead of index to identify a branch
+ - new move-down flag AUFS_MVDOWN_FHSM_LOWER
+ - branch attr 'fhsm' is independent from rw/ro attrib
+ - support for a branch ro+fhsm
+ - fhsm notify after fixing inode attrib
+ - bugfix, hfile test in br_del_file()
+ - bugfix, pinning in mvdown
+ - bugfix, instantiate-revalidate race
+ - possible bugfix, temporary d_inode
+ - fhsm and br_del, allow the root dir only
+ - bugfix, get a removed dentry from an inode
[ Vagrant Cascadian ]
* [armmp] Enable IMX_IPUV3_CORE (closes: #756810).
diff --git a/debian/config/config b/debian/config/config
index cba0c452a152..c5e5f95bfe64 100644
--- a/debian/config/config
+++ b/debian/config/config
@@ -4173,6 +4173,7 @@ CONFIG_AUFS_BRANCH_MAX_127=y
## end choice
# CONFIG_AUFS_HNOTIFY is not set
CONFIG_AUFS_EXPORT=y
+# CONFIG_AUFS_FHSM is not set
# CONFIG_AUFS_RDU is not set
# CONFIG_AUFS_SHWH is not set
# CONFIG_AUFS_BR_RAMFS is not set
diff --git a/debian/patches/features/all/aufs3/aufs3-add.patch b/debian/patches/features/all/aufs3/aufs3-add.patch
index fb1bc4cdb859..f015e078600a 100644
--- a/debian/patches/features/all/aufs3/aufs3-add.patch
+++ b/debian/patches/features/all/aufs3/aufs3-add.patch
@@ -1,7 +1,7 @@
From: J. R. Okajima <hooanon05@yahoo.co.jp>
-Date: Thu Jul 10 02:32:20 2014 +0900
-Subject: aufs3.x-rcN-20140714
-Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/501539c2f9478ef69fa42acfb43ef1420d9bb524/tree/
+Date: Thu Sep 4 19:46:58 2014 +0900
+Subject: aufs3.16-20140908
+Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/888949daf96bf7e2b857dc38e22029513f94d4ae/tree/
Bug-Debian: https://bugs.debian.org/541828
Patch generated by debian/patches/features/all/aufs3/gen-patch
@@ -94,8 +94,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ When the aufs mount option 'noxino' is specified, it
+ will be empty. About XINO files, see the aufs manual.
--- a/Documentation/filesystems/aufs/README 1970-01-01 01:00:00.000000000 +0100
-+++ b/Documentation/filesystems/aufs/README 2014-07-15 14:04:48.720871625 +0100
-@@ -0,0 +1,368 @@
++++ b/Documentation/filesystems/aufs/README 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,370 @@
+
+Aufs3 -- advanced multi layered unification filesystem version 3.x
+http://aufs.sf.net
@@ -447,6 +447,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+The Parted Magic Project made a donation (2013/9 and 11).
+Pavel Barta made a donation (2013/10).
+Nikolay Pertsev made a donation (2014/5).
++James B made a donation (2014/7).
++Stefano Di Biase made a donation (2014/8).
+
+Thank you very much.
+Donations are always, including future donations, very important and
@@ -629,8 +631,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+helper, instead of doing in kernel space. Actually I am still thinking
+about it. But currently I have implemented it in kernel space.
--- a/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 01:00:00.000000000 +0100
-+++ b/Documentation/filesystems/aufs/design/02struct.txt 2014-07-15 14:04:48.720871625 +0100
-@@ -0,0 +1,249 @@
++++ b/Documentation/filesystems/aufs/design/02struct.txt 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,251 @@
+
+# Copyright (C) 2005-2014 Junjiro R. Okajima
+#
@@ -872,6 +874,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+- free space on the lower branch will reduce.
+- another access to the file may happen during moving-down, including
+ UDBA.
++- the file should not be hard-linked nor pseudo-linked. they should be
++ handled by auplink utility later.
+
+Sometimes users want to move-down a file from the upper writable branch
+to the lower readonly or writable branch. For instance,
@@ -1161,6 +1165,129 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ where the source and the target exists and selects the higher
+ one. If the selected branch is readonly, then aufs follows the
+ copyup policy.
+--- a/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 01:00:00.000000000 +0100
++++ b/Documentation/filesystems/aufs/design/06fhsm.txt 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,120 @@
++
++# Copyright (C) 2011-2014 Junjiro R. Okajima
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++
++
++File-based Hierarchical Storage Management (FHSM)
++----------------------------------------------------------------------
++Hierarchical Storage Management (or HSM) is a well-known feature in the
++storage world. Aufs provides this feature as file-based with multiple
++writable branches, based upon the principle of "Colder-Lower".
++Here the word "colder" means that the less used files, and "lower" means
++that the position in the order of the stacked branches.
++These multiple writable branches are prioritized, ie. the topmost one
++should be the fastest drive and be used heavily.
++
++o Characters in aufs FHSM story
++- aufs itself and a new branch attribute.
++- a new ioctl interface to move-down and to establish a connection with
++ the daemon ("move-down" is a converse of "copy-up").
++- userspace tool and daemon.
++
++The userspace daemon establishes a connection with aufs and waits for
++the notification. The notified information is very similar to struct
++statfs containing the number of consumed blocks and inodes.
++When the consumed blocks/inodes of a branch exceeds the user-specified
++upper watermark, the daemon activates its move-down process until the
++consumed blocks/inodes reaches the user-specified lower watermark.
++
++The actual move-down is done by aufs based upon the request from
++user-space since we need to maintain the inode number and the internal
++pointer arrays in aufs.
++
++Currently aufs FHSM handles the regular files only. Additionally they
++must not be hard-linked nor pseudo-linked.
++
++
++o Cowork of aufs and the user-space daemon
++ During the userspace daemon established the connection, aufs sends a
++ small notification to it whenever aufs writes something into the
++ writable branch. But it may cost high since aufs issues statfs(2)
++ internally. So user can specify a new option to cache the
++ info. Actually the notification is controlled by these factors.
++ + the specified cache time.
++ + classified as "force" by aufs internally.
++ Until the specified time expires, aufs doesn't send the info
++ except the forced cases. When aufs decide forcing, the info is always
++ notified to userspace.
++ For example, the number of free inodes is generally large enough and
++ the shortage of it happens rarely. So aufs doesn't force the
++ notification when creating a new file, directory and others. This is
++ the typical case which aufs doesn't force.
++ When aufs writes the actual filedata and the files consumes any of new
++ blocks, the aufs forces notifying.
++
++
++o Interfaces in aufs
++- New branch attribute.
++ + fhsm
++ Specifies that the branch is managed by FHSM feature. In other word,
++ participant in the FHSM.
++ When nofhsm is set to the branch, it will not be the source/target
++ branch of the move-down operation. This attribute is set
++ independently from coo and moo attributes, and if you want full
++ FHSM, you should specify them as well.
++- New mount option.
++ + fhsm_sec
++ Specifies a second to suppress many less important info to be
++ notified.
++- New ioctl.
++ + AUFS_CTL_FHSM_FD
++ create a new file descriptor which userspace can read the notification
++ (a subset of struct statfs) from aufs.
++- Module parameter 'brs'
++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not
++ be set.
++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs
++ When there are two or more branches with fhsm attributes,
++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs
++ terminates it. As a result of remounting and branch-manipulation, the
++ number of branches with fhsm attribute can be one. In this case,
++ /sbin/mount.aufs will terminate the user-space daemon.
++
++
++Finally the operation is done as these steps in kernel-space.
++- make sure that,
++ + no one else is using the file.
++ + the file is not hard-linked.
++ + the file is not pseudo-linked.
++ + the file is a regular file.
++ + the parent dir is not opaqued.
++- find the target writable branch.
++- make sure the file is not whiteout-ed by the upper (than the target)
++ branch.
++- make the parent dir on the target branch.
++- mutex lock the inode on the branch.
++- unlink the whiteout on the target branch (if exists).
++- lookup and create the whiteout-ed temporary name on the target branch.
++- copy the file as the whiteout-ed temporary name on the target branch.
++- rename the whiteout-ed temporary name to the original name.
++- unlink the file on the source branch.
++- maintain the internal pointer array and the external inode number
++ table (XINO).
++- maintain the timestamps and other attributes of the parent dir and the
++ file.
++
++And of course, in every step, an error may happen. So the operation
++should restore the original file state after an error happens.
--- a/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 01:00:00.000000000 +0100
+++ b/Documentation/filesystems/aufs/design/06mmap.txt 2014-01-20 03:24:33.508760970 +0000
@@ -0,0 +1,46 @@
@@ -1437,8 +1564,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+/new.
+Otherwise from /new.
--- a/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/Kconfig 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,168 @@
++++ b/fs/aufs/Kconfig 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,177 @@
+config AUFS_FS
+ tristate "Aufs (Advanced multi layered unification filesystem) support"
+ help
@@ -1528,6 +1655,15 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ /* typedef unsigned long/int __kernel_ino_t */
+ /* alpha and s390x are int */
+
++config AUFS_FHSM
++ bool "File-based Hierarchical Storage Management"
++ help
++ Hierarchical Storage Management (or HSM) is a well-known feature
++ in the storage world. Aufs provides this feature as file-based.
++ with multiple branches.
++ These multiple branches are prioritized, ie. the topmost one
++ should be the fastest drive and be used heavily.
++
+config AUFS_RDU
+ bool "Readdir in userspace"
+ help
@@ -1608,8 +1744,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ When aufs supports Magic SysRq, enabled automatically.
+endif
--- a/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/Makefile 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,41 @@
++++ b/fs/aufs/Makefile 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,42 @@
+
+include ${src}/magic.mk
+ifeq (${CONFIG_AUFS_FS},m)
@@ -1646,6 +1782,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
+aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
+aufs-$(CONFIG_AUFS_EXPORT) += export.o
++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o
+aufs-$(CONFIG_AUFS_POLL) += poll.o
+aufs-$(CONFIG_AUFS_RDU) += rdu.o
+aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
@@ -1714,8 +1851,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_H__ */
--- a/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/branch.c 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,1238 @@
++++ b/fs/aufs/branch.c 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,1445 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -1794,6 +1931,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuRwDestroy(&wbr->wbr_wh_rwsem);
+ }
+
++ if (br->br_fhsm) {
++ au_br_fhsm_fin(br->br_fhsm);
++ kfree(br->br_fhsm);
++ }
++
+ key = br->br_dykey;
+ for (i = 0; i < AuBrDynOp; i++, key++)
+ if (*key)
@@ -1889,6 +2031,13 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out_hnotify;
+ }
+
++ add_branch->br_fhsm = NULL;
++ if (au_br_fhsm(perm)) {
++ err = au_fhsm_br_alloc(add_branch);
++ if (unlikely(err))
++ goto out_wbr;
++ }
++
+ err = au_sbr_realloc(au_sbi(sb), new_nbranch);
+ if (!err)
+ err = au_di_realloc(au_di(root), new_nbranch);
@@ -1897,8 +2046,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (!err)
+ return add_branch; /* success */
+
++out_wbr:
+ kfree(add_branch->br_wbr);
-+
+out_hnotify:
+ au_hnotify_fin_br(add_branch);
+out_br:
@@ -2281,6 +2430,54 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+/* ---------------------------------------------------------------------- */
+
++static unsigned long long au_farray_cb(void *a,
++ unsigned long long max __maybe_unused,
++ void *arg)
++{
++ unsigned long long n;
++ struct file **p, *f;
++ struct au_sphlhead *files;
++ struct au_finfo *finfo;
++ struct super_block *sb = arg;
++
++ n = 0;
++ p = a;
++ files = &au_sbi(sb)->si_files;
++ spin_lock(&files->spin);
++ hlist_for_each_entry(finfo, &files->head, fi_hlist) {
++ f = finfo->fi_file;
++ if (file_count(f)
++ && !special_file(file_inode(f)->i_mode)) {
++ get_file(f);
++ *p++ = f;
++ n++;
++ AuDebugOn(n > max);
++ }
++ }
++ spin_unlock(&files->spin);
++
++ return n;
++}
++
++static struct file **au_farray_alloc(struct super_block *sb,
++ unsigned long long *max)
++{
++ *max = atomic_long_read(&au_sbi(sb)->si_nfiles);
++ return au_array_alloc(max, au_farray_cb, sb);
++}
++
++static void au_farray_free(struct file **a, unsigned long long max)
++{
++ unsigned long long ull;
++
++ for (ull = 0; ull < max; ull++)
++ if (a[ull])
++ fput(a[ull]);
++ au_array_free(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
+/*
+ * delete a branch
+ */
@@ -2387,6 +2584,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuDbg("b%d\n", bindex);
+ for (ull = 0; !err && ull < max; ull++) {
+ i = array[ull];
++ if (unlikely(!i))
++ break;
+ if (i->i_ino == AUFS_ROOT_INO)
+ continue;
+
@@ -2441,6 +2640,137 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
+
++static int test_dir_busy(struct file *file, aufs_bindex_t br_id,
++ struct file **to_free, int *idx)
++{
++ int err;
++ unsigned char matched, root;
++ aufs_bindex_t bindex, bend;
++ struct au_fidir *fidir;
++ struct au_hfile *hfile;
++
++ err = 0;
++ root = IS_ROOT(file->f_dentry);
++ if (root) {
++ get_file(file);
++ to_free[*idx] = file;
++ (*idx)++;
++ goto out;
++ }
++
++ matched = 0;
++ fidir = au_fi(file)->fi_hdir;
++ AuDebugOn(!fidir);
++ bend = au_fbend_dir(file);
++ for (bindex = au_fbstart(file); bindex <= bend; bindex++) {
++ hfile = fidir->fd_hfile + bindex;
++ if (!hfile->hf_file)
++ continue;
++
++ if (hfile->hf_br->br_id == br_id) {
++ matched = 1;
++ break;
++ }
++ }
++ if (matched)
++ err = -EBUSY;
++
++out:
++ return err;
++}
++
++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id,
++ struct file **to_free, int opened)
++{
++ int err, idx;
++ unsigned long long ull, max;
++ aufs_bindex_t bstart;
++ struct file *file, **array;
++ struct inode *inode;
++ struct dentry *root;
++ struct au_hfile *hfile;
++
++ array = au_farray_alloc(sb, &max);
++ err = PTR_ERR(array);
++ if (IS_ERR(array))
++ goto out;
++
++ err = 0;
++ idx = 0;
++ root = sb->s_root;
++ di_write_unlock(root);
++ for (ull = 0; ull < max; ull++) {
++ file = array[ull];
++ if (unlikely(!file))
++ break;
++
++ /* AuDbg("%pD\n", file); */
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ inode = file_inode(file);
++ if (!S_ISDIR(inode->i_mode)) {
++ hfile = &au_fi(file)->fi_htop;
++ if (hfile->hf_br->br_id == br_id)
++ err = -EBUSY;
++ } else
++ err = test_dir_busy(file, br_id, to_free, &idx);
++ fi_read_unlock(file);
++ if (unlikely(err))
++ break;
++ }
++ di_write_lock_child(root);
++ au_farray_free(array, max);
++ AuDebugOn(idx > opened);
++
++out:
++ return err;
++}
++
++static void br_del_file(struct file **to_free, unsigned long long opened,
++ aufs_bindex_t br_id)
++{
++ unsigned long long ull;
++ aufs_bindex_t bindex, bstart, bend, bfound;
++ struct file *file;
++ struct au_fidir *fidir;
++ struct au_hfile *hfile;
++
++ for (ull = 0; ull < opened; ull++) {
++ file = to_free[ull];
++ if (unlikely(!file))
++ break;
++
++ /* AuDbg("%pD\n", file); */
++ AuDebugOn(!S_ISDIR(file_inode(file)->i_mode));
++ bfound = -1;
++ fidir = au_fi(file)->fi_hdir;
++ AuDebugOn(!fidir);
++ fi_write_lock(file);
++ bstart = au_fbstart(file);
++ bend = au_fbend_dir(file);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ hfile = fidir->fd_hfile + bindex;
++ if (!hfile->hf_file)
++ continue;
++
++ if (hfile->hf_br->br_id == br_id) {
++ bfound = bindex;
++ break;
++ }
++ }
++ AuDebugOn(bfound < 0);
++ au_set_h_fptr(file, bfound, NULL);
++ if (bfound == bstart) {
++ for (bstart++; bstart <= bend; bstart++)
++ if (au_hf_dir(file, bstart)) {
++ au_set_fbstart(file, bstart);
++ break;
++ }
++ }
++ fi_write_unlock(file);
++ }
++}
++
+static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
+ const aufs_bindex_t bindex,
+ const aufs_bindex_t bend)
@@ -2533,17 +2863,29 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_br_do_free(br);
+}
+
++static unsigned long long empty_cb(void *array, unsigned long long max,
++ void *arg)
++{
++ return max;
++}
++
+int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
+{
+ int err, rerr, i;
++ unsigned long long opened;
+ unsigned int mnt_flags;
+ aufs_bindex_t bindex, bend, br_id;
+ unsigned char do_wh, verbose;
+ struct au_branch *br;
+ struct au_wbr *wbr;
++ struct dentry *root;
++ struct file **to_free;
+
+ err = 0;
-+ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry);
++ opened = 0;
++ to_free = NULL;
++ root = sb->s_root;
++ bindex = au_find_dbindex(root, del->h_path.dentry);
+ if (bindex < 0) {
+ if (remount)
+ goto out; /* success */
@@ -2563,10 +2905,20 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+ br = au_sbr(sb, bindex);
+ AuDebugOn(!path_equal(&br->br_path, &del->h_path));
-+ i = atomic_read(&br->br_count);
-+ if (unlikely(i)) {
-+ AuVerbose(verbose, "%d file(s) opened\n", i);
-+ goto out;
++
++ br_id = br->br_id;
++ opened = atomic_read(&br->br_count);
++ if (unlikely(opened)) {
++ to_free = au_array_alloc(&opened, empty_cb, NULL);
++ err = PTR_ERR(to_free);
++ if (IS_ERR(to_free))
++ goto out;
++
++ err = test_file_busy(sb, br_id, to_free, opened);
++ if (unlikely(err)) {
++ AuVerbose(verbose, "%llu file(s) opened\n", opened);
++ goto out;
++ }
+ }
+
+ wbr = br->br_wbr;
@@ -2580,7 +2932,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+ }
+
-+ err = test_children_busy(sb->s_root, bindex, verbose);
++ err = test_children_busy(root, bindex, verbose);
+ if (unlikely(err)) {
+ if (do_wh)
+ goto out_wh;
@@ -2588,7 +2940,16 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+
+ err = 0;
-+ br_id = br->br_id;
++ if (to_free) {
++ /*
++ * now we confirmed the branch is deletable.
++ * let's free the remaining opened dirs on the branch.
++ */
++ di_write_unlock(root);
++ br_del_file(to_free, opened, br_id);
++ di_write_lock_child(root);
++ }
++
+ if (!remount)
+ au_br_do_del(sb, bindex, br);
+ else {
@@ -2598,10 +2959,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+
+ if (!bindex) {
-+ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1);
++ au_cpup_attr_all(root->d_inode, /*force*/1);
+ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes;
+ } else
-+ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode);
++ au_sub_nlink(root->d_inode, del->h_path.dentry->d_inode);
+ if (au_opt_test(mnt_flags, PLINK))
+ au_plink_half_refresh(sb, br_id);
+
@@ -2616,6 +2977,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ pr_warn("failed re-creating base whiteout, %s. (%d)\n",
+ del->pathname, rerr);
+out:
++ if (to_free)
++ au_farray_free(to_free, opened);
+ return err;
+}
+
@@ -2715,52 +3078,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ || do_need_sigen_inc(new, old);
+}
+
-+static unsigned long long au_farray_cb(void *a,
-+ unsigned long long max __maybe_unused,
-+ void *arg)
-+{
-+ unsigned long long n;
-+ struct file **p, *f;
-+ struct au_sphlhead *files;
-+ struct au_finfo *finfo;
-+ struct super_block *sb = arg;
-+
-+ n = 0;
-+ p = a;
-+ files = &au_sbi(sb)->si_files;
-+ spin_lock(&files->spin);
-+ hlist_for_each_entry(finfo, &files->head, fi_hlist) {
-+ f = finfo->fi_file;
-+ if (file_count(f)
-+ && !special_file(file_inode(f)->i_mode)) {
-+ get_file(f);
-+ *p++ = f;
-+ n++;
-+ AuDebugOn(n > max);
-+ }
-+ }
-+ spin_unlock(&files->spin);
-+
-+ return n;
-+}
-+
-+static struct file **au_farray_alloc(struct super_block *sb,
-+ unsigned long long *max)
-+{
-+ *max = atomic_long_read(&au_sbi(sb)->si_nfiles);
-+ return au_array_alloc(max, au_farray_cb, sb);
-+}
-+
-+static void au_farray_free(struct file **a, unsigned long long max)
-+{
-+ unsigned long long ull;
-+
-+ for (ull = 0; ull < max; ull++)
-+ if (a[ull])
-+ fput(a[ull]);
-+ au_array_free(a);
-+}
-+
+static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
+{
+ int err, do_warn;
@@ -2784,6 +3101,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ br_id = au_sbr_id(sb, bindex);
+ for (ull = 0; ull < max; ull++) {
+ file = array[ull];
++ if (unlikely(!file))
++ break;
+
+ /* AuDbg("%pD\n", file); */
+ fi_read_lock(file);
@@ -2859,6 +3178,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ aufs_bindex_t bindex;
+ struct dentry *root;
+ struct au_branch *br;
++ struct au_br_fhsm *bf;
+
+ root = sb->s_root;
+ bindex = au_find_dbindex(root, mod->h_root);
@@ -2880,11 +3200,21 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (br->br_perm == mod->perm)
+ return 0; /* success */
+
++ /* pre-allocate for non-fhsm --> fhsm */
++ bf = NULL;
++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) {
++ err = au_fhsm_br_alloc(br);
++ if (unlikely(err))
++ goto out;
++ bf = br->br_fhsm;
++ br->br_fhsm = NULL;
++ }
++
+ if (au_br_writable(br->br_perm)) {
+ /* remove whiteout base */
+ err = au_br_init_wh(sb, br, mod->perm);
+ if (unlikely(err))
-+ goto out;
++ goto out_bf;
+
+ if (!au_br_writable(mod->perm)) {
+ /* rw --> ro, file might be mmapped */
@@ -2920,18 +3250,32 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+ }
+ }
++ if (unlikely(err))
++ goto out_bf;
++
++ if (au_br_fhsm(br->br_perm)) {
++ if (!au_br_fhsm(mod->perm)) {
++ /* fhsm --> non-fhsm */
++ au_br_fhsm_fin(br->br_fhsm);
++ kfree(br->br_fhsm);
++ br->br_fhsm = NULL;
++ }
++ } else if (au_br_fhsm(mod->perm))
++ /* non-fhsm --> fhsm */
++ br->br_fhsm = bf;
++
++ if ((br->br_perm & AuBrAttr_UNPIN)
++ && !(mod->perm & AuBrAttr_UNPIN))
++ au_br_dflags_force(br);
++ else if (!(br->br_perm & AuBrAttr_UNPIN)
++ && (mod->perm & AuBrAttr_UNPIN))
++ au_br_dflags_restore(br);
++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
++ br->br_perm = mod->perm;
++ goto out; /* success */
+
-+ if (!err) {
-+ if ((br->br_perm & AuBrAttr_UNPIN)
-+ && !(mod->perm & AuBrAttr_UNPIN))
-+ au_br_dflags_force(br);
-+ else if (!(br->br_perm & AuBrAttr_UNPIN)
-+ && (mod->perm & AuBrAttr_UNPIN))
-+ au_br_dflags_restore(br);
-+ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm);
-+ br->br_perm = mod->perm;
-+ }
-+
++out_bf:
++ kfree(bf);
+out:
+ AuTraceErr(err);
+ return err;
@@ -2955,8 +3299,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
--- a/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/branch.h 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,290 @@
++++ b/fs/aufs/branch.h 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -3002,6 +3346,16 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif
+};
+
++/* File-based Hierarchical Storage Management */
++struct au_br_fhsm {
++#ifdef CONFIG_AUFS_FHSM
++ struct mutex bf_lock;
++ unsigned long bf_jiffy;
++ struct aufs_stfs bf_stfs;
++ int bf_readable;
++#endif
++};
++
+/* members for writable branch only */
+enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last};
+struct au_wbr {
@@ -3052,6 +3406,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ atomic_t br_count;
+
+ struct au_wbr *br_wbr;
++ struct au_br_fhsm *br_fhsm;
+
+ /* xino truncation */
+ atomic_t br_xino_running;
@@ -3083,53 +3438,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return au_br_mnt(br)->mnt_sb;
+}
+
-+/* branch permissions and attributes */
-+#define AuBrPerm_RW 1 /* writable, hardlinkable wh */
-+#define AuBrPerm_RO (1 << 1) /* readonly */
-+#define AuBrPerm_RR (1 << 2) /* natively readonly */
-+#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR)
-+
-+#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */
-+#define AuBrAttr_COO_ALL (1 << 4)
-+#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL)
-+
-+#define AuBrAttr_UNPIN (1 << 5) /* rename-able top dir of
-+ branch */
-+
-+#define AuBrRAttr_WH (1 << 6) /* whiteout-able */
-+#define AuBrRAttr_Mask AuBrRAttr_WH
-+
-+#define AuBrWAttr_NoLinkWH (1 << 7) /* un-hardlinkable whiteouts */
-+#define AuBrWAttr_MOO (1 << 8) /* move-up on open */
-+#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO)
-+
-+#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO)
-+
-+/* the longest combination */
-+#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \
-+ "+" AUFS_BRATTR_COO_REG \
-+ "+" AUFS_BRATTR_UNPIN \
-+ "+" AUFS_BRWATTR_NLWH)
-+
-+typedef struct {
-+ char a[AuBrPermStrSz];
-+} au_br_perm_str_t;
-+
-+static inline int au_br_writable(int brperm)
-+{
-+ return brperm & AuBrPerm_RW;
-+}
-+
-+static inline int au_br_whable(int brperm)
-+{
-+ return brperm & (AuBrPerm_RW | AuBrRAttr_WH);
-+}
-+
-+static inline int au_br_wh_linkable(int brperm)
-+{
-+ return !(brperm & AuBrWAttr_NoLinkWH);
-+}
-+
+static inline int au_br_rdonly(struct au_branch *br)
+{
+ return ((au_br_sb(br)->s_flags & MS_RDONLY)
@@ -3137,11 +3445,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ? -EROFS : 0;
+}
+
-+static inline int au_br_cmoo(int brperm)
-+{
-+ return brperm & AuBrAttr_CMOO_Mask;
-+}
-+
+static inline int au_br_hnotifyable(int brperm __maybe_unused)
+{
+#ifdef CONFIG_AUFS_HNOTIFY
@@ -3245,11 +3548,30 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem)
+#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem)
+
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_FHSM
++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm)
++{
++ mutex_init(&brfhsm->bf_lock);
++ brfhsm->bf_jiffy = 0;
++ brfhsm->bf_readable = 0;
++}
++
++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm)
++{
++ mutex_destroy(&brfhsm->bf_lock);
++}
++#else
++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm)
++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm)
++#endif
++
+#endif /* __KERNEL__ */
+#endif /* __AUFS_BRANCH_H__ */
--- a/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/conf.mk 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,36 @@
++++ b/fs/aufs/conf.mk 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,37 @@
+
+AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
+
@@ -3263,6 +3585,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ SBILIST \
+ HNOTIFY HFSNOTIFY \
+ EXPORT INO_T_64 \
++ FHSM \
+ RDU \
+ SHWH \
+ BR_RAMFS \
@@ -3287,8 +3610,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+-include ${srctree}/${src}/conf_priv.mk
--- a/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/cpup.c 2014-07-15 14:04:48.724871625 +0100
-@@ -0,0 +1,1289 @@
++++ b/fs/aufs/cpup.c 2014-09-08 00:38:33.510569903 +0100
+@@ -0,0 +1,1301 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -3788,7 +4111,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ int err;
+ umode_t mode;
+ unsigned int mnt_flags;
-+ unsigned char isdir;
++ unsigned char isdir, isreg, force;
+ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME);
+ struct au_dtime dt;
+ struct path h_path;
@@ -3819,10 +4142,12 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+ h_path.dentry = h_dst;
+
++ isreg = 0;
+ isdir = 0;
+ mode = h_inode->i_mode;
+ switch (mode & S_IFMT) {
+ case S_IFREG:
++ isreg = 1;
+ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR,
+ /*want_excl*/true);
+ if (!err)
@@ -3871,6 +4196,16 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0);
+ /* ignore this error */
+
++ if (!err) {
++ force = 0;
++ if (isreg) {
++ force = !!cpg->len;
++ if (cpg->len == -1)
++ force = !!i_size_read(h_inode);
++ }
++ au_fhsm_wrote(sb, cpg->bdst, force);
++ }
++
+ if (do_dt)
+ au_dtime_revert(&dt);
+ return err;
@@ -5531,8 +5866,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DCSUB_H__ */
--- a/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/debug.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,519 @@
++++ b/fs/aufs/debug.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -5591,6 +5926,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+MODULE_PARM_DESC(debug, "debug print");
+module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP);
+
++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */
+char *au_plevel = KERN_DEBUG;
+#define dpri(fmt, ...) do { \
+ if ((au_plevel \
@@ -6053,8 +6389,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return 0;
+}
--- a/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/debug.h 2014-01-20 03:24:33.508760970 +0000
-@@ -0,0 +1,247 @@
++++ b/fs/aufs/debug.h 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -6167,6 +6503,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+struct au_finfo;
+struct dentry;
+#ifdef CONFIG_AUFS_DEBUG
++extern struct mutex au_dbg_mtx;
+extern char *au_plevel;
+struct au_nhash;
+void au_dpri_whlist(struct au_nhash *whlist);
@@ -6195,38 +6532,52 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+int __init au_debug_init(void);
+void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
+#define AuDbgWhlist(w) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#w "\n"); \
+ au_dpri_whlist(w); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgVdir(v) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#v "\n"); \
+ au_dpri_vdir(v); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgInode(i) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#i "\n"); \
+ au_dpri_inode(i); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgDAlias(i) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#i "\n"); \
+ au_dpri_dalias(i); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgDentry(d) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#d "\n"); \
+ au_dpri_dentry(d); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgFile(f) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#f "\n"); \
+ au_dpri_file(f); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgSb(sb) do { \
++ mutex_lock(&au_dbg_mtx); \
+ AuDbg(#sb "\n"); \
+ au_dpri_sb(sb); \
++ mutex_unlock(&au_dbg_mtx); \
+} while (0)
+
+#define AuDbgSleep(sec) do { \
@@ -6303,8 +6654,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DEBUG_H__ */
--- a/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/dentry.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,1094 @@
++++ b/fs/aufs/dentry.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,1096 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -7311,10 +7662,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(!au_di(dentry)))
+ goto out;
+
-+ inode = dentry->d_inode;
-+ if (inode && is_bad_inode(inode))
-+ goto out;
-+
+ valid = 1;
+ sb = dentry->d_sb;
+ /*
@@ -7328,6 +7675,12 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuTraceErr(err);
+ goto out;
+ }
++ inode = dentry->d_inode;
++ if (unlikely(inode && is_bad_inode(inode))) {
++ err = -EINVAL;
++ AuTraceErr(err);
++ goto out_dgrade;
++ }
+ if (unlikely(au_dbrange_test(dentry))) {
+ err = -EINVAL;
+ AuTraceErr(err);
@@ -8183,8 +8536,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return -1;
+}
--- a/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/dir.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,643 @@
++++ b/fs/aufs/dir.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -8404,6 +8757,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ finfo = au_fi(file);
+ fidir = finfo->fi_hdir;
+ if (fidir) {
++ au_sphl_del(&finfo->fi_hlist,
++ &au_sbi(file->f_dentry->d_sb)->si_files);
+ vdir_cache = fidir->fd_vdir_cache; /* lock-free */
+ if (vdir_cache)
+ au_vdir_free(vdir_cache);
@@ -9428,7 +9783,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DYNOP_H__ */
--- a/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/export.c 2014-01-20 03:24:33.512760970 +0000
++++ b/fs/aufs/export.c 2014-09-08 00:38:33.514569904 +0100
@@ -0,0 +1,831 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -10146,7 +10501,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ii_read_lock_child(inode);
+ bindex = au_ibstart(inode);
+ if (!dir) {
-+ dentry = d_find_alias(inode);
++ dentry = d_find_any_alias(inode);
+ if (unlikely(!dentry))
+ goto out_unlock;
+ AuDebugOn(au_test_anon(dentry));
@@ -10162,7 +10517,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ii_read_unlock(dir);
+ if (unlikely(!h_dir))
+ goto out_parent;
-+ h_parent = d_find_alias(h_dir);
++ h_parent = d_find_any_alias(h_dir);
+ if (unlikely(!h_parent))
+ goto out_hparent;
+
@@ -10262,8 +10617,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ atomic_set(&sbinfo->si_xigen_next, u);
+}
--- a/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/f_op.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,791 @@
++++ b/fs/aufs/f_op.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -10322,8 +10677,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_set_fbstart(file, bindex);
+ au_set_h_fptr(file, bindex, h_file);
+ au_update_figen(file);
-+ finfo->fi_file = file;
-+ au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files);
+ /* todo: necessary? */
+ /* file->f_ra = h_file->f_ra; */
+ }
@@ -10449,10 +10802,12 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ size_t count, loff_t *ppos)
+{
+ ssize_t err;
++ blkcnt_t blks;
++ aufs_bindex_t bstart;
+ struct au_pin pin;
+ struct dentry *dentry;
++ struct inode *inode, *h_inode;
+ struct super_block *sb;
-+ struct inode *inode;
+ struct file *h_file;
+ char __user *buf = (char __user *)ubuf;
+
@@ -10473,8 +10828,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out;
+ }
+
++ bstart = au_fbstart(file);
+ h_file = au_hf_top(file);
+ get_file(h_file);
++ h_inode = h_file->f_dentry->d_inode;
++ blks = h_inode->i_blocks;
+ au_unpin(&pin);
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
@@ -10483,6 +10841,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ii_write_lock_child(inode);
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = file_inode(h_file)->i_mode;
++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks);
++ if (err > 0)
++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks);
+ ii_write_unlock(inode);
+ fput(h_file);
+
@@ -10570,9 +10931,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter)
+{
+ ssize_t err;
++ blkcnt_t blks;
++ aufs_bindex_t bstart;
+ struct au_pin pin;
+ struct dentry *dentry;
-+ struct inode *inode;
++ struct inode *inode, *h_inode;
+ struct file *file, *h_file;
+ struct super_block *sb;
+
@@ -10594,8 +10957,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out;
+ }
+
++ bstart = au_fbstart(file);
+ h_file = au_hf_top(file);
+ get_file(h_file);
++ h_inode = h_file->f_dentry->d_inode;
++ blks = h_inode->i_blocks;
+ au_unpin(&pin);
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
@@ -10604,6 +10970,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ii_write_lock_child(inode);
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = file_inode(h_file)->i_mode;
++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks);
++ if (err > 0)
++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks);
+ ii_write_unlock(inode);
+ fput(h_file);
+
@@ -10659,11 +11028,13 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ size_t len, unsigned int flags)
+{
+ ssize_t err;
++ blkcnt_t blks;
++ aufs_bindex_t bstart;
+ struct au_pin pin;
+ struct dentry *dentry;
-+ struct inode *inode;
-+ struct file *h_file;
++ struct inode *inode, *h_inode;
+ struct super_block *sb;
++ struct file *h_file;
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
@@ -10682,8 +11053,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out;
+ }
+
++ bstart = au_fbstart(file);
+ h_file = au_hf_top(file);
+ get_file(h_file);
++ h_inode = h_file->f_dentry->d_inode;
++ blks = h_inode->i_blocks;
+ au_unpin(&pin);
+ di_read_unlock(dentry, AuLock_IR);
+ fi_write_unlock(file);
@@ -10692,6 +11066,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ ii_write_lock_child(inode);
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = file_inode(h_file)->i_mode;
++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks);
++ if (err > 0)
++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks);
+ ii_write_unlock(inode);
+ fput(h_file);
+
@@ -11055,9 +11432,438 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif
+ .fallocate = aufs_fallocate
+};
+--- a/fs/aufs/fhsm.c 1970-01-01 01:00:00.000000000 +0100
++++ b/fs/aufs/fhsm.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,426 @@
++/*
++ * Copyright (C) 2011-2014 Junjiro R. Okajima
++ *
++ * This program, aufs is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * File-based Hierarchy Storage Management
++ */
++
++#include <linux/anon_inodes.h>
++#include <linux/poll.h>
++#include <linux/seq_file.h>
++#include <linux/statfs.h>
++#include "aufs.h"
++
++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ AuDebugOn(!fhsm);
++ return fhsm->fhsm_bottom;
++}
++
++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ AuDebugOn(!fhsm);
++ fhsm->fhsm_bottom = bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br)
++{
++ struct au_br_fhsm *bf;
++
++ bf = br->br_fhsm;
++ MtxMustLock(&bf->bf_lock);
++
++ return !bf->bf_readable
++ || time_after(jiffies,
++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_fhsm_notify(struct super_block *sb, int val)
++{
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ if (au_fhsm_pid(fhsm)
++ && atomic_read(&fhsm->fhsm_readable) != -1) {
++ atomic_set(&fhsm->fhsm_readable, val);
++ if (val)
++ wake_up(&fhsm->fhsm_wqh);
++ }
++}
++
++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex,
++ struct aufs_stfs *rstfs, int do_lock, int do_notify)
++{
++ int err;
++ struct au_branch *br;
++ struct au_br_fhsm *bf;
++
++ br = au_sbr(sb, bindex);
++ AuDebugOn(au_br_rdonly(br));
++ bf = br->br_fhsm;
++ AuDebugOn(!bf);
++
++ if (do_lock)
++ mutex_lock(&bf->bf_lock);
++ else
++ MtxMustLock(&bf->bf_lock);
++
++ /* sb->s_root for NFS is unreliable */
++ err = au_br_stfs(br, &bf->bf_stfs);
++ if (unlikely(err)) {
++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err);
++ goto out;
++ }
++
++ bf->bf_jiffy = jiffies;
++ bf->bf_readable = 1;
++ if (do_notify)
++ au_fhsm_notify(sb, /*val*/1);
++ if (rstfs)
++ *rstfs = bf->bf_stfs;
++
++out:
++ if (do_lock)
++ mutex_unlock(&bf->bf_lock);
++ au_fhsm_notify(sb, /*val*/1);
++
++ return err;
++}
++
++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++ struct au_branch *br;
++ struct au_br_fhsm *bf;
++
++ AuDbg("b%d, force %d\n", bindex, force);
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ if (!au_ftest_si(sbinfo, FHSM)
++ || fhsm->fhsm_bottom == bindex)
++ return;
++
++ br = au_sbr(sb, bindex);
++ bf = br->br_fhsm;
++ AuDebugOn(!bf);
++ mutex_lock(&bf->bf_lock);
++ if (force
++ || au_fhsm_pid(fhsm)
++ || au_fhsm_test_jiffy(sbinfo, br))
++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0,
++ /*do_notify*/1);
++ mutex_unlock(&bf->bf_lock);
++}
++
++void au_fhsm_wrote_all(struct super_block *sb, int force)
++{
++ aufs_bindex_t bindex, bend;
++ struct au_branch *br;
++
++ /* exclude the bottom */
++ bend = au_fhsm_bottom(sb);
++ for (bindex = 0; bindex < bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_fhsm(br->br_perm))
++ au_fhsm_wrote(sb, bindex, force);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static unsigned int au_fhsm_poll(struct file *file,
++ struct poll_table_struct *wait)
++{
++ unsigned int mask;
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ mask = 0;
++ sbinfo = file->private_data;
++ fhsm = &sbinfo->si_fhsm;
++ poll_wait(file, &fhsm->fhsm_wqh, wait);
++ if (atomic_read(&fhsm->fhsm_readable))
++ mask = POLLIN /* | POLLRDNORM */;
++
++ AuTraceErr((int)mask);
++ return mask;
++}
++
++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr,
++ struct aufs_stfs *stfs, __s16 brid)
++{
++ int err;
++
++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs));
++ if (!err)
++ err = __put_user(brid, &stbr->brid);
++ if (unlikely(err))
++ err = -EFAULT;
++
++ return err;
++}
++
++static ssize_t au_fhsm_do_read(struct super_block *sb,
++ struct aufs_stbr __user *stbr, size_t count)
++{
++ ssize_t err;
++ int nstbr;
++ aufs_bindex_t bindex, bend;
++ struct au_branch *br;
++ struct au_br_fhsm *bf;
++
++ /* except the bottom branch */
++ err = 0;
++ nstbr = 0;
++ bend = au_fhsm_bottom(sb);
++ for (bindex = 0; !err && bindex < bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (!au_br_fhsm(br->br_perm))
++ continue;
++
++ bf = br->br_fhsm;
++ mutex_lock(&bf->bf_lock);
++ if (bf->bf_readable) {
++ err = -EFAULT;
++ if (count >= sizeof(*stbr))
++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs,
++ br->br_id);
++ if (!err) {
++ bf->bf_readable = 0;
++ count -= sizeof(*stbr);
++ nstbr++;
++ }
++ }
++ mutex_unlock(&bf->bf_lock);
++ }
++ if (!err)
++ err = sizeof(*stbr) * nstbr;
++
++ return err;
++}
++
++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count,
++ loff_t *pos)
++{
++ ssize_t err;
++ int readable;
++ aufs_bindex_t nfhsm, bindex, bend;
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++ struct au_branch *br;
++ struct super_block *sb;
++
++ err = 0;
++ sbinfo = file->private_data;
++ fhsm = &sbinfo->si_fhsm;
++need_data:
++ spin_lock_irq(&fhsm->fhsm_wqh.lock);
++ if (!atomic_read(&fhsm->fhsm_readable)) {
++ if (vfsub_file_flags(file) & O_NONBLOCK)
++ err = -EAGAIN;
++ else
++ err = wait_event_interruptible_locked_irq
++ (fhsm->fhsm_wqh,
++ atomic_read(&fhsm->fhsm_readable));
++ }
++ spin_unlock_irq(&fhsm->fhsm_wqh.lock);
++ if (unlikely(err))
++ goto out;
++
++ /* sb may already be dead */
++ au_rw_read_lock(&sbinfo->si_rwsem);
++ readable = atomic_read(&fhsm->fhsm_readable);
++ if (readable > 0) {
++ sb = sbinfo->si_sb;
++ AuDebugOn(!sb);
++ /* exclude the bottom branch */
++ nfhsm = 0;
++ bend = au_fhsm_bottom(sb);
++ for (bindex = 0; bindex < bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_fhsm(br->br_perm))
++ nfhsm++;
++ }
++ err = -EMSGSIZE;
++ if (nfhsm * sizeof(struct aufs_stbr) <= count) {
++ atomic_set(&fhsm->fhsm_readable, 0);
++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf,
++ count);
++ }
++ }
++ au_rw_read_unlock(&sbinfo->si_rwsem);
++ if (!readable)
++ goto need_data;
++
++out:
++ return err;
++}
++
++static int au_fhsm_release(struct inode *inode, struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ /* sb may already be dead */
++ sbinfo = file->private_data;
++ fhsm = &sbinfo->si_fhsm;
++ spin_lock(&fhsm->fhsm_spin);
++ fhsm->fhsm_pid = 0;
++ spin_unlock(&fhsm->fhsm_spin);
++ kobject_put(&sbinfo->si_kobj);
++
++ return 0;
++}
++
++static const struct file_operations au_fhsm_fops = {
++ .owner = THIS_MODULE,
++ .llseek = noop_llseek,
++ .read = au_fhsm_read,
++ .poll = au_fhsm_poll,
++ .release = au_fhsm_release
++};
++
++int au_fhsm_fd(struct super_block *sb, int oflags)
++{
++ int err, fd;
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++
++ err = -EPERM;
++ if (unlikely(!capable(CAP_SYS_ADMIN)))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK)))
++ goto out;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ spin_lock(&fhsm->fhsm_spin);
++ if (!fhsm->fhsm_pid)
++ fhsm->fhsm_pid = current->pid;
++ else
++ err = -EBUSY;
++ spin_unlock(&fhsm->fhsm_spin);
++ if (unlikely(err))
++ goto out;
++
++ oflags |= O_RDONLY;
++ /* oflags |= FMODE_NONOTIFY; */
++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags);
++ err = fd;
++ if (unlikely(fd < 0))
++ goto out_pid;
++
++ /* succeed reglardless 'fhsm' status */
++ kobject_get(&sbinfo->si_kobj);
++ si_noflush_read_lock(sb);
++ if (au_ftest_si(sbinfo, FHSM))
++ au_fhsm_wrote_all(sb, /*force*/0);
++ si_read_unlock(sb);
++ goto out; /* success */
++
++out_pid:
++ spin_lock(&fhsm->fhsm_spin);
++ fhsm->fhsm_pid = 0;
++ spin_unlock(&fhsm->fhsm_spin);
++out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_fhsm_br_alloc(struct au_branch *br)
++{
++ int err;
++
++ err = 0;
++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS);
++ if (br->br_fhsm)
++ au_br_fhsm_init(br->br_fhsm);
++ else
++ err = -ENOMEM;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_fhsm_fin(struct super_block *sb)
++{
++ au_fhsm_notify(sb, /*val*/-1);
++}
++
++void au_fhsm_init(struct au_sbinfo *sbinfo)
++{
++ struct au_fhsm *fhsm;
++
++ fhsm = &sbinfo->si_fhsm;
++ spin_lock_init(&fhsm->fhsm_spin);
++ init_waitqueue_head(&fhsm->fhsm_wqh);
++ atomic_set(&fhsm->fhsm_readable, 0);
++ fhsm->fhsm_expire
++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC);
++ fhsm->fhsm_bottom = -1;
++}
++
++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec)
++{
++ sbinfo->si_fhsm.fhsm_expire
++ = msecs_to_jiffies(sec * MSEC_PER_SEC);
++}
++
++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo)
++{
++ unsigned int u;
++
++ if (!au_ftest_si(sbinfo, FHSM))
++ return;
++
++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC;
++ if (u != AUFS_FHSM_CACHE_DEF_SEC)
++ seq_printf(seq, ",fhsm_sec=%u", u);
++}
--- a/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/file.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,808 @@
++++ b/fs/aufs/file.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -11172,6 +11978,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+static int au_cmoo(struct dentry *dentry)
+{
+ int err, cmoo;
++ unsigned int udba;
+ struct path h_path;
+ struct au_pin pin;
+ struct au_cp_generic cpg = {
@@ -11184,6 +11991,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ };
+ struct inode *inode, *delegated;
+ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct au_fhsm *fhsm;
++ pid_t pid;
+ struct au_branch *br;
+ struct dentry *parent;
+ struct au_hinode *hdir;
@@ -11200,6 +12010,14 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out;
+
+ sb = dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ fhsm = &sbinfo->si_fhsm;
++ pid = au_fhsm_pid(fhsm);
++ if (pid
++ && (current->pid == pid
++ || current->real_parent->pid == pid))
++ goto out;
++
+ br = au_sbr(sb, cpg.bsrc);
+ cmoo = au_br_cmoo(br->br_perm);
+ if (!cmoo)
@@ -11225,34 +12043,42 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ goto out_dgrade;
+
+ di_downgrade_lock(parent, AuLock_IR);
-+ err = au_pin(&pin, dentry, cpg.bdst, au_opt_udba(sb),
++ udba = au_opt_udba(sb);
++ err = au_pin(&pin, dentry, cpg.bdst, udba,
+ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
-+ if (!err) {
-+ err = au_sio_cpup_simple(&cpg);
-+ au_unpin(&pin);
++ if (unlikely(err))
++ goto out_parent;
++
++ err = au_sio_cpup_simple(&cpg);
++ au_unpin(&pin);
++ if (unlikely(err))
++ goto out_parent;
++ if (!(cmoo & AuBrWAttr_MOO))
++ goto out_parent; /* success */
++
++ err = au_pin(&pin, dentry, cpg.bsrc, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_parent;
++
++ h_path.mnt = au_br_mnt(br);
++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
++ hdir = au_hi(parent->d_inode, cpg.bsrc);
++ delegated = NULL;
++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
++ au_unpin(&pin);
++ /* todo: keep h_dentry or not? */
++ if (unlikely(err == -EWOULDBLOCK)) {
++ pr_warn("cannot retry for NFSv4 delegation"
++ " for an internal unlink\n");
++ iput(delegated);
+ }
-+ if (!err && (cmoo & AuBrWAttr_MOO)) {
-+ /* todo: keep h_dentry? */
-+ h_path.mnt = au_br_mnt(br);
-+ h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
-+ hdir = au_hi(parent->d_inode, cpg.bsrc);
-+ delegated = NULL;
-+ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT2);
-+ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated,
-+ /*force*/1);
-+ au_hn_imtx_unlock(hdir);
-+ if (unlikely(err == -EWOULDBLOCK)) {
-+ pr_warn("cannot retry for NFSv4 delegation"
-+ " for an internal unlink\n");
-+ iput(delegated);
-+ }
-+ if (unlikely(err)) {
-+ pr_err("unlink %pd after coo failed (%d), ignored\n",
-+ dentry, err);
-+ err = 0;
-+ }
++ if (unlikely(err)) {
++ pr_err("unlink %pd after coo failed (%d), ignored\n",
++ dentry, err);
++ err = 0;
+ }
-+ goto out_parent;
++ goto out_parent; /* success */
+
+out_dgrade:
+ di_downgrade_lock(parent, AuLock_IR);
@@ -11269,6 +12095,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+{
+ int err;
+ struct dentry *dentry;
++ struct au_finfo *finfo;
+
+ err = au_finfo_init(file, fidir);
+ if (unlikely(err))
@@ -11282,9 +12109,15 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ err = open(file, vfsub_file_flags(file));
+ di_read_unlock(dentry, AuLock_IR);
+
++ finfo = au_fi(file);
++ if (!err) {
++ finfo->fi_file = file;
++ au_sphl_add(&finfo->fi_hlist,
++ &au_sbi(file->f_dentry->d_sb)->si_files);
++ }
+ fi_write_unlock(file);
+ if (unlikely(err)) {
-+ au_fi(file)->fi_hdir = NULL;
++ finfo->fi_hdir = NULL;
+ au_finfo_fin(file);
+ }
+
@@ -11655,8 +12488,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (p->hf_file) {
+ if (file_inode(p->hf_file))
+ break;
-+ else
-+ au_hfput(p, file);
++ au_hfput(p, file);
+ }
+ } else {
+ bend = au_br_index(sb, brid);
@@ -11673,8 +12505,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (p->hf_file) {
+ if (file_inode(p->hf_file))
+ break;
-+ else
-+ au_hfput(p, file);
++ au_hfput(p, file);
+ }
+ AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
+}
@@ -12790,8 +13621,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FSTYPE_H__ */
--- a/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/hfsnotify.c 2014-07-15 14:04:48.728871625 +0100
-@@ -0,0 +1,281 @@
++++ b/fs/aufs/hfsnotify.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -12854,10 +13685,12 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ * by udba rename or rmdir, aufs assign a new inode to the known
+ * h_inode, so specify 1 to allow dups.
+ */
++ lockdep_off();
+ err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode,
+ /*mnt*/NULL, /*allow_dups*/1);
+ /* even if err */
+ fsnotify_put_mark(mark);
++ lockdep_on();
+
+ return err;
+}
@@ -12876,8 +13709,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ group = mark->group;
+ fsnotify_get_group(group);
+ spin_unlock(&mark->lock);
++ lockdep_off();
+ fsnotify_destroy_mark(mark, group);
+ fsnotify_put_group(group);
++ lockdep_on();
+
+ /* free hn by myself */
+ return 0;
@@ -13004,8 +13839,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ struct au_br_hfsnotify *hfsn;
+
+ hfsn = br->br_hfsn;
-+ if (hfsn)
++ if (hfsn) {
++ lockdep_off();
+ fsnotify_put_group(hfsn->hfsn_group);
++ lockdep_on();
++ }
+}
+
+static int au_hfsn_init_br(struct au_branch *br, int perm)
@@ -13133,7 +13971,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+}
--- a/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/hnotify.c 2014-07-15 14:04:48.732871625 +0100
++++ b/fs/aufs/hnotify.c 2014-09-08 00:38:33.514569904 +0100
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
@@ -13364,7 +14202,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ spin_unlock(&inode->i_lock);
+ } else {
+ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
-+ d = d_find_alias(inode);
++ d = d_find_any_alias(inode);
+ if (!d) {
+ au_iigen_dec(inode);
+ goto out;
@@ -13509,7 +14347,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ struct dentry *dentry, *d, *parent;
+ struct qstr *dname;
+
-+ parent = d_find_alias(dir);
++ parent = d_find_any_alias(dir);
+ if (!parent)
+ return NULL;
+
@@ -13850,8 +14688,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_hn_destroy_cache();
+}
--- a/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/i_op.c 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,1140 @@
++++ b/fs/aufs/i_op.c 2014-09-08 00:39:05.266571221 +0100
+@@ -0,0 +1,1142 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -14057,11 +14895,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+ if (npositive) {
+ inode = au_new_inode(dentry, /*must_new*/0);
-+ ret = (void *)inode;
-+ }
-+ if (IS_ERR(inode)) {
-+ inode = NULL;
-+ goto out_unlock;
++ if (IS_ERR(inode)) {
++ ret = (void *)inode;
++ inode = NULL;
++ goto out_unlock;
++ }
+ }
+
+ ret = d_splice_alias(inode, dentry);
@@ -14236,7 +15074,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_hn_imtx_unlock(p->hdir);
+}
+
-+static int au_pin_hdir_lock(struct au_pin *p)
++int au_pin_hdir_lock(struct au_pin *p)
+{
+ int err;
+
@@ -14402,6 +15240,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (!err)
+ goto out; /* success */
+
++ au_unpin(p);
++
+out_err:
+ pr_err("err %d\n", err);
+ err = au_busy_or_stale();
@@ -14993,8 +15833,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ .update_time = aufs_update_time
+};
--- a/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/i_op_add.c 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,880 @@
++++ b/fs/aufs/i_op_add.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,891 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -15030,17 +15870,19 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ int err, rerr;
+ aufs_bindex_t bwh;
+ struct path h_path;
++ struct super_block *sb;
+ struct inode *inode, *h_dir;
+ struct dentry *wh;
+
+ bwh = -1;
++ sb = dir->i_sb;
+ if (wh_dentry) {
+ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
+ IMustLock(h_dir);
+ AuDebugOn(au_h_iptr(dir, bindex) != h_dir);
+ bwh = au_dbwh(dentry);
+ h_path.dentry = wh_dentry;
-+ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex);
++ h_path.mnt = au_sbr_mnt(sb, bindex);
+ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path,
+ dentry);
+ if (unlikely(err))
@@ -15055,6 +15897,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (au_ibstart(dir) == au_dbstart(dentry))
+ au_cpup_attr_timesizes(dir);
+ dir->i_version++;
++ au_fhsm_wrote(sb, bindex, /*force*/0);
+ return 0; /* success */
+ }
+
@@ -15536,7 +16379,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ dget(au_h_dptr(src_dentry, a->bsrc)));
+ dget(a->h_path.dentry);
+ au_set_h_dptr(dentry, a->bdst, NULL);
++ AuDbg("temporary d_inode...\n");
++ spin_lock(&dentry->d_lock);
+ dentry->d_inode = src_dentry->d_inode; /* tmp */
++ spin_unlock(&dentry->d_lock);
+ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0);
+ if (IS_ERR(h_file))
+ err = PTR_ERR(h_file);
@@ -15558,7 +16404,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_set_h_dptr(dentry, a->bdst,
+ a->h_path.dentry);
+ }
++ spin_lock(&dentry->d_lock);
+ dentry->d_inode = NULL; /* restore */
++ spin_unlock(&dentry->d_lock);
++ AuDbg("temporary d_inode...done\n");
+ au_set_h_dptr(dentry, a->bsrc, NULL);
+ au_set_dbend(dentry, bend);
+ } else {
@@ -15737,6 +16586,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (d_unhashed(a->h_path.dentry))
+ /* some filesystem calls d_drop() */
+ d_drop(dentry);
++ /* some filesystems consume an inode even hardlink */
++ au_fhsm_wrote(sb, a->bdst, /*force*/0);
+ goto out_unpin; /* success */
+
+out_revert:
@@ -16386,8 +17237,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
--- a/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/i_op_ren.c 2014-01-20 03:24:33.512760970 +0000
-@@ -0,0 +1,1032 @@
++++ b/fs/aufs/i_op_ren.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -16672,7 +17523,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_hn_imtx_unlock(a->src_hinode);
+ if (IS_ERR(diropq))
+ err = PTR_ERR(diropq);
-+ dput(diropq);
++ else
++ dput(diropq);
+
+ return err;
+}
@@ -16772,6 +17624,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (a->thargs)
+ au_ren_del_whtmp(a); /* ignore this error */
+
++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0);
+ err = 0;
+ goto out_success;
+
@@ -18196,8 +19049,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return au_test_h_perm(h_inode, mask);
+}
--- a/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/inode.h 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,601 @@
++++ b/fs/aufs/inode.h 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -18308,6 +19161,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+};
+
+void au_pin_hdir_unlock(struct au_pin *p);
++int au_pin_hdir_lock(struct au_pin *p);
+int au_pin_hdir_relock(struct au_pin *p);
+void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task);
+void au_pin_hdir_acquire_nest(struct au_pin *p);
@@ -18800,8 +19654,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_INODE_H__ */
--- a/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/ioctl.c 2014-01-20 03:24:33.516760970 +0000
-@@ -0,0 +1,201 @@
++++ b/fs/aufs/ioctl.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -18824,6 +19678,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ * plink-management and readdir in userspace.
+ * assist the pathconf(3) wrapper library.
+ * move-down
++ * File-based Hierarchical Storage Management.
+ */
+
+#include <linux/compat.h>
@@ -18925,6 +19780,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long err;
++ struct dentry *dentry;
+
+ switch (cmd) {
+ case AUFS_CTL_RDU:
@@ -18940,6 +19796,18 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ err = au_ibusy_ioctl(file, arg);
+ break;
+
++ case AUFS_CTL_BRINFO:
++ err = au_brinfo_ioctl(file, arg);
++ break;
++
++ case AUFS_CTL_FHSM_FD:
++ dentry = file->f_dentry;
++ if (IS_ROOT(dentry))
++ err = au_fhsm_fd(dentry->d_sb, arg);
++ else
++ err = -ENOTTY;
++ break;
++
+ default:
+ /* do not call the lower */
+ AuDbg("0x%x\n", cmd);
@@ -18989,6 +19857,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ err = au_ibusy_compat_ioctl(file, arg);
+ break;
+
++ case AUFS_CTL_BRINFO:
++ err = au_brinfo_compat_ioctl(file, arg);
++ break;
++
+ default:
+ err = aufs_ioctl_dir(file, cmd, arg);
+ }
@@ -19584,8 +20456,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_MODULE_H__ */
--- a/fs/aufs/mvdown.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/mvdown.c 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,653 @@
++++ b/fs/aufs/mvdown.c 2014-09-08 00:38:33.514569904 +0100
+@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2011-2014 Junjiro R. Okajima
+ *
@@ -19615,6 +20487,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ struct dentry *h_parent;
+ struct au_hinode *hdir;
+ struct inode *h_dir, *h_inode;
++ struct au_pin pin;
+ } info[AUFS_MVDOWN_NARRAY];
+
+ struct aufs_mvdown mvdown;
@@ -19623,7 +20496,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ struct super_block *sb;
+ aufs_bindex_t bopq, bwh, bfound;
+ unsigned char rename_lock;
-+ struct au_pin pin;
+};
+
+#define mvd_errno mvdown.au_errno
@@ -19637,12 +20509,14 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir
+#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir
+#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode
++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin
+
+#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb
+#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent
+#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir
+#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir
+#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode
++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin
+
+#define AU_MVD_PR(flag, ...) do { \
+ if (flag) \
@@ -19658,13 +20532,20 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ sb = a->sb;
+ bindex = a->mvd_bsrc;
+ bend = au_sbend(sb);
-+ if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) {
++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER)
++ for (bindex++; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_fhsm(br->br_perm)
++ && (!(au_br_sb(br)->s_flags & MS_RDONLY)))
++ return bindex;
++ }
++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER))
+ for (bindex++; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ if (!au_br_rdonly(br))
+ return bindex;
+ }
-+ } else {
++ else
+ for (bindex++; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ if (!(au_br_sb(br)->s_flags & MS_RDONLY)) {
@@ -19674,7 +20555,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return bindex;
+ }
+ }
-+ }
+
+ return -1;
+}
@@ -19713,22 +20593,44 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc);
+ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst);
++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst,
++ au_opt_udba(a->sb),
++ AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++ AuTraceErr(err);
++ if (unlikely(err)) {
++ AU_MVD_PR(dmsg, "pin_dst failed\n");
++ goto out;
++ }
++
+ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) {
+ a->rename_lock = 0;
-+ err = au_pin(&a->pin, a->dentry, a->mvd_bdst,
-+ au_opt_udba(a->sb),
-+ AuPin_MNT_WRITE | AuPin_DI_LOCKED);
-+ if (!err) {
-+ a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
-+ mutex_lock_nested(&a->mvd_h_src_dir->i_mutex,
-+ AuLsc_I_PARENT3);
-+ } else
-+ AU_MVD_PR(dmsg, "pin failed\n");
-+ goto out;
++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
++ AuLsc_DI_PARENT, AuLsc_I_PARENT3,
++ au_opt_udba(a->sb),
++ AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++ err = au_do_pin(&a->mvd_pin_src);
++ AuTraceErr(err);
++ a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
++ if (unlikely(err)) {
++ AU_MVD_PR(dmsg, "pin_src failed\n");
++ goto out_dst;
++ }
++ goto out; /* success */
+ }
+
-+ err = 0;
+ a->rename_lock = 1;
++ au_pin_hdir_unlock(&a->mvd_pin_dst);
++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc,
++ au_opt_udba(a->sb),
++ AuPin_MNT_WRITE | AuPin_DI_LOCKED);
++ AuTraceErr(err);
++ a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode;
++ if (unlikely(err)) {
++ AU_MVD_PR(dmsg, "pin_src failed\n");
++ au_pin_hdir_lock(&a->mvd_pin_dst);
++ goto out_dst;
++ }
++ au_pin_hdir_unlock(&a->mvd_pin_src);
+ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
+ a->mvd_h_dst_parent, a->mvd_hdir_dst);
+ if (h_trap) {
@@ -19737,7 +20639,20 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ err = (h_trap != a->mvd_h_dst_parent);
+ }
+ BUG_ON(err); /* it should never happen */
++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) {
++ err = -EBUSY;
++ AuTraceErr(err);
++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
++ a->mvd_h_dst_parent, a->mvd_hdir_dst);
++ au_pin_hdir_lock(&a->mvd_pin_src);
++ au_unpin(&a->mvd_pin_src);
++ au_pin_hdir_lock(&a->mvd_pin_dst);
++ goto out_dst;
++ }
++ goto out; /* success */
+
++out_dst:
++ au_unpin(&a->mvd_pin_dst);
+out:
+ AuTraceErr(err);
+ return err;
@@ -19745,12 +20660,16 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a)
+{
-+ if (!a->rename_lock) {
-+ mutex_unlock(&a->mvd_h_src_dir->i_mutex);
-+ au_unpin(&a->pin);
-+ } else
++ if (!a->rename_lock)
++ au_unpin(&a->mvd_pin_src);
++ else {
+ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src,
+ a->mvd_h_dst_parent, a->mvd_hdir_dst);
++ au_pin_hdir_lock(&a->mvd_pin_src);
++ au_unpin(&a->mvd_pin_src);
++ au_pin_hdir_lock(&a->mvd_pin_dst);
++ }
++ au_unpin(&a->mvd_pin_dst);
+}
+
+/* copy-down the file */
@@ -19762,7 +20681,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ .bdst = a->mvd_bdst,
+ .bsrc = a->mvd_bsrc,
+ .len = -1,
-+ .pin = &a->pin,
++ .pin = &a->mvd_pin_dst,
+ .flags = AuCpup_DTIME | AuCpup_HOPEN
+ };
+
@@ -19821,8 +20740,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+/*
+ * unlink the topmost h_dentry
-+ * Note: the target file MAY be modified by UDBA between this mutex_unlock() and
-+ * mutex_lock() in vfs_unlink(). in this case, such changes may be lost.
+ */
+static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a)
+{
@@ -19895,6 +20812,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out_unlock;
+
++ AuDbg("%pd2, 0x%x, %d --> %d\n",
++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst);
+ if (find_lower_writable(a) < 0)
+ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM;
+
@@ -20167,8 +21086,6 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(!capable(CAP_SYS_ADMIN)))
+ goto out;
+
-+ WARN_ONCE(1, "move-down is still testing...\n");
-+
+ err = -ENOMEM;
+ args = kmalloc(sizeof(*args), GFP_NOFS);
+ if (unlikely(!args))
@@ -20210,13 +21127,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out_parent;
+
-+ AuDbgDentry(dentry);
-+ AuDbgInode(args->inode);
+ err = au_do_mvdown(dmsg, args);
+ if (unlikely(err))
+ goto out_parent;
-+ AuDbgDentry(dentry);
-+ AuDbgInode(args->inode);
+
+ au_cpup_attr_timesizes(args->dir);
+ au_cpup_attr_timesizes(args->inode);
@@ -20240,8 +21153,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
--- a/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/opts.c 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,1750 @@
++++ b/fs/aufs/opts.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,1799 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -20289,6 +21202,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ Opt_diropq_a, Opt_diropq_w,
+ Opt_warn_perm, Opt_nowarn_perm,
+ Opt_wbr_copyup, Opt_wbr_create,
++ Opt_fhsm_sec,
+ Opt_refrof, Opt_norefrof,
+ Opt_verbose, Opt_noverbose,
+ Opt_sum, Opt_nosum, Opt_wsum,
@@ -20346,6 +21260,12 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ {Opt_dio, "dio"},
+ {Opt_nodio, "nodio"},
+
++#ifdef CONFIG_AUFS_FHSM
++ {Opt_fhsm_sec, "fhsm_sec=%d"},
++#else
++ {Opt_ignore_silent, "fhsm_sec=%d"},
++#endif
++
+ {Opt_diropq_a, "diropq=always"},
+ {Opt_diropq_a, "diropq=a"},
+ {Opt_diropq_w, "diropq=whiteouted"},
@@ -20456,6 +21376,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG},
+ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL},
+ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN},
++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM},
+
+ /* ro/rr branch */
+ {AuBrRAttr_WH, AUFS_BRRATTR_WH},
@@ -20947,6 +21868,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuDbg("copyup %d, %s\n", opt->wbr_copyup,
+ au_optstr_wbr_copyup(opt->wbr_copyup));
+ break;
++ case Opt_fhsm_sec:
++ AuDbg("fhsm_sec %u\n", opt->fhsm_second);
++ break;
+ default:
+ BUG();
+ }
@@ -21425,6 +22349,20 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ pr_err("wrong value, %s\n", opt_str);
+ break;
+
++ case Opt_fhsm_sec:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0)) {
++ pr_err("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (sysaufs_brs) {
++ opt->fhsm_second = n;
++ opt->type = token;
++ } else
++ pr_warn("ignored %s\n", opt_str);
++ err = 0;
++ break;
++
+ case Opt_ignore:
+ pr_warn("ignored %s\n", opt_str);
+ /*FALLTHROUGH*/
@@ -21541,6 +22479,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_fset_opts(opts->flags, REFRESH_DYAOP);
+ break;
+
++ case Opt_fhsm_sec:
++ au_fhsm_set(sbinfo, opt->fhsm_second);
++ break;
++
+ case Opt_diropq_a:
+ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
+ break;
@@ -21754,7 +22696,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
+ unsigned int pending)
+{
-+ int err;
++ int err, fhsm;
+ aufs_bindex_t bindex, bend;
+ unsigned char do_plink, skip, do_free;
+ struct au_branch *br;
@@ -21785,6 +22727,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ " by the permission bits on the lower branch\n");
+
+ err = 0;
++ fhsm = 0;
+ root = sb->s_root;
+ dir = root->d_inode;
+ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
@@ -21827,6 +22770,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (wbr)
+ wbr_wh_read_unlock(wbr);
+
++ if (au_br_fhsm(br->br_perm)) {
++ fhsm++;
++ AuDebugOn(!br->br_fhsm);
++ }
++
+ if (skip)
+ continue;
+
@@ -21845,6 +22793,20 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+ }
+
++ if (fhsm >= 2) {
++ au_fset_si(sbinfo, FHSM);
++ for (bindex = bend; bindex >= 0; bindex--) {
++ br = au_sbr(sb, bindex);
++ if (au_br_fhsm(br->br_perm)) {
++ au_fhsm_set_bottom(sb, bindex);
++ break;
++ }
++ }
++ } else {
++ au_fclr_si(sbinfo, FHSM);
++ au_fhsm_set_bottom(sb, -1);
++ }
++
+ return err;
+}
+
@@ -21993,8 +22955,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return au_mntflags(sb) & AuOptMask_UDBA;
+}
--- a/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/opts.h 2014-07-15 14:04:48.732871625 +0100
-@@ -0,0 +1,212 @@
++++ b/fs/aufs/opts.h 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -22164,6 +23126,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ int udba;
+ struct au_opt_wbr_create wbr_create;
+ int wbr_copyup;
++ unsigned int fhsm_second;
+ };
+};
+
@@ -23558,8 +24521,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_RWSEM_H__ */
--- a/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/sbinfo.c 2014-01-20 03:24:33.516760970 +0000
-@@ -0,0 +1,351 @@
++++ b/fs/aufs/sbinfo.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -23659,6 +24622,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup;
+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create;
+
++ au_fhsm_init(sbinfo);
++
+ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def);
+
+ sbinfo->si_xino_jiffy = jiffies;
@@ -24026,8 +24991,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_SPL_H__ */
--- a/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/super.c 2014-07-15 14:04:48.736871625 +0100
-@@ -0,0 +1,998 @@
++++ b/fs/aufs/super.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,1004 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -24309,6 +25274,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
+ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
+
++ au_fhsm_show(m, sbinfo);
++
+ AuBool(SUM, sum);
+ /* AuBool(SUM_W, wsum); */
+ AuBool(WARN_PERM, warn_perm);
@@ -24524,9 +25491,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+
+ sz = sizeof(array) * *hint;
-+ array = kmalloc(sz, GFP_NOFS);
++ array = kzalloc(sz, GFP_NOFS);
+ if (unlikely(!array))
-+ array = vmalloc(sz);
++ array = vzalloc(sz);
+ if (unlikely(!array)) {
+ array = ERR_PTR(-ENOMEM);
+ goto out;
@@ -24693,6 +25660,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ sigen = au_sigen(sb);
+ for (ull = 0; ull < max; ull++) {
+ inode = array[ull];
++ if (unlikely(!inode))
++ break;
+ if (au_iigen(inode, NULL) != sigen) {
+ ii_write_lock_child(inode);
+ e = au_refresh_hinode_self(inode);
@@ -24826,6 +25795,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_dy_arefresh(do_dx);
+ }
+
++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */
+ aufs_write_unlock(root);
+
+out_mtx:
@@ -25001,6 +25971,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (sbinfo) {
+ au_sbilist_del(sb);
+ aufs_write_lock(sb->s_root);
++ au_fhsm_fin(sb);
+ if (sbinfo->si_wbr_create_ops->fin)
+ sbinfo->si_wbr_create_ops->fin(sb);
+ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
@@ -25027,8 +25998,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ .owner = THIS_MODULE,
+};
--- a/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/super.h 2014-07-15 14:04:48.736871625 +0100
-@@ -0,0 +1,582 @@
++++ b/fs/aufs/super.h 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -25106,6 +26077,21 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return ino % AuPlink_NHASH;
+}
+
++/* File-based Hierarchical Storage Management */
++struct au_fhsm {
++#ifdef CONFIG_AUFS_FHSM
++ /* allow only one process who can receive the notification */
++ spinlock_t fhsm_spin;
++ pid_t fhsm_pid;
++ wait_queue_head_t fhsm_wqh;
++ atomic_t fhsm_readable;
++
++ /* these are protected by si_rwsem */
++ unsigned long fhsm_expire;
++ aufs_bindex_t fhsm_bottom;
++#endif
++};
++
+struct au_branch;
+struct au_sbinfo {
+ /* nowait tasks in the system-wide workqueue */
@@ -25155,6 +26141,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ /* most free space */
+ struct au_wbr_mfs si_wbr_mfs;
+
++ /* File-based Hierarchical Storage Management */
++ struct au_fhsm si_fhsm;
++
+ /* mount flags */
+ /* include/asm-ia64/siginfo.h defines a macro named si_flags */
+ unsigned int si_mntflags;
@@ -25238,6 +26227,14 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ * if it is false, refreshing dirs at access time is unnecesary
+ */
+#define AuSi_FAILED_REFRESH_DIR 1
++
++#define AuSi_FHSM (1 << 1) /* fhsm is active now */
++
++#ifndef CONFIG_AUFS_FHSM
++#undef AuSi_FHSM
++#define AuSi_FHSM 0
++#endif
++
+static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
+ unsigned int flag)
+{
@@ -25320,6 +26317,43 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+/* mvdown.c */
+int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg);
+
++#ifdef CONFIG_AUFS_FHSM
++/* fhsm.c */
++
++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm)
++{
++ pid_t pid;
++
++ spin_lock(&fhsm->fhsm_spin);
++ pid = fhsm->fhsm_pid;
++ spin_unlock(&fhsm->fhsm_spin);
++
++ return pid;
++}
++
++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force);
++void au_fhsm_wrote_all(struct super_block *sb, int force);
++int au_fhsm_fd(struct super_block *sb, int oflags);
++int au_fhsm_br_alloc(struct au_branch *br);
++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex);
++void au_fhsm_fin(struct super_block *sb);
++void au_fhsm_init(struct au_sbinfo *sbinfo);
++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec);
++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo);
++#else
++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex,
++ int force)
++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force)
++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags)
++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm)
++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br)
++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(au_fhsm_fin, struct super_block *sb)
++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo)
++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec)
++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo)
++#endif
++
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_sbinfo *au_sbi(struct super_block *sb)
@@ -25436,8 +26470,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ bit = si_pid_bit();
+ if (bit < PID_MAX_DEFAULT)
+ return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
-+ else
-+ return si_pid_test_slow(sb);
++ return si_pid_test_slow(sb);
+}
+
+static inline void si_pid_set(struct super_block *sb)
@@ -25719,8 +26752,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
--- a/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/sysaufs.h 2014-01-20 03:24:33.516760970 +0000
-@@ -0,0 +1,103 @@
++++ b/fs/aufs/sysaufs.h 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -25792,6 +26825,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
+ char *buf);
++long au_brinfo_ioctl(struct file *file, unsigned long arg);
++#ifdef CONFIG_COMPAT
++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg);
++#endif
+
+void sysaufs_br_init(struct au_branch *br);
+void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
@@ -25825,8 +26862,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __SYSAUFS_H__ */
--- a/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/sysfs.c 2014-07-15 14:04:48.736871625 +0100
-@@ -0,0 +1,289 @@
++++ b/fs/aufs/sysfs.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -25848,6 +26885,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ * sysfs interface
+ */
+
++#include <linux/compat.h>
+#include <linux/seq_file.h>
+#include "aufs.h"
+
@@ -26044,6 +27082,88 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+/* ---------------------------------------------------------------------- */
+
++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg)
++{
++ int err;
++ int16_t brid;
++ aufs_bindex_t bindex, bend;
++ size_t sz;
++ char *buf;
++ struct seq_file *seq;
++ struct au_branch *br;
++
++ si_read_lock(sb, AuLock_FLUSH);
++ bend = au_sbend(sb);
++ err = bend + 1;
++ if (!arg)
++ goto out;
++
++ err = -ENOMEM;
++ buf = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!buf))
++ goto out;
++
++ seq = au_seq(buf, PAGE_SIZE);
++ err = PTR_ERR(seq);
++ if (IS_ERR(seq))
++ goto out_buf;
++
++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path);
++ for (bindex = 0; bindex <= bend; bindex++, arg++) {
++ err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg));
++ if (unlikely(err))
++ break;
++
++ br = au_sbr(sb, bindex);
++ brid = br->br_id;
++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id));
++ err = __put_user(brid, &arg->id);
++ if (unlikely(err))
++ break;
++
++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm));
++ err = __put_user(br->br_perm, &arg->perm);
++ if (unlikely(err))
++ break;
++
++ au_seq_path(seq, &br->br_path);
++ err = seq_putc(seq, '\0');
++ if (!err && seq->count <= sz) {
++ err = copy_to_user(arg->path, seq->buf, seq->count);
++ seq->count = 0;
++ if (unlikely(err))
++ break;
++ } else {
++ err = -E2BIG;
++ goto out_seq;
++ }
++ }
++ if (unlikely(err))
++ err = -EFAULT;
++
++out_seq:
++ kfree(seq);
++out_buf:
++ free_page((unsigned long)buf);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++long au_brinfo_ioctl(struct file *file, unsigned long arg)
++{
++ return au_brinfo(file->f_dentry->d_sb, (void __user *)arg);
++}
++
++#ifdef CONFIG_COMPAT
++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg)
++{
++ return au_brinfo(file->f_dentry->d_sb, compat_ptr(arg));
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
+void sysaufs_br_init(struct au_branch *br)
+{
+ int i;
@@ -27169,8 +28289,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return 0;
+}
--- a/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/vfsub.c 2014-07-15 14:04:40.008871417 +0100
-@@ -0,0 +1,782 @@
++++ b/fs/aufs/vfsub.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -27331,7 +28451,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out;
+
++ lockdep_off();
+ err = vfs_create(dir, path->dentry, mode, want_excl);
++ lockdep_on();
+ if (!err) {
+ struct path tmp = *path;
+ int did;
@@ -27362,7 +28484,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out;
+
++ lockdep_off();
+ err = vfs_symlink(dir, path->dentry, symname);
++ lockdep_on();
+ if (!err) {
+ struct path tmp = *path;
+ int did;
@@ -27393,7 +28517,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out;
+
++ lockdep_off();
+ err = vfs_mknod(dir, path->dentry, mode, dev);
++ lockdep_on();
+ if (!err) {
+ struct path tmp = *path;
+ int did;
@@ -27519,7 +28645,9 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ if (unlikely(err))
+ goto out;
+
++ lockdep_off();
+ err = vfs_mkdir(dir, path->dentry, mode);
++ lockdep_on();
+ if (!err) {
+ struct path tmp = *path;
+ int did;
@@ -27765,9 +28893,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ int err, do_sio, wkq_err;
+
+ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
-+ if (!do_sio)
++ if (!do_sio) {
++ lockdep_off();
+ err = vfsub_mkdir(dir, path, mode);
-+ else {
++ lockdep_on();
++ } else {
+ struct au_vfsub_mkdir_args args = {
+ .errp = &err,
+ .dir = dir,
@@ -27799,9 +28929,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ int err, do_sio, wkq_err;
+
+ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
-+ if (!do_sio)
++ if (!do_sio) {
++ lockdep_off();
+ err = vfsub_rmdir(dir, path);
-+ else {
++ lockdep_on();
++ } else {
+ struct au_vfsub_rmdir_args args = {
+ .errp = &err,
+ .dir = dir,
@@ -27834,8 +28966,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+ *a->errp = -EPERM;
+ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
++ lockdep_off();
+ *a->errp = notify_change(a->path->dentry, a->ia,
+ a->delegated_inode);
++ lockdep_on();
+ if (!*a->errp)
+ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
+ }
@@ -28241,8 +29375,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#endif /* __KERNEL__ */
+#endif /* __AUFS_VFSUB_H__ */
--- a/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/wbr_policy.c 2014-07-15 14:04:48.736871625 +0100
-@@ -0,0 +1,764 @@
++++ b/fs/aufs/wbr_policy.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -28410,6 +29544,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ au_set_ibend(inode, bdst);
+ au_set_h_iptr(inode, bdst, au_igrab(h_inode),
+ au_hi_flags(inode, /*isdir*/1));
++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0);
+ goto out; /* success */
+
+ /* revert */
@@ -29008,8 +30143,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ }
+};
--- a/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
-+++ b/fs/aufs/whout.c 2014-07-15 14:04:48.736871625 +0100
-@@ -0,0 +1,1051 @@
++++ b/fs/aufs/whout.c 2014-09-08 00:38:33.518569904 +0100
+@@ -0,0 +1,1056 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -29602,6 +30737,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ wbr_wh_write_unlock(wbr);
+ au_hn_imtx_unlock(hdir);
+ di_read_unlock(a->sb->s_root, AuLock_IR);
++ if (!err)
++ au_fhsm_wrote(a->sb, bindex, /*force*/0);
+
+out:
+ if (wbr)
@@ -29689,6 +30826,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+ /* return this error in this context */
+ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true);
++ if (!err)
++ au_fhsm_wrote(sb, bindex, /*force*/0);
+
+out:
+ wbr_wh_read_unlock(wbr);
@@ -29813,9 +30952,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
+ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) {
+ err = link_or_create_wh(sb, bindex, wh_dentry);
-+ if (!err)
++ if (!err) {
+ au_set_dbwh(dentry, bindex);
-+ else {
++ au_fhsm_wrote(sb, bindex, /*force*/0);
++ } else {
+ dput(wh_dentry);
+ wh_dentry = ERR_PTR(err);
+ }
@@ -31779,8 +32919,8 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ return err;
+}
--- a/include/uapi/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
-+++ b/include/uapi/linux/aufs_type.h 2014-07-15 14:04:48.740871626 +0100
-@@ -0,0 +1,301 @@
++++ b/include/uapi/linux/aufs_type.h 2014-09-08 00:39:05.266571221 +0100
+@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2005-2014 Junjiro R. Okajima
+ *
@@ -31822,7 +32962,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+#include <linux/limits.h>
+
-+#define AUFS_VERSION "3.x-rcN-20140714"
++#define AUFS_VERSION "3.16-20140908"
+
+/* todo? move this to linux-2.6.19/include/magic.h */
+#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -31876,6 +33016,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define AUFS_WKQ_NAME AUFS_NAME "d"
+#define AUFS_MFS_DEF_SEC 30 /* seconds */
+#define AUFS_MFS_MAX_SEC 3600 /* seconds */
++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */
+#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */
+
+/* pseudo-link maintenace under /proc */
@@ -31901,11 +33042,77 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define AUFS_BRPERM_RR "rr"
+#define AUFS_BRATTR_COO_REG "coo_reg"
+#define AUFS_BRATTR_COO_ALL "coo_all"
++#define AUFS_BRATTR_FHSM "fhsm"
+#define AUFS_BRATTR_UNPIN "unpin"
+#define AUFS_BRRATTR_WH "wh"
+#define AUFS_BRWATTR_NLWH "nolwh"
+#define AUFS_BRWATTR_MOO "moo"
+
++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */
++#define AuBrPerm_RO (1 << 1) /* readonly */
++#define AuBrPerm_RR (1 << 2) /* natively readonly */
++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR)
++
++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */
++#define AuBrAttr_COO_ALL (1 << 4)
++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL)
++
++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */
++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of
++ branch */
++
++#define AuBrRAttr_WH (1 << 7) /* whiteout-able */
++#define AuBrRAttr_Mask AuBrRAttr_WH
++
++#define AuBrWAttr_NoLinkWH (1 << 8) /* un-hardlinkable whiteouts */
++#define AuBrWAttr_MOO (1 << 9) /* move-up on open */
++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO)
++
++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO)
++
++#ifdef __KERNEL__
++#ifndef CONFIG_AUFS_FHSM
++#undef AuBrAttr_FHSM
++#define AuBrAttr_FHSM 0
++#endif
++#endif
++
++/* the longest combination */
++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \
++ "+" AUFS_BRATTR_COO_REG \
++ "+" AUFS_BRATTR_FHSM \
++ "+" AUFS_BRATTR_UNPIN \
++ "+" AUFS_BRWATTR_NLWH)
++
++typedef struct {
++ char a[AuBrPermStrSz];
++} au_br_perm_str_t;
++
++static inline int au_br_writable(int brperm)
++{
++ return brperm & AuBrPerm_RW;
++}
++
++static inline int au_br_whable(int brperm)
++{
++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH);
++}
++
++static inline int au_br_wh_linkable(int brperm)
++{
++ return !(brperm & AuBrWAttr_NoLinkWH);
++}
++
++static inline int au_br_cmoo(int brperm)
++{
++ return brperm & AuBrAttr_CMOO_Mask;
++}
++
++static inline int au_br_fhsm(int brperm)
++{
++ return brperm & AuBrAttr_FHSM;
++}
++
+/* ---------------------------------------------------------------------- */
+
+/* ioctl */
@@ -31914,14 +33121,11 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+ AuCtl_RDU,
+ AuCtl_RDU_INO,
+
-+ /* pathconf wrapper */
-+ AuCtl_WBR_FD,
-+
-+ /* busy inode */
-+ AuCtl_IBUSY,
-+
-+ /* move-down */
-+ AuCtl_MVDOWN
++ AuCtl_WBR_FD, /* pathconf wrapper */
++ AuCtl_IBUSY, /* busy inode */
++ AuCtl_MVDOWN, /* move-down */
++ AuCtl_BR, /* info about branches */
++ AuCtl_FHSM_FD /* connection for fhsm */
+};
+
+/* borrowed from linux/include/linux/kernel.h */
@@ -32035,9 +33239,10 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */
+#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */
+#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */
-+#define AUFS_MVDOWN_STFS (1 << 9) /* req. stfs */
-+#define AUFS_MVDOWN_STFS_FAILED (1 << 10) /* output: stfs is unusable */
-+#define AUFS_MVDOWN_BOTTOM (1 << 11) /* output: no more lowers */
++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */
++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */
++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */
++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */
+
+/* index for move-down */
+enum {
@@ -32072,6 +33277,18 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+
+/* ---------------------------------------------------------------------- */
+
++union aufs_brinfo {
++ /* PATH_MAX may differ between kernel-space and user-space */
++ char _spacer[4096];
++ struct {
++ int16_t id;
++ int perm;
++ char path[0];
++ };
++} __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)
@@ -32080,5 +33297,7 @@ Patch generated by debian/patches/features/all/aufs3/gen-patch
+#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy)
+#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \
+ struct aufs_mvdown)
++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo)
++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int)
+
+#endif /* __AUFS_TYPE_H__ */
diff --git a/debian/patches/features/all/aufs3/aufs3-base.patch b/debian/patches/features/all/aufs3/aufs3-base.patch
index 69cee6a9174e..333a088ef4b4 100644
--- a/debian/patches/features/all/aufs3/aufs3-base.patch
+++ b/debian/patches/features/all/aufs3/aufs3-base.patch
@@ -1,13 +1,38 @@
From: J. R. Okajima <hooanon05@yahoo.co.jp>
-Date: Mon Jun 30 09:36:40 2014 +0900
-Subject: aufs3.x-rcN base patch
-Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/501539c2f9478ef69fa42acfb43ef1420d9bb524/tree/
+Date: Sat Aug 23 03:27:11 2014 +0900
+Subject: aufs3.16 base patch
+Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/888949daf96bf7e2b857dc38e22029513f94d4ae/tree/
Bug-Debian: https://bugs.debian.org/541828
Patch headers added by debian/patches/features/all/aufs3/gen-patch
-aufs3.x-rcN base patch
+aufs3.16 base patch
+diff --git a/MAINTAINERS b/MAINTAINERS
+index c2066f4..f07a989 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1698,6 +1698,20 @@ F: include/linux/audit.h
+ F: include/uapi/linux/audit.h
+ F: kernel/audit*
+
++AUFS (advanced multi layered unification filesystem) FILESYSTEM
++M: "J. R. Okajima" <hooanon05g@gmail.com>
++L: linux-unionfs@vger.kernel.org
++L: aufs-users@lists.sourceforge.net (members only)
++W: http://aufs.sourceforge.net
++T: git://git.code.sf.net/p/aufs/aufs3-linux
++T: git://github.com/sfjro/aufs3-linux.git
++S: Supported
++F: Documentation/filesystems/aufs/
++F: Documentation/ABI/testing/debugfs-aufs
++F: Documentation/ABI/testing/sysfs-aufs
++F: fs/aufs/
++F: include/uapi/linux/aufs_type.h
++
+ AUXILIARY DISPLAY DRIVERS
+ M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
+ W: http://miguelojeda.es/auxdisplay.htm
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6cb1beb..30efd68 100644
--- a/drivers/block/loop.c
diff --git a/debian/patches/features/all/aufs3/aufs3-kbuild.patch b/debian/patches/features/all/aufs3/aufs3-kbuild.patch
index 77cea2478fcf..d1316a3e07b8 100644
--- a/debian/patches/features/all/aufs3/aufs3-kbuild.patch
+++ b/debian/patches/features/all/aufs3/aufs3-kbuild.patch
@@ -1,12 +1,12 @@
From: J. R. Okajima <hooanon05@yahoo.co.jp>
-Date: Sun Jun 15 19:47:55 2014 +0900
-Subject: aufs3.x-rcN kbuild patch
-Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/501539c2f9478ef69fa42acfb43ef1420d9bb524/tree/
+Date: Thu Aug 7 21:42:20 2014 +0900
+Subject: aufs3.16 kbuild patch
+Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/888949daf96bf7e2b857dc38e22029513f94d4ae/tree/
Bug-Debian: https://bugs.debian.org/541828
Patch headers added by debian/patches/features/all/aufs3/gen-patch
-aufs3.x-rcN kbuild patch
+aufs3.16 kbuild patch
diff --git a/fs/Kconfig b/fs/Kconfig
index 312393f..78632ed 100644
diff --git a/debian/patches/features/all/aufs3/aufs3-mmap.patch b/debian/patches/features/all/aufs3/aufs3-mmap.patch
index f32562802d2e..8b1266602548 100644
--- a/debian/patches/features/all/aufs3/aufs3-mmap.patch
+++ b/debian/patches/features/all/aufs3/aufs3-mmap.patch
@@ -1,12 +1,12 @@
From: J. R. Okajima <hooanon05@yahoo.co.jp>
-Date: Thu Jul 10 02:32:20 2014 +0900
-Subject: aufs3.x-rcN mmap patch
-Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/501539c2f9478ef69fa42acfb43ef1420d9bb524/tree/
+Date: Thu Aug 7 21:42:20 2014 +0900
+Subject: aufs3.16 mmap patch
+Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/888949daf96bf7e2b857dc38e22029513f94d4ae/tree/
Bug-Debian: https://bugs.debian.org/541828
Patch headers added by debian/patches/features/all/aufs3/gen-patch
-aufs3.x-rcN mmap patch
+aufs3.16 mmap patch
diff --git a/fs/buffer.c b/fs/buffer.c
index eba6e4f..31f0b2d 100644
@@ -79,109 +79,34 @@ index 678455d..0ef7ef4 100644
ino = inode->i_ino;
pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
diff --git a/include/linux/mm.h b/include/linux/mm.h
-index e03dd29..f849643 100644
+index e03dd29..dd32624 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
-@@ -18,6 +18,9 @@
- #include <linux/pfn.h>
- #include <linux/bit_spinlock.h>
- #include <linux/shrinker.h>
-+#include <linux/dcache.h>
-+#include <linux/file.h>
-+#include <linux/fs.h>
-
- struct mempolicy;
- struct anon_vma;
-@@ -1184,6 +1187,93 @@ static inline int fixup_user_fault(struct task_struct *tsk,
+@@ -1184,6 +1184,28 @@ static inline int fixup_user_fault(struct task_struct *tsk,
}
#endif
-+/*
-+ * Mainly for aufs which mmap(2) diffrent file and wants to print different path
-+ * in /proc/PID/maps.
-+ */
-+/* #define AUFS_DEBUG_MMAP */
-+static inline void aufs_trace(struct file *f, struct file *pr,
-+ const char func[], int line, const char func2[])
-+{
-+#ifdef AUFS_DEBUG_MMAP
-+ if (pr)
-+ pr_info("%s:%d: %s, %p\n", func, line, func2,
-+ f ? (char *)f->f_dentry->d_name.name : "(null)");
-+#endif
-+}
-+
-+static inline struct file *vmr_do_pr_or_file(struct vm_region *region,
-+ const char func[], int line)
-+{
-+ struct file *f = region->vm_file, *pr = region->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ return (f && pr) ? pr : f;
-+}
-+
-+static inline void vmr_do_fput(struct vm_region *region,
-+ const char func[], int line)
-+{
-+ struct file *f = region->vm_file, *pr = region->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ fput(f);
-+ if (f && pr)
-+ fput(pr);
-+}
++#ifdef CONFIG_MMU
++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int);
++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[],
++ int);
++extern void vma_do_get_file(struct vm_area_struct *, const char[], int);
++extern void vma_do_fput(struct vm_area_struct *, const char[], int);
+
-+static inline void vma_do_file_update_time(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ file_update_time(f);
-+ if (f && pr)
-+ file_update_time(pr);
-+}
-+
-+static inline struct file *vma_do_pr_or_file(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ return (f && pr) ? pr : f;
-+}
-+
-+static inline void vma_do_get_file(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ get_file(f);
-+ if (f && pr)
-+ get_file(pr);
-+}
-+
-+static inline void vma_do_fput(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+ aufs_trace(f, pr, func, line, __func__);
-+ fput(f);
-+ if (f && pr)
-+ fput(pr);
-+}
-+
-+#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \
-+ __LINE__)
-+#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__)
+#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \
+ __LINE__)
+#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \
+ __LINE__)
+#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__)
+#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__)
++#else
++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int);
++extern void vmr_do_fput(struct vm_region *, const char[], int);
++
++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \
++ __LINE__)
++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__)
++#endif /* CONFIG_MMU */
+
extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
@@ -219,11 +144,24 @@ index 6a13c46..714302c 100644
if (tmp->vm_flags & VM_DENYWRITE)
atomic_dec(&inode->i_writecount);
mutex_lock(&mapping->i_mmap_mutex);
+diff --git a/mm/Makefile b/mm/Makefile
+index 4064f3e..0003fdf 100644
+--- a/mm/Makefile
++++ b/mm/Makefile
+@@ -18,7 +18,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \
+ mm_init.o mmu_context.o percpu.o slab_common.o \
+ compaction.o balloon_compaction.o vmacache.o \
+ interval_tree.o list_lru.o workingset.o \
+- iov_iter.o $(mmu-y)
++ iov_iter.o prfile.o $(mmu-y)
+
+ obj-y += init-mm.o
+
diff --git a/mm/filemap.c b/mm/filemap.c
-index dafb06f..f8c0ba3 100644
+index 900edfa..f4dda0c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
-@@ -2037,7 +2037,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+@@ -2040,7 +2040,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
int ret = VM_FAULT_LOCKED;
sb_start_pagefault(inode->i_sb);
@@ -287,7 +225,7 @@ index a402f8f..134e15d 100644
return error;
}
diff --git a/mm/memory.c b/mm/memory.c
-index d67fd9f..aa1e55d 100644
+index 8b44f76..69a72bf 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2161,7 +2161,7 @@ reuse:
@@ -422,3 +360,95 @@ index 4a852f6..b369644 100644
kmem_cache_free(vm_area_cachep, vma);
kleave(" = %d", ret);
return ret;
+diff --git a/mm/prfile.c b/mm/prfile.c
+new file mode 100644
+index 0000000..fc708d2
+--- /dev/null
++++ b/mm/prfile.c
+@@ -0,0 +1,86 @@
++/*
++ * Mainly for aufs which mmap(2) diffrent file and wants to print different path
++ * in /proc/PID/maps.
++ * Call these functions via macros defined in linux/mm.h.
++ *
++ * See Documentation/filesystems/aufs/design/06mmap.txt
++ *
++ * Copyright (c) 2014 Junjro R. Okajima
++ * Copyright (c) 2014 Ian Campbell
++ */
++
++#include <linux/mm.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++
++/* #define PRFILE_TRACE */
++static inline void prfile_trace(struct file *f, struct file *pr,
++ const char func[], int line, const char func2[])
++{
++#ifdef PRFILE_TRACE
++ if (pr)
++ pr_info("%s:%d: %s, %p\n", func, line, func2,
++ f ? (char *)f->f_dentry->d_name.name : "(null)");
++#endif
++}
++
++#ifdef CONFIG_MMU
++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[],
++ int line)
++{
++ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ file_update_time(f);
++ if (f && pr)
++ file_update_time(pr);
++}
++
++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[],
++ int line)
++{
++ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ return (f && pr) ? pr : f;
++}
++
++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line)
++{
++ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ get_file(f);
++ if (f && pr)
++ get_file(pr);
++}
++
++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line)
++{
++ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ fput(f);
++ if (f && pr)
++ fput(pr);
++}
++#else
++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[],
++ int line)
++{
++ struct file *f = region->vm_file, *pr = region->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ return (f && pr) ? pr : f;
++}
++
++void vmr_do_fput(struct vm_region *region, const char func[], int line)
++{
++ struct file *f = region->vm_file, *pr = region->vm_prfile;
++
++ prfile_trace(f, pr, func, line, __func__);
++ fput(f);
++ if (f && pr)
++ fput(pr);
++}
++#endif /* CONFIG_MMU */
diff --git a/debian/patches/features/all/aufs3/aufs3-remove-circular-includes.patch b/debian/patches/features/all/aufs3/aufs3-remove-circular-includes.patch
deleted file mode 100644
index f6bea9ec2ccb..000000000000
--- a/debian/patches/features/all/aufs3/aufs3-remove-circular-includes.patch
+++ /dev/null
@@ -1,222 +0,0 @@
-From: Ian Campbell <ijc@hellion.org.uk>
-Date: Sun, 20 Jul 2014 16:13:35 +0100
-Subject: aufs3: remove include of linux/fs.h from linux/mm.h
-Forwarded: http://sourceforge.net/p/aufs/mailman/message/32628514/
-
-This include is added by aufs3-mmap.patch but causes circular dependencies on
-arm64 as seen with the Debian kernel packages in http://buildd.debian-ports.org/status/fetch.php?pkg=linux&arch=arm64&ver=3.14.12-1&stamp=1405234443 which contains:
-
-In file included from /«PKGBUILDDIR»/include/linux/mm.h:23:0,
- from /«PKGBUILDDIR»/include/linux/pid_namespace.h:6,
- from /«PKGBUILDDIR»/include/linux/ptrace.h:9,
- from /«PKGBUILDDIR»/arch/arm64/include/asm/compat.h:26,
- from /«PKGBUILDDIR»/arch/arm64/include/asm/stat.h:23,
- from /«PKGBUILDDIR»/include/linux/stat.h:5,
- from /«PKGBUILDDIR»/include/linux/module.h:10,
- from /«PKGBUILDDIR»/init/main.c:15:
-/«PKGBUILDDIR»/include/linux/fs.h:1575:64: warning: 'struct kstat' declared inside parameter list [enabled by default]
- int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
-
-According to http://article.gmane.org/gmane.linux.ports.arm.kernel/342042
-> The added mm.h->fs.h looks like a mistake, it should not be there, and we have
-> in the past worked hard to separate mm.h, sched.h and fs.h from one another.
-
-Move all of the static inline functions added to mm.h by
-aufs3-mmap.patch into a new file, mm/aufs_mmap.c, instead to avoid the
-new includes in mm.h.
-
-Signed-off-by: Ian Campbell <ijc@hellion.org.uk>
-
---- a/include/linux/mm.h
-+++ b/include/linux/mm.h
-@@ -18,9 +18,6 @@
- #include <linux/pfn.h>
- #include <linux/bit_spinlock.h>
- #include <linux/shrinker.h>
--#include <linux/dcache.h>
--#include <linux/file.h>
--#include <linux/fs.h>
-
- struct mempolicy;
- struct anon_vma;
-@@ -1187,83 +1184,17 @@ static inline int fixup_user_fault(struc
- }
- #endif
-
--/*
-- * Mainly for aufs which mmap(2) diffrent file and wants to print different path
-- * in /proc/PID/maps.
-- */
--/* #define AUFS_DEBUG_MMAP */
--static inline void aufs_trace(struct file *f, struct file *pr,
-- const char func[], int line, const char func2[])
--{
--#ifdef AUFS_DEBUG_MMAP
-- if (pr)
-- pr_info("%s:%d: %s, %p\n", func, line, func2,
-- f ? (char *)f->f_dentry->d_name.name : "(null)");
--#endif
--}
--
--static inline struct file *vmr_do_pr_or_file(struct vm_region *region,
-- const char func[], int line)
--{
-- struct file *f = region->vm_file, *pr = region->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- return (f && pr) ? pr : f;
--}
--
--static inline void vmr_do_fput(struct vm_region *region,
-- const char func[], int line)
--{
-- struct file *f = region->vm_file, *pr = region->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- fput(f);
-- if (f && pr)
-- fput(pr);
--}
--
--static inline void vma_do_file_update_time(struct vm_area_struct *vma,
-- const char func[], int line)
--{
-- struct file *f = vma->vm_file, *pr = vma->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- file_update_time(f);
-- if (f && pr)
-- file_update_time(pr);
--}
--
--static inline struct file *vma_do_pr_or_file(struct vm_area_struct *vma,
-- const char func[], int line)
--{
-- struct file *f = vma->vm_file, *pr = vma->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- return (f && pr) ? pr : f;
--}
--
--static inline void vma_do_get_file(struct vm_area_struct *vma,
-- const char func[], int line)
--{
-- struct file *f = vma->vm_file, *pr = vma->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- get_file(f);
-- if (f && pr)
-- get_file(pr);
--}
--
--static inline void vma_do_fput(struct vm_area_struct *vma,
-- const char func[], int line)
--{
-- struct file *f = vma->vm_file, *pr = vma->vm_prfile;
--
-- aufs_trace(f, pr, func, line, __func__);
-- fput(f);
-- if (f && pr)
-- fput(pr);
--}
--
-+extern struct file *vmr_do_pr_or_file(struct vm_region *region,
-+ const char func[], int line);
-+extern void vmr_do_fput(struct vm_region *region, const char func[], int line);
-+extern void vma_do_file_update_time(struct vm_area_struct *vma,
-+ const char func[], int line);
-+extern struct file *vma_do_pr_or_file(struct vm_area_struct *vma,
-+ const char func[], int line);
-+extern void vma_do_get_file(struct vm_area_struct *vma,
-+ const char func[], int line);
-+extern void vma_do_fput(struct vm_area_struct *vma, const char func[], int line);
-+
- #define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \
- __LINE__)
- #define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__)
---- a/mm/Makefile
-+++ b/mm/Makefile
-@@ -21,6 +21,7 @@ obj-y := filemap.o mempool.o oom_kill.
- iov_iter.o $(mmu-y)
-
- obj-y += init-mm.o
-+obj-y += aufs_mmap.o
-
- ifdef CONFIG_NO_BOOTMEM
- obj-y += nobootmem.o
---- /dev/null
-+++ b/mm/aufs_mmap.c
-@@ -0,0 +1,73 @@
-+#include <linux/mm.h>
-+#include <linux/file.h>
-+#include <linux/fs.h>
-+
-+/*
-+ * Mainly for aufs which mmap(2) diffrent file and wants to print different path
-+ * in /proc/PID/maps.
-+ */
-+/* #define AUFS_DEBUG_MMAP */
-+static inline void aufs_trace(struct file *f, struct file *pr,
-+ const char func[], int line, const char func2[])
-+{
-+#ifdef AUFS_DEBUG_MMAP
-+ if (pr)
-+ pr_info("%s:%d: %s, %p\n", func, line, func2,
-+ f ? (char *)f->f_dentry->d_name.name : "(null)");
-+#endif
-+}
-+
-+#ifndef CONFIG_MMU
-+struct file *vmr_do_pr_or_file(struct vm_region *region,
-+ const char func[], int line)
-+{
-+ struct file *f = region->vm_file, *pr = region->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ return (f && pr) ? pr : f;
-+}
-+
-+void vmr_do_fput(struct vm_region *region, const char func[], int line)
-+{
-+ struct file *f = region->vm_file, *pr = region->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ fput(f);
-+ if (f && pr)
-+ fput(pr);
-+}
-+#endif
-+
-+void vma_do_file_update_time(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ file_update_time(f);
-+ if (f && pr)
-+ file_update_time(pr);
-+}
-+
-+struct file *vma_do_pr_or_file(struct vm_area_struct *vma,
-+ const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ return (f && pr) ? pr : f;
-+}
-+
-+void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ get_file(f);
-+ if (f && pr)
-+ get_file(pr);
-+}
-+
-+void vma_do_fput(struct vm_area_struct *vma, const char func[], int line)
-+{
-+ struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+ aufs_trace(f, pr, func, line, __func__);
-+ fput(f);
-+ if (f && pr)
-+ fput(pr);
-+}
diff --git a/debian/patches/features/all/aufs3/aufs3-standalone.patch b/debian/patches/features/all/aufs3/aufs3-standalone.patch
index ca5d77c40691..c8ef3d05e22b 100644
--- a/debian/patches/features/all/aufs3/aufs3-standalone.patch
+++ b/debian/patches/features/all/aufs3/aufs3-standalone.patch
@@ -1,12 +1,12 @@
From: J. R. Okajima <hooanon05@yahoo.co.jp>
-Date: Fri Jun 20 09:25:26 2014 +0900
-Subject: aufs3.x-rcN standalone patch
-Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/501539c2f9478ef69fa42acfb43ef1420d9bb524/tree/
+Date: Thu Aug 7 21:42:20 2014 +0900
+Subject: aufs3.16 standalone patch
+Origin: http://sourceforge.net/p/aufs/aufs3-standalone/ci/888949daf96bf7e2b857dc38e22029513f94d4ae/tree/
Bug-Debian: https://bugs.debian.org/541828
Patch headers added by debian/patches/features/all/aufs3/gen-patch
-aufs3.x-rcN standalone patch
+aufs3.16 standalone patch
diff --git a/fs/inode.c b/fs/inode.c
index b225c0f..73259c8 100644
@@ -121,7 +121,7 @@ index d90deaa..60b4239 100644
static int fsnotify_mark_destroy(void *ignored)
{
diff --git a/fs/open.c b/fs/open.c
-index 36662d0..9a7e1e0 100644
+index d6fd3ac..5e99d8b 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -62,6 +62,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
@@ -132,7 +132,7 @@ index 36662d0..9a7e1e0 100644
long vfs_truncate(struct path *path, loff_t length)
{
-@@ -299,6 +300,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+@@ -298,6 +299,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
sb_end_write(inode->i_sb);
return ret;
}
diff --git a/debian/patches/series b/debian/patches/series
index fd4cdece800e..4a43e77a0c28 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -24,7 +24,6 @@ features/all/aufs3/aufs3-mmap.patch
features/all/aufs3/aufs3-standalone.patch
features/all/aufs3/aufs3-add.patch
# Debian-specific changes
-features/all/aufs3/aufs3-remove-circular-includes.patch
debian/aufs3-mark-as-staging.patch
# Change some defaults for security reasons