[packages/kernel] - up to 4.7.1
arekm
arekm at pld-linux.org
Wed Aug 17 18:37:51 CEST 2016
commit f0c0a0075ebbd8e5d2b07223d3e6a049d302da27
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Wed Aug 17 18:36:56 2016 +0200
- up to 4.7.1
kernel-apparmor.patch | 22 --
kernel-aufs4.patch | 817 +++++++++++++++++++++++++++++++-------------------
kernel.spec | 4 +-
3 files changed, 508 insertions(+), 335 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index b8d64dc..8b00cb0 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -70,7 +70,7 @@
%define rel 1
%define basever 4.7
-%define postver .0
+%define postver .1
# define this to '-%{basever}' for longterm branch
%define versuffix %{nil}
@@ -119,7 +119,7 @@ Source0: https://www.kernel.org/pub/linux/kernel/v4.x/linux-%{basever}.tar.xz
# Source0-md5: 5276563eb1f39a048e4a8a887408c031
%if "%{postver}" != ".0"
Patch0: https://www.kernel.org/pub/linux/kernel/v4.x/patch-%{version}.xz
-# Patch0-md5: c8ff415734155965ae7a2a85ef9c9e03
+# Patch0-md5: b87c3627d4c3e3043f46c6422dfd83b0
%endif
Source1: kernel.sysconfig
diff --git a/kernel-apparmor.patch b/kernel-apparmor.patch
index 9d10f82..399ae31 100644
--- a/kernel-apparmor.patch
+++ b/kernel-apparmor.patch
@@ -598,28 +598,6 @@ index a689f10..c841b12 100644
return 1;
}
-commit 9ad29b2e7820895339f90eb71b411d0134cf1ce9
-Author: John Johansen <john.johansen at canonical.com>
-Date: Wed Nov 18 11:41:05 2015 -0800
-
- apparmor: fix ref count leak when profile sha1 hash is read
-
- Signed-off-by: John Johansen <john.johansen at canonical.com>
- Acked-by: Seth Arnold <seth.arnold at canonical.com>
-
-diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
-index 45a6199..0d8dd71 100644
---- a/security/apparmor/apparmorfs.c
-+++ b/security/apparmor/apparmorfs.c
-@@ -331,6 +331,7 @@ static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
- seq_printf(seq, "%.2x", profile->hash[i]);
- seq_puts(seq, "\n");
- }
-+ aa_put_profile(profile);
-
- return 0;
- }
-
commit e13f968d154ba9d6a2c4f82f33d3312a63430b54
Author: John Johansen <john.johansen at canonical.com>
Date: Wed Dec 16 18:09:10 2015 -0800
diff --git a/kernel-aufs4.patch b/kernel-aufs4.patch
index 64ad03c..80c6bbf 100644
--- a/kernel-aufs4.patch
+++ b/kernel-aufs4.patch
@@ -1,4 +1,4 @@
-aufs4.x-rcN kbuild patch
+aufs4.7 kbuild patch
diff --git a/fs/Kconfig b/fs/Kconfig
index b8fcb41..78adefb 100644
@@ -22,7 +22,7 @@ index 85b6e13..e7bb164 100644
obj-$(CONFIG_EFIVAR_FS) += efivarfs/
+obj-$(CONFIG_AUFS_FS) += aufs/
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
-index 8bdae34..65dbd5f 100644
+index ec10cfe..800211b 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -59,6 +59,7 @@ header-y += atmsvc.h
@@ -33,13 +33,13 @@ index 8bdae34..65dbd5f 100644
header-y += auto_fs4.h
header-y += auto_fs.h
header-y += auxvec.h
-aufs4.x-rcN base patch
+aufs4.7 base patch
diff --git a/MAINTAINERS b/MAINTAINERS
-index 952fd2a..6a8f0f8 100644
+index 8c20323..d170184 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -2210,6 +2210,19 @@ F: include/linux/audit.h
+@@ -2213,6 +2213,19 @@ F: include/linux/audit.h
F: include/uapi/linux/audit.h
F: kernel/audit*
@@ -265,7 +265,7 @@ index da2751d..2e0fca6 100644
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags);
#endif
-aufs4.x-rcN mmap patch
+aufs4.7 mmap patch
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a11eb71..8f10865 100644
@@ -430,7 +430,7 @@ index 20f3b1f..ee827ce 100644
if (page->mapping != inode->i_mapping) {
unlock_page(page);
diff --git a/mm/memory.c b/mm/memory.c
-index cd1f29e..f0c204c 100644
+index 9e04681..06980d1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2100,7 +2100,7 @@ static inline int wp_page_reuse(struct mm_struct *mm,
@@ -675,7 +675,7 @@ index 0000000..b323b8a
+ fput(pr);
+}
+#endif /* !CONFIG_MMU */
-aufs4.x-rcN standalone patch
+aufs4.7 standalone patch
diff --git a/fs/dcache.c b/fs/dcache.c
index c3c0b6d..c99d2d2 100644
@@ -762,7 +762,7 @@ index aa6d071..f336032 100644
/**
* touch_atime - update the access time
diff --git a/fs/namespace.c b/fs/namespace.c
-index 783004a..44abb2d 100644
+index 419f746..9c0e0af 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -463,6 +463,7 @@ void __mnt_drop_write(struct vfsmount *mnt)
@@ -773,7 +773,7 @@ index 783004a..44abb2d 100644
/**
* mnt_drop_write - give up write access to a mount
-@@ -1811,6 +1812,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
+@@ -1812,6 +1813,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
}
return 0;
}
@@ -2864,8 +2864,8 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h
+#endif /* __AUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
--- /usr/share/empty/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/branch.c 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,1406 @@
++++ linux/fs/aufs/branch.c 2016-08-17 18:01:06.095221547 +0200
+@@ -0,0 +1,1409 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -2919,7 +2919,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+
+ if (br->br_fhsm) {
+ au_br_fhsm_fin(br->br_fhsm);
-+ kfree(br->br_fhsm);
++ au_delayed_kfree(br->br_fhsm);
+ }
+
+ key = br->br_dykey;
@@ -2933,8 +2933,9 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ lockdep_off();
+ path_put(&br->br_path);
+ lockdep_on();
-+ kfree(wbr);
-+ kfree(br);
++ if (wbr)
++ au_delayed_kfree(wbr);
++ au_delayed_kfree(br);
+}
+
+/*
@@ -3032,11 +3033,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ return add_branch; /* success */
+
+out_wbr:
-+ kfree(add_branch->br_wbr);
++ if (add_branch->br_wbr)
++ au_delayed_kfree(add_branch->br_wbr);
+out_hnotify:
+ au_hnotify_fin_br(add_branch);
+out_br:
-+ kfree(add_branch);
++ au_delayed_kfree(add_branch);
+out:
+ return ERR_PTR(err);
+}
@@ -3202,7 +3204,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ br->br_perm = old_perm;
+
+ if (!err && wbr && !au_br_writable(new_perm)) {
-+ kfree(wbr);
++ au_delayed_kfree(wbr);
+ br->br_wbr = NULL;
+ }
+
@@ -4225,7 +4227,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ if (br->br_wbr) {
+ err = au_wbr_init(br, sb, mod->perm);
+ if (unlikely(err)) {
-+ kfree(br->br_wbr);
++ au_delayed_kfree(br->br_wbr);
+ br->br_wbr = NULL;
+ }
+ }
@@ -4237,7 +4239,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ if (!au_br_fhsm(mod->perm)) {
+ /* fhsm --> non-fhsm */
+ au_br_fhsm_fin(br->br_fhsm);
-+ kfree(br->br_fhsm);
++ au_delayed_kfree(br->br_fhsm);
+ br->br_fhsm = NULL;
+ }
+ } else if (au_br_fhsm(mod->perm))
@@ -4249,7 +4251,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
+ goto out; /* success */
+
+out_bf:
-+ kfree(bf);
++ if (bf)
++ au_delayed_kfree(bf);
+out:
+ AuTraceErr(err);
+ return err;
@@ -4629,7 +4632,7 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk
+-include ${srctree}/${src}/conf_priv.mk
diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
--- /usr/share/empty/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/cpup.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/cpup.c 2016-08-17 18:01:06.095221547 +0200
@@ -0,0 +1,1383 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -4990,9 +4993,9 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
+ dst->f_pos = 0;
+ err = au_do_copy_file(dst, src, len, buf, blksize);
+ if (do_kfree)
-+ kfree(buf);
++ au_delayed_kfree(buf);
+ else
-+ free_page((unsigned long)buf);
++ au_delayed_free_page((unsigned long)buf);
+
+out:
+ return err;
@@ -5152,7 +5155,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
+ sym.k[symlen] = 0;
+ err = vfsub_symlink(h_dir, h_path, sym.k);
+ }
-+ free_page((unsigned long)sym.k);
++ au_delayed_free_page((unsigned long)sym.k);
+
+out:
+ return err;
@@ -5523,7 +5526,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
+ }
+out_parent:
+ dput(dst_parent);
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ return err;
+}
@@ -6114,8 +6117,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
+#endif /* __AUFS_CPUP_H__ */
diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
--- /usr/share/empty/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dbgaufs.c 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,432 @@
++++ linux/fs/aufs/dbgaufs.c 2016-08-17 18:01:06.095221547 +0200
+@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -6159,7 +6162,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
+static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
+ struct file *file)
+{
-+ kfree(file->private_data);
++ au_delayed_kfree(file->private_data);
+ return 0;
+}
+
@@ -6221,7 +6224,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
+static int dbgaufs_plink_release(struct inode *inode __maybe_unused,
+ struct file *file)
+{
-+ free_page((unsigned long)file->private_data);
++ au_delayed_free_page((unsigned long)file->private_data);
+ return 0;
+}
+
@@ -6285,7 +6288,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
+ goto out; /* success */
+
+out_free:
-+ free_page((unsigned long)p);
++ au_delayed_free_page((unsigned long)p);
+out:
+ return err;
+}
@@ -6412,8 +6415,11 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
+ br = au_sbr(sb, bindex);
+ xi = &br->br_xino;
+ AuDebugOn(xi->xi_dbgaufs);
++ /* debugfs acquires the parent i_mutex */
++ lockdep_off();
+ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
+ sbinfo, &dbgaufs_xino_fop);
++ lockdep_on();
+ /* ignore an error */
+ if (unlikely(!xi->xi_dbgaufs))
+ AuWarn1("failed %s under debugfs\n", name);
@@ -6602,7 +6608,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h
+#endif /* __DBGAUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
--- /usr/share/empty/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dcsub.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/dcsub.c 2016-08-17 18:01:06.101888388 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -6635,7 +6641,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
+ p = dpage->dentries;
+ for (i = 0; i < dpage->ndentry; i++)
+ dput(*p++);
-+ free_page((unsigned long)dpage->dentries);
++ au_delayed_free_page((unsigned long)dpage->dentries);
+}
+
+int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
@@ -6658,7 +6664,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
+ return 0; /* success */
+
+out_dpages:
-+ kfree(dpages->dpages);
++ au_delayed_kfree(dpages->dpages);
+out:
+ return err;
+}
@@ -6671,7 +6677,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
+ p = dpages->dpages;
+ for (i = 0; i < dpages->ndpage; i++)
+ au_dpage_free(p++);
-+ kfree(dpages->dpages);
++ au_delayed_kfree(dpages->dpages);
+}
+
+static int au_dpages_append(struct au_dcsub_pages *dpages,
@@ -6970,8 +6976,8 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
+#endif /* __AUFS_DCSUB_H__ */
diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
--- /usr/share/empty/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/debug.c 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,441 @@
++++ linux/fs/aufs/debug.c 2016-08-17 18:01:06.101888388 +0200
+@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -7310,7 +7316,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
+ au_br_count_init(&a->fake);
+ err = do_pri_br(-1, &a->fake);
+ au_br_count_fin(&a->fake);
-+ kfree(a);
++ au_delayed_kfree(a);
+ dpri("dev 0x%x\n", sb->s_dev);
+ if (err || !au_test_aufs(sb))
+ return;
@@ -7318,9 +7324,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c
+ sbinfo = au_sbi(sb);
+ if (!sbinfo)
+ return;
-+ dpri("nw %lld, gen %u, kobj %d\n",
-+ percpu_counter_sum(&sbinfo->si_nowait.nw_len),
-+ sbinfo->si_generation,
++ dpri("nw %d, gen %u, kobj %d\n",
++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation,
+ atomic_read(&sbinfo->si_kobj.kref.refcount));
+ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++)
+ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]);
@@ -7644,7 +7649,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
+#endif /* __AUFS_DEBUG_H__ */
diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
--- /usr/share/empty/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/dentry.c 2016-08-17 18:01:06.111888648 +0200
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -7862,7 +7867,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
+
+out_parent:
+ dput(parent);
-+ kfree(whname.name);
++ au_delayed_kfree(whname.name);
+out:
+ return err;
+}
@@ -8776,8 +8781,8 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
+};
diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
--- /usr/share/empty/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.h 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,252 @@
++++ linux/fs/aufs/dentry.h 2016-08-17 18:01:06.111888648 +0200
+@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -8818,7 +8823,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
+ struct au_rwsem di_rwsem;
+ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq;
+ unsigned char di_tmpfile; /* to allow the different name */
-+ struct au_hdentry *di_hdentry;
++ union {
++ struct au_hdentry *di_hdentry;
++ struct llist_node di_lnode; /* delayed free */
++ };
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
@@ -9032,7 +9040,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
+#endif /* __AUFS_DENTRY_H__ */
diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
--- /usr/share/empty/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dinfo.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/dinfo.c 2016-08-17 18:01:06.111888648 +0200
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -9089,7 +9097,7 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
+ goto out;
+ }
+
-+ au_cache_free_dinfo(dinfo);
++ au_cache_dfree_dinfo(dinfo);
+ dinfo = NULL;
+
+out:
@@ -9109,8 +9117,8 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
+ while (bindex++ <= bbot)
+ au_hdput(p++);
+ }
-+ kfree(dinfo->di_hdentry);
-+ au_cache_free_dinfo(dinfo);
++ au_delayed_kfree(dinfo->di_hdentry);
++ au_cache_dfree_dinfo(dinfo);
+}
+
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
@@ -9588,8 +9596,8 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c
+}
diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
--- /usr/share/empty/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dir.c 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,756 @@
++++ linux/fs/aufs/dir.c 2016-08-17 18:01:06.111888648 +0200
+@@ -0,0 +1,762 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -9748,7 +9756,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+out:
+ dput(a->dentry);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
-+ kfree(arg);
++ au_delayed_kfree(arg);
+}
+
+void au_dir_ts(struct inode *dir, aufs_bindex_t bindex)
@@ -9784,7 +9792,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+ if (unlikely(wkq_err)) {
+ pr_err("wkq %d\n", wkq_err);
+ dput(dentry);
-+ kfree(arg);
++ au_delayed_kfree(arg);
+ }
+
+out:
@@ -9903,7 +9911,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+ };
+ err = au_do_open(file, &args);
+ if (unlikely(err))
-+ kfree(fidir);
++ au_delayed_kfree(fidir);
+ }
+ si_read_unlock(sb);
+ return err;
@@ -9915,8 +9923,11 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+ struct au_vdir *vdir_cache;
+ struct au_finfo *finfo;
+ struct au_fidir *fidir;
++ struct au_hfile *hf;
+ aufs_bindex_t bindex, bbot;
++ int execed, delayed;
+
++ delayed = (current->flags & PF_KTHREAD) || in_interrupt();
+ finfo = au_fi(file);
+ fidir = finfo->fi_hdir;
+ if (fidir) {
@@ -9924,22 +9935,25 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+ &au_sbi(file->f_path.dentry->d_sb)->si_files);
+ vdir_cache = fidir->fd_vdir_cache; /* lock-free */
+ if (vdir_cache)
-+ au_vdir_free(vdir_cache);
++ au_vdir_free(vdir_cache, delayed);
+
+ bindex = finfo->fi_btop;
+ if (bindex >= 0) {
++ execed = vfsub_file_execed(file);
++ hf = fidir->fd_hfile + bindex;
+ /*
+ * calls fput() instead of filp_close(),
+ * since no dnotify or lock for the lower file.
+ */
+ bbot = fidir->fd_bbot;
-+ for (; bindex <= bbot; bindex++)
-+ au_set_h_fptr(file, bindex, NULL);
++ for (; bindex <= bbot; bindex++, hf++)
++ if (hf->hf_file)
++ au_hfput(hf, execed);
+ }
-+ kfree(fidir);
++ au_delayed_kfree(fidir);
+ finfo->fi_hdir = NULL;
+ }
-+ au_finfo_fin(file);
++ au_finfo_fin(file, delayed);
+ return 0;
+}
+
@@ -10348,8 +10362,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c
+};
diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
--- /usr/share/empty/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dir.h 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,131 @@
++++ linux/fs/aufs/dir.h 2016-08-17 18:01:06.111888648 +0200
+@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -10394,7 +10408,10 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
+
+struct au_vdir_dehstr {
+ struct hlist_node hash;
-+ struct au_vdir_destr *str;
++ union {
++ struct au_vdir_destr *str;
++ struct llist_node lnode; /* delayed free */
++ };
+} ____cacheline_aligned_in_smp;
+
+struct au_vdir_de {
@@ -10432,7 +10449,10 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
+
+ unsigned long vd_version;
+ unsigned int vd_deblk_sz;
-+ unsigned long vd_jiffy;
++ union {
++ unsigned long vd_jiffy;
++ struct llist_node vd_lnode; /* delayed free */
++ };
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
@@ -10456,7 +10476,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
+int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
+ unsigned int d_type, aufs_bindex_t bindex,
+ unsigned char shwh);
-+void au_vdir_free(struct au_vdir *vdir);
++void au_vdir_free(struct au_vdir *vdir, int atonce);
+int au_vdir_init(struct file *file);
+int au_vdir_fill_de(struct file *file, struct dir_context *ctx);
+
@@ -10483,7 +10503,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
+#endif /* __AUFS_DIR_H__ */
diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
--- /usr/share/empty/fs/aufs/dynop.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dynop.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/dynop.c 2016-08-17 18:01:21.295617591 +0200
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2010-2016 Junjiro R. Okajima
@@ -10514,17 +10534,17 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+ * How large will these lists be?
+ * Usually just a few elements, 20-30 at most for each, I guess.
+ */
-+static struct au_splhead dynop[AuDyLast];
++static struct au_sphlhead dynop[AuDyLast];
+
-+static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op)
++static struct au_dykey *dy_gfind_get(struct au_sphlhead *sphl, const void *h_op)
+{
+ struct au_dykey *key, *tmp;
-+ struct list_head *head;
++ struct hlist_head *head;
+
+ key = NULL;
-+ head = &spl->head;
++ head = &sphl->head;
+ rcu_read_lock();
-+ list_for_each_entry_rcu(tmp, head, dk_list)
++ hlist_for_each_entry_rcu(tmp, head, dk_hnode)
+ if (tmp->dk_op.dy_hop == h_op) {
+ key = tmp;
+ kref_get(&key->dk_kref);
@@ -10571,24 +10591,24 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+}
+
+/* kref_get() if @key is already added */
-+static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key)
++static struct au_dykey *dy_gadd(struct au_sphlhead *sphl, struct au_dykey *key)
+{
+ struct au_dykey *tmp, *found;
-+ struct list_head *head;
++ struct hlist_head *head;
+ const void *h_op = key->dk_op.dy_hop;
+
+ found = NULL;
-+ head = &spl->head;
-+ spin_lock(&spl->spin);
-+ list_for_each_entry(tmp, head, dk_list)
++ head = &sphl->head;
++ spin_lock(&sphl->spin);
++ hlist_for_each_entry(tmp, head, dk_hnode)
+ if (tmp->dk_op.dy_hop == h_op) {
+ kref_get(&tmp->dk_kref);
+ found = tmp;
+ break;
+ }
+ if (!found)
-+ list_add_rcu(&key->dk_list, head);
-+ spin_unlock(&spl->spin);
++ hlist_add_head_rcu(&key->dk_hnode, head);
++ spin_unlock(&sphl->spin);
+
+ if (!found)
+ DyPrSym(key);
@@ -10601,17 +10621,17 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+
+ key = container_of(rcu, struct au_dykey, dk_rcu);
+ DyPrSym(key);
-+ kfree(key);
++ kfree(key); /* not delayed */
+}
+
+static void dy_free(struct kref *kref)
+{
+ struct au_dykey *key;
-+ struct au_splhead *spl;
++ struct au_sphlhead *sphl;
+
+ key = container_of(kref, struct au_dykey, dk_kref);
-+ spl = dynop + key->dk_op.dy_type;
-+ au_spl_del_rcu(&key->dk_list, spl);
++ sphl = dynop + key->dk_op.dy_type;
++ au_sphl_del_rcu(&key->dk_hnode, sphl);
+ call_rcu(&key->dk_rcu, dy_free_rcu);
+}
+
@@ -10696,7 +10716,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br)
+{
+ struct au_dykey *key, *old;
-+ struct au_splhead *spl;
++ struct au_sphlhead *sphl;
+ struct op {
+ unsigned int sz;
+ void (*set)(struct au_dykey *key, const void *h_op,
@@ -10710,8 +10730,8 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+ };
+ const struct op *p;
+
-+ spl = dynop + op->dy_type;
-+ key = dy_gfind_get(spl, op->dy_hop);
++ sphl = dynop + op->dy_type;
++ key = dy_gfind_get(sphl, op->dy_hop);
+ if (key)
+ goto out_add; /* success */
+
@@ -10725,9 +10745,9 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+ key->dk_op.dy_hop = op->dy_hop;
+ kref_init(&key->dk_kref);
+ p->set(key, op->dy_hop, au_br_sb(br));
-+ old = dy_gadd(spl, key);
++ old = dy_gadd(sphl, key);
+ if (old) {
-+ kfree(key);
++ au_delayed_kfree(key);
+ key = old;
+ }
+
@@ -10822,16 +10842,16 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+
+void au_dy_arefresh(int do_dx)
+{
-+ struct au_splhead *spl;
-+ struct list_head *head;
++ struct au_sphlhead *sphl;
++ struct hlist_head *head;
+ struct au_dykey *key;
+
-+ spl = dynop + AuDy_AOP;
-+ head = &spl->head;
-+ spin_lock(&spl->spin);
-+ list_for_each_entry(key, head, dk_list)
++ sphl = dynop + AuDy_AOP;
++ head = &sphl->head;
++ spin_lock(&sphl->spin);
++ hlist_for_each_entry(key, head, dk_hnode)
+ dy_adx((void *)key, do_dx);
-+ spin_unlock(&spl->spin);
++ spin_unlock(&sphl->spin);
+}
+
+/* ---------------------------------------------------------------------- */
@@ -10844,7 +10864,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key));
+
+ for (i = 0; i < AuDyLast; i++)
-+ au_spl_init(dynop + i);
++ au_sphl_init(dynop + i);
+}
+
+void au_dy_fin(void)
@@ -10852,11 +10872,11 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
+ int i;
+
+ for (i = 0; i < AuDyLast; i++)
-+ WARN_ON(!list_empty(&dynop[i].head));
++ WARN_ON(!hlist_empty(&dynop[i].head));
+}
diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
--- /usr/share/empty/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dynop.h 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/dynop.h 2016-08-17 18:01:06.118555489 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010-2016 Junjiro R. Okajima
@@ -10899,7 +10919,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
+
+struct au_dykey {
+ union {
-+ struct list_head dk_list;
++ struct hlist_node dk_hnode;
+ struct rcu_head dk_rcu;
+ };
+ struct au_dynop dk_op;
@@ -10934,7 +10954,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
+#endif /* __AUFS_DYNOP_H__ */
diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
--- /usr/share/empty/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/export.c 2016-07-25 19:05:34.811159821 +0200
++++ linux/fs/aufs/export.c 2016-08-17 18:01:06.128555749 +0200
@@ -0,0 +1,837 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -11355,7 +11375,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
+ }
+
+out_name:
-+ free_page((unsigned long)arg.name);
++ au_delayed_free_page((unsigned long)arg.name);
+out_file:
+ fput(file);
+out:
@@ -11509,7 +11529,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
+ dentry = ERR_PTR(-ESTALE);
+ }
+out_pathname:
-+ free_page((unsigned long)pathname);
++ au_delayed_free_page((unsigned long)pathname);
+out_h_parent:
+ dput(h_parent);
+out:
@@ -12205,8 +12225,8 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
+}
diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
--- /usr/share/empty/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,843 @@
++++ linux/fs/aufs/file.c 2016-08-17 18:01:21.295617591 +0200
+@@ -0,0 +1,845 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -12482,7 +12502,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+ }
+ if (unlikely(err)) {
+ finfo->fi_hdir = NULL;
-+ au_finfo_fin(file);
++ au_finfo_fin(file, /*atonce*/0);
+ }
+
+out:
@@ -12802,6 +12822,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+
+static void au_do_refresh_dir(struct file *file)
+{
++ int execed;
+ aufs_bindex_t bindex, bbot, new_bindex, brid;
+ struct au_hfile *p, tmp, *q;
+ struct au_finfo *finfo;
@@ -12840,6 +12861,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+ }
+ }
+
++ execed = vfsub_file_execed(file);
+ p = fidir->fd_hfile;
+ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) {
+ bbot = au_sbbot(sb);
@@ -12848,14 +12870,14 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+ if (p->hf_file) {
+ if (file_inode(p->hf_file))
+ break;
-+ au_hfput(p, file);
++ au_hfput(p, execed);
+ }
+ } else {
+ bbot = au_br_index(sb, brid);
+ for (finfo->fi_btop = 0; finfo->fi_btop < bbot;
+ finfo->fi_btop++, p++)
+ if (p->hf_file)
-+ au_hfput(p, file);
++ au_hfput(p, execed);
+ bbot = au_sbbot(sb);
+ }
+
@@ -12865,7 +12887,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+ if (p->hf_file) {
+ if (file_inode(p->hf_file))
+ break;
-+ au_hfput(p, file);
++ au_hfput(p, execed);
+ }
+ AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
+}
@@ -13052,8 +13074,8 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
+};
diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
--- /usr/share/empty/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.h 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,291 @@
++++ linux/fs/aufs/file.h 2016-08-17 18:01:06.135222590 +0200
+@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -13119,7 +13141,10 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
+ struct au_fidir *fi_hdir; /* for dir only */
+
+ struct hlist_node fi_hlist;
-+ struct file *fi_file; /* very ugly */
++ union {
++ struct file *fi_file; /* very ugly */
++ struct llist_node fi_lnode; /* delayed free */
++ };
+} ____cacheline_aligned_in_smp;
+
+/* ---------------------------------------------------------------------- */
@@ -13170,7 +13195,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
+struct file *au_read_pre(struct file *file, int keep_fi);
+
+/* finfo.c */
-+void au_hfput(struct au_hfile *hf, struct file *file);
++void au_hfput(struct au_hfile *hf, int execed);
+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
+ struct file *h_file);
+
@@ -13179,7 +13204,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
+int au_fidir_realloc(struct au_finfo *finfo, int nbr);
+
+void au_fi_init_once(void *_fi);
-+void au_finfo_fin(struct file *file);
++void au_finfo_fin(struct file *file, int atonce);
+int au_finfo_init(struct file *file, struct au_fidir *fidir);
+
+/* ioctl.c */
@@ -13347,8 +13372,8 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
+#endif /* __AUFS_FILE_H__ */
diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
--- /usr/share/empty/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/finfo.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,149 @@
++++ linux/fs/aufs/finfo.c 2016-08-17 18:01:06.135222590 +0200
+@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -13372,10 +13397,9 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
+
+#include "aufs.h"
+
-+void au_hfput(struct au_hfile *hf, struct file *file)
++void au_hfput(struct au_hfile *hf, int execed)
+{
-+ /* todo: direct access f_flags */
-+ if (vfsub_file_flags(file) & __FMODE_EXEC)
++ if (execed)
+ allow_write_access(hf->hf_file);
+ fput(hf->hf_file);
+ hf->hf_file = NULL;
@@ -13397,7 +13421,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
+ hf = fidir->fd_hfile + bindex;
+
+ if (hf && hf->hf_file)
-+ au_hfput(hf, file);
++ au_hfput(hf, vfsub_file_execed(file));
+ if (val) {
+ FiMustWriteLock(file);
+ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry));
@@ -13454,7 +13478,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
+
+/* ---------------------------------------------------------------------- */
+
-+void au_finfo_fin(struct file *file)
++void au_finfo_fin(struct file *file, int atonce)
+{
+ struct au_finfo *finfo;
+
@@ -13463,7 +13487,10 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
+ finfo = au_fi(file);
+ AuDebugOn(finfo->fi_hdir);
+ AuRwDestroy(&finfo->fi_rwsem);
-+ au_cache_free_finfo(finfo);
++ if (!atonce)
++ au_cache_dfree_finfo(finfo);
++ else
++ au_cache_free_finfo(finfo);
+}
+
+void au_fi_init_once(void *_finfo)
@@ -13500,8 +13527,8 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
+}
diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
--- /usr/share/empty/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/f_op.c 2016-07-25 19:05:34.811159821 +0200
-@@ -0,0 +1,770 @@
++++ linux/fs/aufs/f_op.c 2016-08-17 18:01:06.135222590 +0200
+@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -13603,6 +13630,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
+{
+ struct au_finfo *finfo;
+ aufs_bindex_t bindex;
++ int delayed;
+
+ finfo = au_fi(file);
+ au_sphl_del(&finfo->fi_hlist,
@@ -13611,7 +13639,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
+ if (bindex >= 0)
+ au_set_h_fptr(file, bindex, NULL);
+
-+ au_finfo_fin(file);
++ delayed = (current->flags & PF_KTHREAD) || in_interrupt();
++ au_finfo_fin(file, delayed);
+ return 0;
+}
+
@@ -14274,7 +14303,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
+};
diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
--- /usr/share/empty/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/fstype.h 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/fstype.h 2016-08-17 18:01:06.145222850 +0200
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -14319,7 +14348,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_iso9660(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE)
++#if IS_ENABLED(CONFIG_ISO9660_FS)
+ return sb->s_magic == ISOFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14328,7 +14357,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_romfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_ROMFS_FS)
+ return sb->s_magic == ROMFS_MAGIC;
+#else
+ return 0;
@@ -14337,7 +14366,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_cramfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE)
++#if IS_ENABLED(CONFIG_CRAMFS)
+ return sb->s_magic == CRAMFS_MAGIC;
+#endif
+ return 0;
@@ -14345,7 +14374,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_nfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_NFS_FS)
+ return sb->s_magic == NFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14354,7 +14383,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_fuse(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE)
++#if IS_ENABLED(CONFIG_FUSE_FS)
+ return sb->s_magic == FUSE_SUPER_MAGIC;
+#else
+ return 0;
@@ -14363,7 +14392,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_xfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_XFS_FS)
+ return sb->s_magic == XFS_SB_MAGIC;
+#else
+ return 0;
@@ -14381,7 +14410,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE)
++#if IS_ENABLED(CONFIG_ECRYPT_FS)
+ return !strcmp(au_sbtype(sb), "ecryptfs");
+#else
+ return 0;
@@ -14395,7 +14424,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_ubifs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_UBIFS_FS)
+ return sb->s_magic == UBIFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14422,7 +14451,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_configfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_CONFIGFS_FS)
+ return sb->s_magic == CONFIGFS_MAGIC;
+#else
+ return 0;
@@ -14431,7 +14460,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_minix(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE)
++#if IS_ENABLED(CONFIG_MINIX_FS)
+ return sb->s_magic == MINIX3_SUPER_MAGIC
+ || sb->s_magic == MINIX2_SUPER_MAGIC
+ || sb->s_magic == MINIX2_SUPER_MAGIC2
@@ -14444,7 +14473,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_fat(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE)
++#if IS_ENABLED(CONFIG_FAT_FS)
+ return sb->s_magic == MSDOS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14472,7 +14501,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_squashfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE)
++#if IS_ENABLED(CONFIG_SQUASHFS)
+ return sb->s_magic == SQUASHFS_MAGIC;
+#else
+ return 0;
@@ -14481,7 +14510,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_btrfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE)
++#if IS_ENABLED(CONFIG_BTRFS_FS)
+ return sb->s_magic == BTRFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14490,7 +14519,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_xenfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE)
++#if IS_ENABLED(CONFIG_XENFS)
+ return sb->s_magic == XENFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14508,7 +14537,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_nilfs(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE)
++#if IS_ENABLED(CONFIG_NILFS)
+ return sb->s_magic == NILFS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14517,7 +14546,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+
+static inline int au_test_hfsplus(struct super_block *sb __maybe_unused)
+{
-+#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE)
++#if IS_ENABLED(CONFIG_HFSPLUS_FS)
+ return sb->s_magic == HFSPLUS_SUPER_MAGIC;
+#else
+ return 0;
@@ -14678,7 +14707,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h
+#endif /* __AUFS_FSTYPE_H__ */
diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
--- /usr/share/empty/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hfsnotify.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/hfsnotify.c 2016-08-17 18:01:06.145222850 +0200
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -14714,7 +14743,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
+ struct au_hnotify *hn = container_of(mark, struct au_hnotify,
+ hn_mark);
+ /* AuDbg("here\n"); */
-+ au_cache_free_hnotify(hn);
++ au_cache_dfree_hnotify(hn);
+ smp_mb__before_atomic();
+ if (atomic64_dec_and_test(&au_hfsn_ifree))
+ wake_up(&au_hfsn_wq);
@@ -14838,7 +14867,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
+ struct au_br_hfsnotify *hfsn = group->private;
+
+ /* AuDbg("here\n"); */
-+ kfree(hfsn);
++ au_delayed_kfree(hfsn);
+}
+
+static int au_hfsn_handle_event(struct fsnotify_group *group,
@@ -14932,7 +14961,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c
+ goto out; /* success */
+
+out_hfsn:
-+ kfree(hfsn);
++ au_delayed_kfree(hfsn);
+out:
+ return err;
+}
@@ -15029,8 +15058,8 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c
+}
diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
--- /usr/share/empty/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hnotify.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,710 @@
++++ linux/fs/aufs/hnotify.c 2016-08-17 18:01:06.148556271 +0200
+@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -15068,7 +15097,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+ AuTraceErr(err);
+ if (unlikely(err)) {
+ hinode->hi_notify = NULL;
-+ au_cache_free_hnotify(hn);
++ au_cache_dfree_hnotify(hn);
+ /*
+ * The upper dir was removed by udba, but the same named
+ * dir left. In this case, aufs assignes a new inode
@@ -15092,7 +15121,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+ if (hn) {
+ hinode->hi_notify = NULL;
+ if (au_hnotify_op.free(hinode, hn))
-+ au_cache_free_hnotify(hn);
++ au_cache_dfree_hnotify(hn);
+ }
+}
+
@@ -15526,7 +15555,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
+ inode = lookup_wlock_by_ino(sb, bfound, h_ino);
+ try_iput = 1;
-+ }
++ }
+
+ args.flags = a->flags[AuHn_CHILD];
+ args.dentry = dentry;
@@ -15565,7 +15594,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+ iput(a->dir);
+ si_write_unlock(sb);
+ au_nwt_done(&sbinfo->si_nowait);
-+ kfree(a);
++ au_delayed_kfree(a);
+}
+
+/* ---------------------------------------------------------------------- */
@@ -15671,7 +15700,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+ iput(args->h_child_inode);
+ iput(args->h_dir);
+ iput(args->dir);
-+ kfree(args);
++ au_delayed_kfree(args);
+ }
+
+out:
@@ -15712,17 +15741,26 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+
+static void au_hn_destroy_cache(void)
+{
-+ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
-+ au_cachep[AuCache_HNOTIFY] = NULL;
++ struct au_cache *cp;
++
++ flush_delayed_work(&au_dfree.dwork);
++ cp = au_dfree.cache + AuCache_HNOTIFY;
++ AuDebugOn(!llist_empty(&cp->llist));
++ kmem_cache_destroy(cp->cache);
++ cp->cache = NULL;
+}
+
++AU_CACHE_DFREE_FUNC(hnotify, HNOTIFY, hn_lnode);
++
+int __init au_hnotify_init(void)
+{
+ int err;
++ struct au_cache *cp;
+
+ err = -ENOMEM;
-+ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
-+ if (au_cachep[AuCache_HNOTIFY]) {
++ cp = au_dfree.cache + AuCache_HNOTIFY;
++ cp->cache = AuCache(au_hnotify);
++ if (cp->cache) {
+ err = 0;
+ if (au_hnotify_op.init)
+ err = au_hnotify_op.init();
@@ -15735,15 +15773,19 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
+
+void au_hnotify_fin(void)
+{
++ struct au_cache *cp;
++
+ if (au_hnotify_op.fin)
+ au_hnotify_op.fin();
++
+ /* cf. au_cache_fin() */
-+ if (au_cachep[AuCache_HNOTIFY])
++ cp = au_dfree.cache + AuCache_HNOTIFY;
++ if (cp->cache)
+ au_hn_destroy_cache();
+}
diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
--- /usr/share/empty/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/iinfo.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/iinfo.c 2016-08-17 18:01:06.148556271 +0200
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -16014,7 +16056,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
+
+ iinfo = au_ii(inode);
+ if (iinfo->ii_vdir)
-+ au_vdir_free(iinfo->ii_vdir);
++ au_vdir_free(iinfo->ii_vdir, /*atonce*/0);
+
+ bindex = iinfo->ii_btop;
+ if (bindex >= 0) {
@@ -16026,7 +16068,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
+ hi++;
+ }
+ }
-+ kfree(iinfo->ii_hinode);
++ au_delayed_kfree(iinfo->ii_hinode);
+ AuRwDestroy(&iinfo->ii_rwsem);
+}
diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
@@ -16552,8 +16594,8 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
+}
diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
--- /usr/share/empty/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/inode.h 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,694 @@
++++ linux/fs/aufs/inode.h 2016-08-17 18:01:06.151889691 +0200
+@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -16591,7 +16633,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
+ /* never use fsnotify_add_vfsmount_mark() */
+ struct fsnotify_mark hn_mark;
+#endif
-+ struct inode *hn_aufs_inode; /* no get/put */
++ union {
++ struct inode *hn_aufs_inode; /* no get/put */
++ struct llist_node hn_lnode; /* delayed free */
++ };
+#endif
+} ____cacheline_aligned_in_smp;
+
@@ -16634,7 +16679,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
+struct au_icntnr {
+ struct au_iinfo iinfo;
+ struct inode vfs_inode;
-+ struct hlist_node plink;
++ union {
++ struct hlist_node plink;
++ struct llist_node lnode; /* delayed free */
++ };
+} ____cacheline_aligned_in_smp;
+
+/* au_pin flags */
@@ -17473,7 +17521,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
+#endif
diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
--- /usr/share/empty/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_add.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/i_op_add.c 2016-08-17 18:01:06.148556271 +0200
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -17822,7 +17870,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
+ if (!try_aopen)
+ aufs_read_unlock(dentry, AuLock_DW);
+out_free:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ return err;
+}
@@ -18286,7 +18334,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
+ }
+ aufs_read_and_write_unlock2(dentry, src_dentry);
+out_kfree:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ AuTraceErr(err);
+ return err;
@@ -18395,14 +18443,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
+ }
+ aufs_read_unlock(dentry, AuLock_DW);
+out_free:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
--- /usr/share/empty/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,1414 @@
++++ linux/fs/aufs/i_op.c 2016-08-17 18:01:06.148556271 +0200
+@@ -0,0 +1,1413 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -18686,8 +18734,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
+{
+ int err, h_opened = *opened;
+ unsigned int lkup_flags;
-+ struct dentry *parent;
-+ struct dentry *d;
++ struct dentry *parent, *d;
+ struct au_sphlhead *aopen;
+ struct vfsub_aopen_args args = {
+ .open_flag = open_flag,
@@ -18782,10 +18829,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
+ di_write_unlock(parent);
+ aufs_read_unlock(dentry, AuLock_DW);
+ AuDbgDentry(dentry);
-+ if (unlikely(err))
++ if (unlikely(err < 0))
+ goto out;
+out_no_open:
-+ if (!err && !(*opened & FILE_CREATED)) {
++ if (err >= 0 && !(*opened & FILE_CREATED)) {
+ AuLabel(out_no_open);
+ dget(dentry);
+ err = finish_no_open(file, dentry);
@@ -19399,7 +19446,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
+out_si:
+ si_read_unlock(sb);
+out_kfree:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ AuTraceErr(err);
+ return err;
@@ -19492,7 +19539,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
+ di_write_unlock(dentry);
+ si_read_unlock(sb);
+out_kfree:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ AuTraceErr(err);
+ return err;
@@ -19819,7 +19866,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
+};
diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
--- /usr/share/empty/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_del.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/i_op_del.c 2016-08-17 18:01:06.148556271 +0200
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -20217,7 +20264,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
+out_unlock:
+ aufs_read_unlock(dentry, AuLock_DW);
+out_free:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ return err;
+}
@@ -20327,14 +20374,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
+out_unlock:
+ aufs_read_unlock(dentry, AuLock_DW);
+out_free:
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ AuTraceErr(err);
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
--- /usr/share/empty/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_ren.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/i_op_ren.c 2016-08-17 18:01:06.148556271 +0200
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -21346,7 +21393,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
+ iput(a->dst_inode);
+ if (a->thargs)
+ au_whtmp_rmdir_free(a->thargs);
-+ kfree(a);
++ au_delayed_kfree(a);
+out:
+ AuTraceErr(err);
+ return err;
@@ -21542,7 +21589,7 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig
+endif
diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c
--- /usr/share/empty/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/loop.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/loop.c 2016-08-17 18:01:06.151889691 +0200
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -21688,7 +21735,7 @@ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c
+{
+ if (backing_file_func)
+ symbol_put(loop_backing_file);
-+ kfree(au_warn_loopback_array);
++ au_delayed_kfree(au_warn_loopback_array);
+}
diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h
--- /usr/share/empty/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
@@ -21830,8 +21877,8 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
+aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
--- /usr/share/empty/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,223 @@
++++ linux/fs/aufs/module.c 2016-08-17 18:01:06.151889691 +0200
+@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -21869,17 +21916,64 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+}
+
+/* ---------------------------------------------------------------------- */
-+
+/*
+ * aufs caches
+ */
-+struct kmem_cache *au_cachep[AuCache_Last] = {
-+ [0] = NULL
-+};
++
++struct au_dfree au_dfree;
++
++/* delayed free */
++static void au_do_dfree(struct work_struct *work __maybe_unused)
++{
++ struct llist_head *head;
++ struct llist_node *node, *next;
++
++#define AU_CACHE_DFREE_DO_BODY(name, idx, lnode) do { \
++ head = &au_dfree.cache[AuCache_##idx].llist; \
++ node = llist_del_all(head); \
++ for (; node; node = next) { \
++ struct au_##name *p = \
++ p = llist_entry(node, struct au_##name, \
++ lnode); \
++ next = llist_next(node); \
++ au_cache_free_##name(p); \
++ } \
++ } while (0)
++
++ AU_CACHE_DFREE_DO_BODY(dinfo, DINFO, di_lnode);
++ AU_CACHE_DFREE_DO_BODY(icntnr, ICNTNR, lnode);
++ AU_CACHE_DFREE_DO_BODY(finfo, FINFO, fi_lnode);
++ AU_CACHE_DFREE_DO_BODY(vdir, VDIR, vd_lnode);
++ AU_CACHE_DFREE_DO_BODY(vdir_dehstr, DEHSTR, lnode);
++#ifdef CONFIG_AUFS_HNOTIFY
++ AU_CACHE_DFREE_DO_BODY(hnotify, HNOTIFY, hn_lnode);
++#endif
++
++#define AU_DFREE_DO_BODY(llist, func) do { \
++ node = llist_del_all(llist); \
++ for (; node; node = next) { \
++ next = llist_next(node); \
++ func(node); \
++ } \
++ } while (0)
++
++ AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_KFREE, kfree);
++ AU_DFREE_DO_BODY(au_dfree.llist + AU_DFREE_FREE_PAGE, au_free_page);
++
++#undef AU_CACHE_DFREE_DO_BODY
++#undef AU_DFREE_DO_BODY
++}
++
++AU_CACHE_DFREE_FUNC(dinfo, DINFO, di_lnode);
++AU_CACHE_DFREE_FUNC(icntnr, ICNTNR, lnode);
++AU_CACHE_DFREE_FUNC(finfo, FINFO, fi_lnode);
++AU_CACHE_DFREE_FUNC(vdir, VDIR, vd_lnode);
++AU_CACHE_DFREE_FUNC(vdir_dehstr, DEHSTR, lnode);
+
+static void au_cache_fin(void)
+{
+ int i;
++ struct au_cache *cp;
+
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
@@ -21889,27 +21983,33 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+
+ /* excluding AuCache_HNOTIFY */
+ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
++ flush_delayed_work(&au_dfree.dwork);
+ for (i = 0; i < AuCache_HNOTIFY; i++) {
-+ kmem_cache_destroy(au_cachep[i]);
-+ au_cachep[i] = NULL;
++ cp = au_dfree.cache + i;
++ AuDebugOn(!llist_empty(&cp->llist));
++ kmem_cache_destroy(cp->cache);
++ cp->cache = NULL;
+ }
+}
+
+static int __init au_cache_init(void)
+{
-+ au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once);
-+ if (au_cachep[AuCache_DINFO])
++ struct au_cache *cp;
++
++ cp = au_dfree.cache;
++ cp[AuCache_DINFO].cache = AuCacheCtor(au_dinfo, au_di_init_once);
++ if (cp[AuCache_DINFO].cache)
+ /* SLAB_DESTROY_BY_RCU */
-+ au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr,
-+ au_icntnr_init_once);
-+ if (au_cachep[AuCache_ICNTNR])
-+ au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo,
-+ au_fi_init_once);
-+ if (au_cachep[AuCache_FINFO])
-+ au_cachep[AuCache_VDIR] = AuCache(au_vdir);
-+ if (au_cachep[AuCache_VDIR])
-+ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
-+ if (au_cachep[AuCache_DEHSTR])
++ cp[AuCache_ICNTNR].cache = AuCacheCtor(au_icntnr,
++ au_icntnr_init_once);
++ if (cp[AuCache_ICNTNR].cache)
++ cp[AuCache_FINFO].cache = AuCacheCtor(au_finfo,
++ au_fi_init_once);
++ if (cp[AuCache_FINFO].cache)
++ cp[AuCache_VDIR].cache = AuCache(au_vdir);
++ if (cp[AuCache_VDIR].cache)
++ cp[AuCache_DEHSTR].cache = AuCache(au_vdir_dehstr);
++ if (cp[AuCache_DEHSTR].cache)
+ return 0;
+
+ au_cache_fin();
@@ -21972,6 +22072,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+{
+ int err, i;
+ char *p;
++ struct au_cache *cp;
+
+ p = au_esc_chars;
+ for (i = 1; i <= ' '; i++)
@@ -21986,6 +22087,16 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+ for (i = 0; i < AuIop_Last; i++)
+ aufs_iop_nogetattr[i].getattr = NULL;
+
++ /* First, initialize au_dfree */
++ for (i = 0; i < AuCache_Last; i++) { /* including hnotify */
++ cp = au_dfree.cache + i;
++ cp->cache = NULL;
++ init_llist_head(&cp->llist);
++ }
++ for (i = 0; i < AU_DFREE_Last; i++)
++ init_llist_head(au_dfree.llist + i);
++ INIT_DELAYED_WORK(&au_dfree.dwork, au_do_dfree);
++
+ au_sbilist_init();
+ sysaufs_brs_init();
+ au_debug_init();
@@ -22036,6 +22147,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+out_sysaufs:
+ sysaufs_fin();
+ au_dy_fin();
++ flush_delayed_work(&au_dfree.dwork);
+out:
+ return err;
+}
@@ -22051,14 +22163,15 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
+ au_procfs_fin();
+ sysaufs_fin();
+ au_dy_fin();
++ flush_delayed_work(&au_dfree.dwork);
+}
+
+module_init(aufs_init);
+module_exit(aufs_exit);
diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
--- /usr/share/empty/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.h 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,89 @@
++++ linux/fs/aufs/module.h 2016-08-17 18:01:06.158556531 +0200
+@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -22086,6 +22199,7 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
+#ifdef __KERNEL__
+
+#include <linux/slab.h>
++#include "debug.h"
+
+struct path;
+struct seq_file;
@@ -22112,7 +22226,7 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
+
+/* ---------------------------------------------------------------------- */
+
-+/* kmem cache */
++/* kmem cache and delayed free */
+enum {
+ AuCache_DINFO,
+ AuCache_ICNTNR,
@@ -22123,19 +22237,54 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
+ AuCache_Last
+};
+
++enum {
++ AU_DFREE_KFREE,
++ AU_DFREE_FREE_PAGE,
++ AU_DFREE_Last
++};
++
++struct au_cache {
++ struct kmem_cache *cache;
++ struct llist_head llist; /* delayed free */
++};
++
++/*
++ * in order to reduce the cost of the internal timer, consolidate all the
++ * delayed free works into a single delayed_work.
++ */
++struct au_dfree {
++ struct au_cache cache[AuCache_Last];
++ struct llist_head llist[AU_DFREE_Last];
++ struct delayed_work dwork;
++};
++
++extern struct au_dfree au_dfree;
++
+#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
+#define AuCache(type) KMEM_CACHE(type, AuCacheFlags)
+#define AuCacheCtor(type, ctor) \
+ kmem_cache_create(#type, sizeof(struct type), \
+ __alignof__(struct type), AuCacheFlags, ctor)
+
-+extern struct kmem_cache *au_cachep[];
++#define AU_DFREE_DELAY msecs_to_jiffies(10)
++#define AU_DFREE_BODY(lnode, llist) do { \
++ if (llist_add(lnode, llist)) \
++ schedule_delayed_work(&au_dfree.dwork, \
++ AU_DFREE_DELAY); \
++ } while (0)
++#define AU_CACHE_DFREE_FUNC(name, idx, lnode) \
++ void au_cache_dfree_##name(struct au_##name *p) \
++ { \
++ struct au_cache *cp = au_dfree.cache + AuCache_##idx; \
++ AU_DFREE_BODY(&p->lnode, &cp->llist); \
++ }
+
+#define AuCacheFuncs(name, index) \
+static inline struct au_##name *au_cache_alloc_##name(void) \
-+{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
++{ return kmem_cache_alloc(au_dfree.cache[AuCache_##index].cache, GFP_NOFS); } \
+static inline void au_cache_free_##name(struct au_##name *p) \
-+{ kmem_cache_free(au_cachep[AuCache_##index], p); }
++{ kmem_cache_free(au_dfree.cache[AuCache_##index].cache, p); } \
++void au_cache_dfree_##name(struct au_##name *p)
+
+AuCacheFuncs(dinfo, DINFO);
+AuCacheFuncs(icntnr, ICNTNR);
@@ -22146,11 +22295,30 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
+AuCacheFuncs(hnotify, HNOTIFY);
+#endif
+
++static inline void au_delayed_kfree(const void *p)
++{
++ AuDebugOn(!p);
++ AuDebugOn(ksize(p) < sizeof(struct llist_node));
++
++ AU_DFREE_BODY((void *)p, au_dfree.llist + AU_DFREE_KFREE);
++}
++
++/* cast only */
++static inline void au_free_page(void *p)
++{
++ free_page((unsigned long)p);
++}
++
++static inline void au_delayed_free_page(unsigned long addr)
++{
++ AU_DFREE_BODY((void *)addr, au_dfree.llist + AU_DFREE_FREE_PAGE);
++}
++
+#endif /* __KERNEL__ */
+#endif /* __AUFS_MODULE_H__ */
diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
--- /usr/share/empty/fs/aufs/mvdown.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/mvdown.c 2016-07-25 19:05:34.814493242 +0200
++++ linux/fs/aufs/mvdown.c 2016-08-17 18:01:06.158556531 +0200
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2011-2016 Junjiro R. Okajima
@@ -22851,15 +23019,15 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
+ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown));
+ if (unlikely(e))
+ err = -EFAULT;
-+ kfree(args);
++ au_delayed_kfree(args);
+out:
+ AuTraceErr(err);
+ return err;
+}
diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
--- /usr/share/empty/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/opts.c 2016-07-25 19:05:34.814493242 +0200
-@@ -0,0 +1,1859 @@
++++ linux/fs/aufs/opts.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,1860 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -24118,7 +24286,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
+ }
+ }
+
-+ kfree(a);
++ au_delayed_kfree(a);
+ dump_opts(opts);
+ if (unlikely(err))
+ au_opts_free(opts);
@@ -24540,7 +24708,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c
+ au_hn_inode_unlock(hdir);
+
+ if (!err && do_free) {
-+ kfree(wbr);
++ if (wbr)
++ au_delayed_kfree(wbr);
+ br->br_wbr = NULL;
+ }
+ }
@@ -24936,8 +25105,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
+#endif /* __AUFS_OPTS_H__ */
diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
--- /usr/share/empty/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/plink.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,502 @@
++++ linux/fs/aufs/plink.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -24985,6 +25154,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
+{
+ int err;
+ pid_t pid, ppid;
++ struct task_struct *parent, *prev;
+ struct au_sbinfo *sbi;
+
+ SiMustAnyLock(sb);
@@ -24999,11 +25169,22 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
+ goto out;
+
+ /* todo: it highly depends upon /sbin/mount.aufs */
++ prev = NULL;
++ parent = current;
++ ppid = 0;
+ rcu_read_lock();
-+ ppid = task_pid_vnr(rcu_dereference(current->real_parent));
++ while (1) {
++ parent = rcu_dereference(parent->real_parent);
++ if (parent == prev)
++ break;
++ ppid = task_pid_vnr(parent);
++ if (pid == ppid) {
++ rcu_read_unlock();
++ goto out;
++ }
++ prev = parent;
++ }
+ rcu_read_unlock();
-+ if (pid == ppid)
-+ goto out;
+
+ if (au_ftest_lock(flags, NOPLMW)) {
+ /* if there is no i_mutex lock in VFS, we don't need to wait */
@@ -26360,8 +26541,8 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h
+#endif /* __AUFS_RWSEM_H__ */
diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
--- /usr/share/empty/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sbinfo.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,353 @@
++++ linux/fs/aufs/sbinfo.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -26397,7 +26578,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+ for (i = 0; i < AuPlink_NHASH; i++)
+ AuDebugOn(!hlist_empty(&sbinfo->si_plink[i].head));
-+ au_nwt_fin(&sbinfo->si_nowait);
++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));
+
+ AuDebugOn(percpu_counter_sum(&sbinfo->si_ninodes));
+ percpu_counter_destroy(&sbinfo->si_ninodes);
@@ -26408,14 +26589,15 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
+ au_br_free(sbinfo);
+ au_rw_write_unlock(&sbinfo->si_rwsem);
+
-+ kfree(sbinfo->si_branch);
++ au_delayed_kfree(sbinfo->si_branch);
+ for (i = 0; i < AU_NPIDMAP; i++)
-+ kfree(sbinfo->au_si_pid.pid_bitmap[i]);
++ if (sbinfo->au_si_pid.pid_bitmap[i])
++ au_delayed_kfree(sbinfo->au_si_pid.pid_bitmap[i]);
+ mutex_destroy(&sbinfo->au_si_pid.pid_mtx);
+ mutex_destroy(&sbinfo->si_xib_mtx);
+ AuRwDestroy(&sbinfo->si_rwsem);
+
-+ kfree(sbinfo);
++ au_delayed_kfree(sbinfo);
+}
+
+int au_si_alloc(struct super_block *sb)
@@ -26487,9 +26669,9 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
+ return 0; /* success */
+
+out_br:
-+ kfree(sbinfo->si_branch);
++ au_delayed_kfree(sbinfo->si_branch);
+out_sbinfo:
-+ kfree(sbinfo);
++ au_delayed_kfree(sbinfo);
+out:
+ return err;
+}
@@ -26717,8 +26899,8 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
+}
diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
--- /usr/share/empty/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/spl.h 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,111 @@
++++ linux/fs/aufs/spl.h 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -26745,6 +26927,7 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
+
+#ifdef __KERNEL__
+
++#if 0
+struct au_splhead {
+ spinlock_t spin;
+ struct list_head head;
@@ -26777,6 +26960,7 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
+ list_del_rcu(list);
+ spin_unlock(&spl->spin);
+}
++#endif
+
+/* ---------------------------------------------------------------------- */
+
@@ -26832,8 +27016,8 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h
+#endif /* __AUFS_SPL_H__ */
diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
--- /usr/share/empty/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/super.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,1039 @@
++++ linux/fs/aufs/super.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -26882,8 +27066,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
+{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
+
-+ INIT_HLIST_HEAD(&inode->i_dentry);
-+ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
++ au_cache_dfree_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
+}
+
+static void aufs_destroy_inode(struct inode *inode)
@@ -27665,7 +27848,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
+out_mtx:
+ inode_unlock(inode);
+out_opts:
-+ free_page((unsigned long)opts.opt);
++ au_delayed_free_page((unsigned long)opts.opt);
+out:
+ err = cvt_err(err);
+ AuTraceErr(err);
@@ -27806,7 +27989,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
+ kobject_put(&sbinfo->si_kobj);
+ sb->s_fs_info = NULL;
+out_opts:
-+ free_page((unsigned long)opts.opt);
++ au_delayed_free_page((unsigned long)opts.opt);
+out:
+ AuTraceErr(err);
+ err = cvt_err(err);
@@ -28730,7 +28913,7 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h
+#endif /* __SYSAUFS_H__ */
diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
--- /usr/share/empty/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/sysfs.c 2016-07-25 19:05:34.817826663 +0200
++++ linux/fs/aufs/sysfs.c 2016-08-17 18:01:06.161889951 +0200
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -28943,7 +29126,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
+ if (unlikely(err == PAGE_SIZE))
+ err = -EFBIG;
+ }
-+ kfree(seq);
++ au_delayed_kfree(seq);
+out_unlock:
+ si_read_unlock(sb);
+out:
@@ -29014,9 +29197,9 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c
+ err = -EFAULT;
+
+out_seq:
-+ kfree(seq);
++ au_delayed_kfree(seq);
+out_buf:
-+ free_page((unsigned long)buf);
++ au_delayed_free_page((unsigned long)buf);
+out:
+ si_read_unlock(sb);
+ return err;
@@ -29271,8 +29454,8 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c
+}
diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
--- /usr/share/empty/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vdir.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,889 @@
++++ linux/fs/aufs/vdir.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,899 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -29385,7 +29568,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ struct hlist_node *node;
+
+ hlist_for_each_entry_safe(pos, node, head, wh_hash)
-+ kfree(pos);
++ au_delayed_kfree(pos);
+}
+
+static void au_nhash_de_do_free(struct hlist_head *head)
@@ -29394,7 +29577,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ struct hlist_node *node;
+
+ hlist_for_each_entry_safe(pos, node, head, hash)
-+ au_cache_free_vdir_dehstr(pos);
++ au_cache_dfree_vdir_dehstr(pos);
+}
+
+static void au_nhash_do_free(struct au_nhash *nhash,
@@ -29412,7 +29595,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ nhash_count(head);
+ free(head++);
+ }
-+ kfree(nhash->nh_head);
++ au_delayed_kfree(nhash->nh_head);
+}
+
+void au_nhash_wh_free(struct au_nhash *whlist)
@@ -29455,6 +29638,8 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ AuDebugOn(!nhash->nh_num || !nhash->nh_head);
+
+ v = 0;
++ if (len > 8)
++ len = 8;
+ while (len--)
+ v += *name++;
+ /* v = hash_long(v, magic_bit); */
@@ -29623,15 +29808,23 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+
+/* ---------------------------------------------------------------------- */
+
-+void au_vdir_free(struct au_vdir *vdir)
++void au_vdir_free(struct au_vdir *vdir, int atonce)
+{
+ unsigned char **deblk;
+
+ deblk = vdir->vd_deblk;
-+ while (vdir->vd_nblk--)
-+ kfree(*deblk++);
-+ kfree(vdir->vd_deblk);
-+ au_cache_free_vdir(vdir);
++ if (!atonce) {
++ while (vdir->vd_nblk--)
++ au_delayed_kfree(*deblk++);
++ au_delayed_kfree(vdir->vd_deblk);
++ au_cache_dfree_vdir(vdir);
++ } else {
++ /* not delayed */
++ while (vdir->vd_nblk--)
++ kfree(*deblk++);
++ kfree(vdir->vd_deblk);
++ au_cache_free_vdir(vdir);
++ }
+}
+
+static struct au_vdir *alloc_vdir(struct file *file)
@@ -29665,10 +29858,10 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ if (!err)
+ return vdir; /* success */
+
-+ kfree(vdir->vd_deblk);
++ au_delayed_kfree(vdir->vd_deblk);
+
+out_free:
-+ au_cache_free_vdir(vdir);
++ au_cache_dfree_vdir(vdir);
+out:
+ vdir = ERR_PTR(err);
+ return vdir;
@@ -29680,7 +29873,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ union au_vdir_deblk_p p, deblk_end;
+
+ while (vdir->vd_nblk > 1) {
-+ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
++ au_delayed_kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
+ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
+ vdir->vd_nblk--;
+ }
@@ -29811,7 +30004,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ }
+ }
+
-+ free_page((unsigned long)o);
++ au_delayed_free_page((unsigned long)o);
+
+out:
+ AuTraceErr(err);
@@ -29950,7 +30143,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ if (allocated)
+ au_set_ivdir(inode, allocated);
+ } else if (allocated)
-+ au_vdir_free(allocated);
++ au_vdir_free(allocated, /*atonce*/0);
+
+out:
+ return err;
@@ -30044,7 +30237,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
+ if (allocated)
+ au_set_fvdir_cache(file, allocated);
+ } else if (allocated)
-+ au_vdir_free(allocated);
++ au_vdir_free(allocated, /*atonce*/0);
+
+out:
+ return err;
@@ -31052,8 +31245,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
+}
diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
--- /usr/share/empty/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vfsub.h 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,310 @@
++++ linux/fs/aufs/vfsub.h 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -31252,6 +31445,12 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
+ return flags;
+}
+
++static inline int vfsub_file_execed(struct file *file)
++{
++ /* todo: direct access f_flags */
++ return !!(vfsub_file_flags(file) & __FMODE_EXEC);
++}
++
+#if 0 /* reserved */
+static inline void vfsub_file_accessed(struct file *h_file)
+{
@@ -31366,7 +31565,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
+#endif /* __AUFS_VFSUB_H__ */
diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
--- /usr/share/empty/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wbr_policy.c 2016-07-25 19:05:34.817826663 +0200
++++ linux/fs/aufs/wbr_policy.c 2016-08-17 18:01:06.161889951 +0200
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -31831,7 +32030,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
+
+ mfs->mfsrr_bytes = bavail;
+ AuDbg("b%d\n", mfs->mfs_bindex);
-+ kfree(st);
++ au_delayed_kfree(st);
+}
+
+static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags)
@@ -32135,7 +32334,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
+};
diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
--- /usr/share/empty/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/whout.c 2016-07-25 19:05:34.817826663 +0200
++++ linux/fs/aufs/whout.c 2016-08-17 18:01:06.161889951 +0200
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -32301,7 +32500,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+
+out_name:
+ if (name != defname)
-+ kfree(name);
++ au_delayed_kfree(name);
+out:
+ AuTraceErrPtr(dentry);
+ return dentry;
@@ -32740,7 +32939,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ au_br_put(a->br);
+ si_write_unlock(a->sb);
+ au_nwt_done(&au_sbi(a->sb)->si_nowait);
-+ kfree(arg);
++ au_delayed_kfree(arg);
+ if (unlikely(err))
+ AuIOErr("err %d\n", err);
+}
@@ -32768,7 +32967,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ if (unlikely(wkq_err)) {
+ atomic_dec(&br->br_wbr->wbr_wh_running);
+ au_br_put(br);
-+ kfree(arg);
++ au_delayed_kfree(arg);
+ }
+ do_dec = 0;
+ }
@@ -32927,7 +33126,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ wh_dentry = ERR_PTR(err);
+ if (!err) {
+ wh_dentry = vfsub_lkup_one(&wh_name, h_parent);
-+ kfree(wh_name.name);
++ au_delayed_kfree(wh_name.name);
+ }
+ return wh_dentry;
+}
@@ -33003,7 +33202,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ break;
+ }
+ }
-+ free_page((unsigned long)wh_name.name);
++ au_delayed_free_page((unsigned long)wh_name.name);
+
+out:
+ return err;
@@ -33045,7 +33244,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ rdhash = AUFS_RDHASH_DEF;
+ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp);
+ if (unlikely(err)) {
-+ kfree(whtmp);
++ au_delayed_kfree(whtmp);
+ whtmp = ERR_PTR(err);
+ }
+
@@ -33060,7 +33259,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
+ dput(whtmp->wh_dentry);
+ iput(whtmp->dir);
+ au_nhash_wh_free(&whtmp->whlist);
-+ kfree(whtmp);
++ au_delayed_kfree(whtmp);
+}
+
+/*
@@ -33288,8 +33487,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h
+#endif /* __AUFS_WHOUT_H__ */
diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
--- /usr/share/empty/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wkq.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,218 @@
++++ linux/fs/aufs/wkq.c 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -33346,7 +33545,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
+ else {
+ kobject_put(wkinfo->kobj);
+ module_put(THIS_MODULE); /* todo: ?? */
-+ kfree(wkinfo);
++ au_delayed_kfree(wkinfo);
+ }
+}
+
@@ -33369,7 +33568,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
+
+static void au_wkq_comp_free(struct completion *comp)
+{
-+ kfree(comp);
++ au_delayed_kfree(comp);
+}
+
+#else
@@ -33450,7 +33649,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
+ int err;
+ struct au_wkinfo *wkinfo;
+
-+ percpu_counter_inc(&au_sbi(sb)->si_nowait.nw_len);
++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len);
+
+ /*
+ * wkq_func() must free this wkinfo.
@@ -33480,16 +33679,11 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
+
+void au_nwt_init(struct au_nowait_tasks *nwt)
+{
-+ percpu_counter_init(&nwt->nw_len, 0, GFP_NOFS);
++ atomic_set(&nwt->nw_len, 0);
++ /* smp_mb(); */ /* atomic_set */
+ init_waitqueue_head(&nwt->nw_wq);
+}
+
-+void au_nwt_fin(struct au_nowait_tasks *nwt)
-+{
-+ AuDebugOn(percpu_counter_sum(&nwt->nw_len));
-+ percpu_counter_destroy(&nwt->nw_len);
-+}
-+
+void au_wkq_fin(void)
+{
+ destroy_workqueue(au_wkq);
@@ -33510,8 +33704,8 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c
+}
diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
--- /usr/share/empty/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wkq.h 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,95 @@
++++ linux/fs/aufs/wkq.h 2016-08-17 18:01:06.161889951 +0200
+@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -33549,7 +33743,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
+ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue
+ */
+struct au_nowait_tasks {
-+ struct percpu_counter nw_len;
++ atomic_t nw_len;
+ wait_queue_head_t nw_wq;
+};
+
@@ -33576,7 +33770,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
+int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb,
+ unsigned int flags);
+void au_nwt_init(struct au_nowait_tasks *nwt);
-+void au_nwt_fin(struct au_nowait_tasks *nwt);
+int __init au_wkq_init(void);
+void au_wkq_fin(void);
+
@@ -33594,14 +33787,13 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
+
+static inline void au_nwt_done(struct au_nowait_tasks *nwt)
+{
-+ percpu_counter_dec(&nwt->nw_len);
-+ if (!percpu_counter_sum(&nwt->nw_len))
++ if (atomic_dec_and_test(&nwt->nw_len))
+ wake_up_all(&nwt->nw_wq);
+}
+
+static inline int au_nwt_flush(struct au_nowait_tasks *nwt)
+{
-+ wait_event(nwt->nw_wq, !percpu_counter_sum(&nwt->nw_len));
++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len));
+ return 0;
+}
+
@@ -33609,8 +33801,8 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h
+#endif /* __AUFS_WKQ_H__ */
diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c
--- /usr/share/empty/fs/aufs/xattr.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/xattr.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,345 @@
++++ linux/fs/aufs/xattr.c 2016-08-17 18:01:06.165223371 +0200
+@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2014-2016 Junjiro R. Okajima
+ *
@@ -33789,10 +33981,12 @@ diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c
+ AuTraceErr(err);
+ }
+
-+ kfree(value);
++ if (value)
++ au_delayed_kfree(value);
+
+out_free:
-+ kfree(o);
++ if (o)
++ au_delayed_kfree(o);
+out:
+ if (!unlocked)
+ inode_unlock(h_isrc);
@@ -33958,8 +34152,8 @@ diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c
+#endif
diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
--- /usr/share/empty/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/xino.c 2016-07-25 19:05:34.817826663 +0200
-@@ -0,0 +1,1317 @@
++++ linux/fs/aufs/xino.c 2016-08-17 18:01:06.165223371 +0200
+@@ -0,0 +1,1318 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
+ *
@@ -34300,7 +34494,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ AuErr1("statfs err %d, ignored\n", err);
+
+out_st:
-+ kfree(st);
++ au_delayed_kfree(st);
+out:
+ return err;
+}
@@ -34335,7 +34529,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ au_br_put(br);
+ si_write_unlock(sb);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
-+ kfree(args);
++ au_delayed_kfree(args);
+}
+
+static int xino_trunc_test(struct super_block *sb, struct au_branch *br)
@@ -34377,7 +34571,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ args = kmalloc(sizeof(*args), GFP_NOFS);
+ if (unlikely(!args)) {
+ AuErr1("no memory\n");
-+ goto out_args;
++ goto out;
+ }
+
+ au_br_get(br);
@@ -34389,9 +34583,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+
+ pr_err("wkq %d\n", wkq_err);
+ au_br_put(br);
++ au_delayed_kfree(args);
+
-+out_args:
-+ kfree(args);
+out:
+ atomic_dec(&br->br_xino_running);
+}
@@ -34914,7 +35107,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page);
+ else
+ AuDbg("b%d\n", bindex);
-+ free_page((unsigned long)page);
++ au_delayed_free_page((unsigned long)page);
+
+out:
+ return err;
@@ -34991,7 +35184,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ if (sbinfo->si_xib)
+ fput(sbinfo->si_xib);
+ sbinfo->si_xib = NULL;
-+ free_page((unsigned long)sbinfo->si_xib_buf);
++ if (sbinfo->si_xib_buf)
++ au_delayed_free_page((unsigned long)sbinfo->si_xib_buf);
+ sbinfo->si_xib_buf = NULL;
+}
+
@@ -35034,7 +35228,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ goto out; /* success */
+
+out_free:
-+ free_page((unsigned long)sbinfo->si_xib_buf);
++ if (sbinfo->si_xib_buf)
++ au_delayed_free_page((unsigned long)sbinfo->si_xib_buf);
+ sbinfo->si_xib_buf = NULL;
+ if (err >= 0)
+ err = -EIO;
@@ -35127,7 +35322,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ fput(p->new);
+ else
+ break;
-+ kfree(fpair);
++ au_delayed_kfree(fpair);
+out:
+ return err;
+}
@@ -35238,7 +35433,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+ if (!IS_ERR(file))
+ au_xino_brid_set(sb, br->br_id);
+ }
-+ free_page((unsigned long)page);
++ au_delayed_free_page((unsigned long)page);
+ } else {
+ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0);
+ if (IS_ERR(file))
@@ -35279,7 +35474,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
+}
diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/linux/aufs_type.h
--- /usr/share/empty/include/uapi/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/uapi/linux/aufs_type.h 2016-07-25 19:05:34.817826663 +0200
++++ linux/include/uapi/linux/aufs_type.h 2016-08-17 18:01:21.295617591 +0200
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2005-2016 Junjiro R. Okajima
@@ -35322,7 +35517,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
+
+#include <linux/limits.h>
+
-+#define AUFS_VERSION "4.x-rcN-20160704"
++#define AUFS_VERSION "4.7-20160815"
+
+/* todo? move this to linux-2.6.19/include/magic.h */
+#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -35700,7 +35895,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
+#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int)
+
+#endif /* __AUFS_TYPE_H__ */
-aufs4.x-rcN loopback patch
+aufs4.7 loopback patch
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 7339e65..76e5da4 100644
@@ -35882,10 +36077,10 @@ index fb2237c..c3888c5 100644
unsigned lo_blocksize;
void *key_data;
diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
-index 504b767..09426ad 100644
+index 00475fb..01390e1 100644
--- a/fs/aufs/f_op.c
+++ b/fs/aufs/f_op.c
-@@ -346,7 +346,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter)
+@@ -348,7 +348,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter)
if (IS_ERR(h_file))
goto out;
@@ -35895,12 +36090,12 @@ index 504b767..09426ad 100644
if (file->f_mapping != h_file->f_mapping) {
file->f_mapping = h_file->f_mapping;
diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c
-index 5711e7a..9df5d16 100644
+index e92a345..35f4d48 100644
--- a/fs/aufs/loop.c
+++ b/fs/aufs/loop.c
@@ -131,3 +131,19 @@ void au_loopback_fin(void)
symbol_put(loop_backing_file);
- kfree(au_warn_loopback_array);
+ au_delayed_kfree(au_warn_loopback_array);
}
+
+/* ---------------------------------------------------------------------- */
@@ -35944,10 +36139,10 @@ index 48bf070..66afec7 100644
#endif /* __KERNEL__ */
diff --git a/fs/aufs/super.c b/fs/aufs/super.c
-index 8bd2d9c..26581c0 100644
+index 58a773c..75f212c 100644
--- a/fs/aufs/super.c
+++ b/fs/aufs/super.c
-@@ -832,7 +832,10 @@ static const struct super_operations aufs_sop = {
+@@ -831,7 +831,10 @@ static const struct super_operations aufs_sop = {
.statfs = aufs_statfs,
.put_super = aufs_put_super,
.sync_fs = aufs_sync_fs,
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/f0c0a0075ebbd8e5d2b07223d3e6a049d302da27
More information about the pld-cvs-commit
mailing list