-diff -Nur linux-2.6.31-vanilla/Documentation/ABI/testing/debugfs-aufs linux-2.6.31/Documentation/ABI/testing/debugfs-aufs
---- linux-2.6.31-vanilla/Documentation/ABI/testing/debugfs-aufs 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/Documentation/ABI/testing/debugfs-aufs 2009-09-16 13:55:29.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/Documentation/ABI/testing/debugfs-aufs linux-2.6.33.1/Documentation/ABI/testing/debugfs-aufs
+--- linux-2.6.33.1-vanilla/Documentation/ABI/testing/debugfs-aufs 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/Documentation/ABI/testing/debugfs-aufs 2010-04-05 16:48:57.000000000 +0200
@@ -0,0 +1,40 @@
+What: /debug/aufs/si_<id>/
+Date: March 2009
+ When the aufs mount option 'noxino' is specified, it
+ will be empty. About XINO files, see
+ Documentation/filesystems/aufs/aufs.5 in detail.
-diff -Nur linux-2.6.31-vanilla/Documentation/ABI/testing/sysfs-aufs linux-2.6.31/Documentation/ABI/testing/sysfs-aufs
---- linux-2.6.31-vanilla/Documentation/ABI/testing/sysfs-aufs 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/Documentation/ABI/testing/sysfs-aufs 2009-09-16 13:55:29.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/Documentation/ABI/testing/sysfs-aufs linux-2.6.33.1/Documentation/ABI/testing/sysfs-aufs
+--- linux-2.6.33.1-vanilla/Documentation/ABI/testing/sysfs-aufs 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/Documentation/ABI/testing/sysfs-aufs 2010-04-05 16:48:57.000000000 +0200
@@ -0,0 +1,25 @@
+What: /sys/fs/aufs/si_<id>/
+Date: March 2009
+ When the aufs mount option 'noxino' is specified, it
+ will be empty. About XINO files, see
+ Documentation/filesystems/aufs/aufs.5 in detail.
-diff -Nur linux-2.6.31-vanilla/fs/aufs/aufs.h linux-2.6.31/fs/aufs/aufs.h
---- linux-2.6.31-vanilla/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/aufs.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,51 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/aufs.h linux-2.6.33.1/fs/aufs/aufs.h
+--- linux-2.6.33.1-vanilla/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/aufs.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,59 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#ifdef __KERNEL__
+
++#define AuStub(type, name, body, ...) \
++ static inline type name(__VA_ARGS__) { body; }
++
++#define AuStubVoid(name, ...) \
++ AuStub(void, name, , __VA_ARGS__)
++#define AuStubInt0(name, ...) \
++ AuStub(int, name, return 0, __VA_ARGS__)
++
+#include "debug.h"
+
+#include "branch.h"
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c
---- linux-2.6.31-vanilla/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/branch.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,969 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/branch.c linux-2.6.33.1/fs/aufs/branch.c
+--- linux-2.6.33.1-vanilla/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/branch.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,996 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ */
+
+#include <linux/file.h>
++#include <linux/statfs.h>
+#include "aufs.h"
+
+/*
+ }
+
+ /* some filesystems acquire extra lock */
-+ lockdep_off();
++ /* lockdep_off(); */
+ mntput(br->br_mnt);
-+ lockdep_on();
++ /* lockdep_on(); */
+
+ kfree(wbr);
+ kfree(br);
+{
+ struct au_branch *add_branch;
+ struct dentry *root;
++ int err;
+
++ err = -ENOMEM;
+ root = sb->s_root;
+ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS);
+ if (unlikely(!add_branch))
+ goto out_br;
+ }
+
-+ if (unlikely(au_sbr_realloc(au_sbi(sb), new_nbranch)
-+ || au_di_realloc(au_di(root), new_nbranch)
-+ || au_ii_realloc(au_ii(root->d_inode), new_nbranch)))
-+ goto out_wbr;
-+ return add_branch; /* success */
++ err = au_sbr_realloc(au_sbi(sb), new_nbranch);
++ if (!err)
++ err = au_di_realloc(au_di(root), new_nbranch);
++ if (!err)
++ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch);
++ if (!err)
++ return add_branch; /* success */
+
-+ out_wbr:
+ kfree(add_branch->br_wbr);
++
+ out_br:
+ kfree(add_branch);
+ out:
-+ return ERR_PTR(-ENOMEM);
++ return ERR_PTR(err);
+}
+
+/*
+{
+ int err;
+
-+ err = 0;
-+ if (unlikely(au_br_writable(brperm) && IS_RDONLY(inode))) {
-+ AuErr("write permission for readonly mount or inode, %s\n",
-+ path);
-+ err = -EINVAL;
-+ }
++ err = (au_br_writable(brperm) && IS_RDONLY(inode));
++ if (!err)
++ goto out;
++
++ err = -EINVAL;
++ pr_err("write permission for readonly mount or inode, %s\n", path);
+
++ out:
+ return err;
+}
+
+ err = 1;
+ if (!remount) {
+ err = -EINVAL;
-+ AuErr("%s duplicated\n", add->pathname);
++ pr_err("%s duplicated\n", add->pathname);
+ }
+ goto out;
+ }
+ err = -ENOSPC; /* -E2BIG; */
+ if (unlikely(AUFS_BRANCH_MAX <= add->bindex
+ || AUFS_BRANCH_MAX - 1 <= bend)) {
-+ AuErr("number of branches exceeded %s\n", add->pathname);
++ pr_err("number of branches exceeded %s\n", add->pathname);
+ goto out;
+ }
+
+ err = -EDOM;
+ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) {
-+ AuErr("bad index %d\n", add->bindex);
++ pr_err("bad index %d\n", add->bindex);
+ goto out;
+ }
+
+ inode = add->path.dentry->d_inode;
+ err = -ENOENT;
+ if (unlikely(!inode->i_nlink)) {
-+ AuErr("no existence %s\n", add->pathname);
++ pr_err("no existence %s\n", add->pathname);
+ goto out;
+ }
+
+ err = -EINVAL;
+ if (unlikely(inode->i_sb == sb)) {
-+ AuErr("%s must be outside\n", add->pathname);
++ pr_err("%s must be outside\n", add->pathname);
+ goto out;
+ }
+
+ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) {
-+ AuErr("unsupported filesystem, %s (%s)\n",
-+ add->pathname, au_sbtype(inode->i_sb));
++ pr_err("unsupported filesystem, %s (%s)\n",
++ add->pathname, au_sbtype(inode->i_sb));
+ goto out;
+ }
+
+ for (bindex = 0; bindex <= bend; bindex++)
+ if (unlikely(test_overlap(sb, add->path.dentry,
+ au_h_dptr(root, bindex)))) {
-+ AuErr("%s is overlapped\n", add->pathname);
++ pr_err("%s is overlapped\n", add->pathname);
+ goto out;
+ }
+
+ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO)
+ || h_inode->i_uid != inode->i_uid
+ || h_inode->i_gid != inode->i_gid)
-+ AuWarn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
-+ add->pathname,
-+ inode->i_uid, inode->i_gid,
-+ (inode->i_mode & S_IALLUGO),
-+ h_inode->i_uid, h_inode->i_gid,
-+ (h_inode->i_mode & S_IALLUGO));
++ pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
++ add->pathname,
++ inode->i_uid, inode->i_gid,
++ (inode->i_mode & S_IALLUGO),
++ h_inode->i_uid, h_inode->i_gid,
++ (h_inode->i_mode & S_IALLUGO));
+ }
+
+ out:
+ bindex = au_br_index(sb, br->br_id);
+ if (0 <= bindex) {
+ hdir = au_hi(sb->s_root->d_inode, bindex);
-+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+ } else {
+ h_mtx = &h_root->d_inode->i_mutex;
+ mutex_lock_nested(h_mtx, AuLsc_I_PARENT);
+ wbr_wh_write_unlock(wbr);
+ }
+ if (hdir)
-+ au_hin_imtx_unlock(hdir);
++ au_hn_imtx_unlock(hdir);
+ else
+ mutex_unlock(h_mtx);
+ br->br_perm = old_perm;
+ int perm, struct path *path)
+{
+ int err;
++ struct kstatfs kst;
+ struct au_wbr *wbr;
++ struct dentry *h_dentry;
+
+ wbr = br->br_wbr;
+ au_rw_init(&wbr->wbr_wh_rwsem);
+ atomic_set(&wbr->wbr_wh_running, 0);
+ wbr->wbr_bytes = 0;
+
-+ err = au_br_init_wh(sb, br, perm, path->dentry);
++ /*
++ * a limit for rmdir/rename a dir
++ * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h
++ */
++ h_dentry = path->dentry;
++ err = vfs_statfs(h_dentry, &kst);
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ if (kst.f_namelen >= NAME_MAX)
++ err = au_br_init_wh(sb, br, perm, h_dentry);
++ else
++ pr_err("%.*s(%s), unsupported namelen %ld\n",
++ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb),
++ kst.f_namelen);
+
++ out:
+ return err;
+}
+
+ hip = iinfo->ii_hinode + bindex;
+ memmove(hip + 1, hip, sizeof(*hip) * amount);
+ hip->hi_inode = NULL;
-+ au_hin_init(hip, NULL);
++ au_hn_init(hip);
+ iinfo->ii_bend++;
+ if (unlikely(bend < 0))
+ iinfo->ii_bstart = 0;
+
+ root = sb->s_root;
+ root_inode = root->d_inode;
-+ au_plink_block_maintain(sb);
++ au_plink_maint_block(sb);
+ bend = au_sbend(sb);
+ amount = bend + 1 - bindex;
+ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
+ au_add_nlink(root_inode, h_dentry->d_inode);
+
+ /*
-+ * this test/set prevents aufs from handling unnecesary inotify events
++ * this test/set prevents aufs from handling unnecesary notify events
+ * of xino files, in a case of re-adding a writable branch which was
+ * once detached from aufs.
+ */
+ */
+
+/* to show the line number, do not make it inlined function */
-+#define AuVerbose(do_info, fmt, args...) do { \
++#define AuVerbose(do_info, fmt, ...) do { \
+ if (do_info) \
-+ AuInfo(fmt, ##args); \
++ pr_info(fmt, ##__VA_ARGS__); \
+} while (0)
+
+/*
+ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS);
+ if (p)
+ sbinfo->si_branch = p;
++ /* harmless error */
+}
+
+static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
+ p = krealloc(dinfo->di_hdentry, sizeof(*p) * bend, GFP_NOFS);
+ if (p)
+ dinfo->di_hdentry = p;
++ /* harmless error */
+}
+
+static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
+ if (bindex < bend)
+ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex));
+ iinfo->ii_hinode[0 + bend].hi_inode = NULL;
-+ au_hin_init(iinfo->ii_hinode + bend, NULL);
++ au_hn_init(iinfo->ii_hinode + bend);
+ iinfo->ii_bend--;
+
+ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS);
+ if (p)
+ iinfo->ii_hinode = p;
++ /* harmless error */
+}
+
+static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
+
+ root = sb->s_root;
+ inode = root->d_inode;
-+ au_plink_block_maintain(sb);
++ au_plink_maint_block(sb);
+ sbinfo = au_sbi(sb);
+ bend = sbinfo->si_bend;
+
+ if (remount)
+ goto out; /* success */
+ err = -ENOENT;
-+ AuErr("%s no such branch\n", del->pathname);
++ pr_err("%s no such branch\n", del->pathname);
+ goto out;
+ }
+ AuDbg("bindex b%d\n", bindex);
+ /* revert */
+ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry);
+ if (rerr)
-+ AuWarn("failed re-creating base whiteout, %s. (%d)\n",
-+ del->pathname, rerr);
++ pr_warning("failed re-creating base whiteout, %s. (%d)\n",
++ del->pathname, rerr);
+ out:
+ return err;
+}
+static void au_warn_ima(void)
+{
+#ifdef CONFIG_IMA
-+ AuWarn("RW -> RO makes IMA to produce wrong message");
++ /* since it doesn't support mark_files_ro() */
++ pr_warning("RW -> RO makes IMA to produce wrong message");
+#endif
+}
+
+ struct au_branch *br;
+
+ root = sb->s_root;
-+ au_plink_block_maintain(sb);
++ au_plink_maint_block(sb);
+ bindex = au_find_dbindex(root, mod->h_root);
+ if (bindex < 0) {
+ if (remount)
+ return 0; /* success */
+ err = -ENOENT;
-+ AuErr("%s no such branch\n", mod->path);
++ pr_err("%s no such branch\n", mod->path);
+ goto out;
+ }
+ AuDbg("bindex b%d\n", bindex);
+ out:
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.h linux-2.6.31/fs/aufs/branch.h
---- linux-2.6.31-vanilla/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/branch.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/branch.h linux-2.6.33.1/fs/aufs/branch.h
+--- linux-2.6.33.1-vanilla/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/branch.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,219 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+struct au_wbr {
+ struct au_rwsem wbr_wh_rwsem;
+ struct dentry *wbr_wh[AuBrWh_Last];
-+ atomic_t wbr_wh_running;
++ atomic_t wbr_wh_running;
+#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */
+#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */
+#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */
+ ? -EROFS : 0;
+}
+
-+static inline int au_br_hinotifyable(int brperm __maybe_unused)
++static inline int au_br_hnotifyable(int brperm __maybe_unused)
+{
-+#ifdef CONFIG_AUFS_HINOTIFY
++#ifdef CONFIG_AUFS_HNOTIFY
+ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH;
+#else
+ return 0;
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_BRANCH_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c
---- linux-2.6.31-vanilla/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/cpup.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,1048 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/conf.mk linux-2.6.33.1/fs/aufs/conf.mk
+--- linux-2.6.33.1-vanilla/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/conf.mk 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,33 @@
++
++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS}
++
++define AuConf
++ifdef ${1}
++AuConfStr += ${1}=${${1}}
++endif
++endef
++
++$(foreach i, BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \
++ HNOTIFY HFSNOTIFY HINOTIFY \
++ EXPORT INO_T_64 \
++ RDU \
++ SP_IATTR \
++ SHWH \
++ BR_RAMFS \
++ BR_FUSE POLL \
++ BR_HFSPLUS \
++ BDEV_LOOP \
++ DEBUG MAGIC_SYSRQ, \
++ $(eval $(call AuConf,CONFIG_AUFS_${i})))
++
++AuConfName = ${obj}/conf.str
++${AuConfName}.tmp: FORCE
++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@
++${AuConfName}: ${AuConfName}.tmp
++ @diff -q $< $@ > /dev/null 2>&1 || { \
++ echo ' GEN ' $@; \
++ cp -p $< $@; \
++ }
++FORCE:
++clean-files += ${AuConfName} ${AuConfName}.tmp
++${obj}/sysfs.o: ${AuConfName}
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/cpup.c linux-2.6.33.1/fs/aufs/cpup.c
+--- linux-2.6.33.1-vanilla/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/cpup.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,1049 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+ h_inode = au_h_iptr(inode, au_ibstart(inode));
+ fsstack_copy_attr_times(inode, h_inode);
-+ vfsub_copy_inode_size(inode, h_inode);
++ fsstack_copy_inode_size(inode, h_inode);
+}
+
+void au_cpup_attr_nlink(struct inode *inode, int force)
+
+ err = vfsub_notify_change(&dt->dt_h_path, &attr);
+ if (unlikely(err))
-+ AuWarn("restoring timestamps failed(%d). ignored\n", err);
++ pr_warning("restoring timestamps failed(%d). ignored\n", err);
+}
+
+/* ---------------------------------------------------------------------- */
+ goto out;
+
+ err = -ENOMEM;
-+ sym = __getname();
++ sym = __getname_gfp(GFP_NOFS);
+ if (unlikely(!sym))
+ goto out;
+
+
+ dget(wh_dentry);
+ h_path.dentry = wh_dentry;
-+ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0);
++ if (!S_ISDIR(wh_dentry->d_inode->i_mode))
++ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0);
++ else
++ err = vfsub_rmdir(h_parent->d_inode, &h_path);
+ if (unlikely(err)) {
+ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n",
+ AuDLNPair(wh_dentry), err);
+ h_orph = wbr->wbr_orph;
+
+ h_parent = dget(au_h_dptr(parent, bdst));
-+ au_set_h_dptr(parent, bdst, NULL);
+ au_set_h_dptr(parent, bdst, dget(h_orph));
+ h_tmpdir = h_orph->d_inode;
-+ au_set_h_iptr(dir, bdst, NULL, 0);
+ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
+
+ /* this temporary unlock is safe */
+ mutex_unlock(&h_inode->i_mutex);
+ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ /* todo: au_h_open_pre()? */
+ }
+
+ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE))
+
+ if (h_orph) {
+ mutex_unlock(&h_tmpdir->i_mutex);
-+ au_set_h_iptr(dir, bdst, NULL, 0);
++ /* todo: au_h_open_post()? */
+ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
-+ au_set_h_dptr(parent, bdst, NULL);
+ au_set_h_dptr(parent, bdst, h_parent);
+ }
+ iput(h_dir);
+ dput(parent);
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.h linux-2.6.31/fs/aufs/cpup.h
---- linux-2.6.31-vanilla/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/cpup.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/cpup.h linux-2.6.33.1/fs/aufs/cpup.h
+--- linux-2.6.33.1-vanilla/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/cpup.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,81 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_CPUP_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dbgaufs.c linux-2.6.31/fs/aufs/dbgaufs.c
---- linux-2.6.31-vanilla/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dbgaufs.c 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dbgaufs.c linux-2.6.33.1/fs/aufs/dbgaufs.c
+--- linux-2.6.33.1-vanilla/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dbgaufs.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,331 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ err = 0;
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dbgaufs.h linux-2.6.31/fs/aufs/dbgaufs.h
---- linux-2.6.31-vanilla/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dbgaufs.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,79 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dbgaufs.h linux-2.6.33.1/fs/aufs/dbgaufs.h
+--- linux-2.6.33.1-vanilla/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dbgaufs.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,52 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+int dbgaufs_si_init(struct au_sbinfo *sbinfo);
+void dbgaufs_fin(void);
+int __init dbgaufs_init(void);
-+
+#else
-+
-+static inline
-+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
-+{
-+ /* empty */
-+}
-+
-+static inline
-+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
-+{
-+ /* empty */
-+}
-+
-+static inline
-+void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
-+{
-+ /* empty */
-+}
-+
-+static inline
-+int dbgaufs_si_init(struct au_sbinfo *sbinfo)
-+{
-+ return 0;
-+}
-+
-+#define dbgaufs_fin() do {} while (0)
-+
-+static inline
-+int __init dbgaufs_init(void)
-+{
-+ return 0;
-+}
++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo)
++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo)
++AuStubVoid(dbgaufs_fin, void)
++AuStubInt0(__init dbgaufs_init, void)
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* __KERNEL__ */
+#endif /* __DBGAUFS_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dcsub.c linux-2.6.31/fs/aufs/dcsub.c
---- linux-2.6.31-vanilla/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dcsub.c 2009-09-16 13:55:29.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dcsub.c linux-2.6.33.1/fs/aufs/dcsub.c
+--- linux-2.6.33.1-vanilla/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dcsub.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,223 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ out:
+ return trap;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dcsub.h linux-2.6.31/fs/aufs/dcsub.h
---- linux-2.6.31-vanilla/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dcsub.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dcsub.h linux-2.6.33.1/fs/aufs/dcsub.h
+--- linux-2.6.33.1-vanilla/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dcsub.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,54 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DCSUB_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c
---- linux-2.6.31-vanilla/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/debug.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,431 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/debug.c linux-2.6.33.1/fs/aufs/debug.c
+--- linux-2.6.33.1-vanilla/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/debug.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,432 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+char *au_plevel = KERN_DEBUG;
-+#define dpri(fmt, arg...) do { \
++#define dpri(fmt, ...) do { \
+ if (au_debug_test()) \
-+ printk("%s" fmt, au_plevel, ##arg); \
++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+ && file->f_dentry
+ && au_test_aufs(file->f_dentry->d_sb)
+ && au_fi(file))
-+ snprintf(a, sizeof(a), ", mmapped %d", au_test_mmapped(file));
++ snprintf(a, sizeof(a), ", mmapped %d",
++ !!au_fi(file)->fi_h_vm_ops);
+ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n",
+ bindex, file->f_mode, file->f_flags, (long)file_count(file),
+ file->f_pos, a);
+#ifdef AuForceNoRefrof
+ au_opt_clr(sbinfo->si_mntflags, REFROF);
+#endif
-+#ifdef AuForceHinotify
-+ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HINOTIFY);
++#ifdef AuForceHnotify
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HNOTIFY);
+#endif
+#ifdef AuForceRd0
+ sbinfo->si_rdblk = 0;
+ AuDebugOn(destr.len < NAME_MAX);
+
+#ifdef CONFIG_4KSTACKS
-+ AuWarn("CONFIG_4KSTACKS is defined.\n");
++ pr_warning("CONFIG_4KSTACKS is defined.\n");
+#endif
+
+#ifdef AuForceNoBrs
+
+ return 0;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.h linux-2.6.31/fs/aufs/debug.h
---- linux-2.6.31-vanilla/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/debug.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,263 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/debug.h linux-2.6.33.1/fs/aufs/debug.h
+--- linux-2.6.33.1-vanilla/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/debug.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,229 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+}
+#else
+#define AuDebugOn(a) do {} while (0)
-+#define au_debug() do {} while (0)
-+static inline int au_debug_test(void)
-+{
-+ return 0;
-+}
++AuStubVoid(au_debug, int n)
++AuStubInt0(au_debug_test, void)
+#endif /* CONFIG_AUFS_DEBUG */
+
+/* ---------------------------------------------------------------------- */
+
+/* debug print */
+
-+#define AuDpri(lvl, fmt, arg...) \
-+ printk(lvl AUFS_NAME " %s:%d:%s[%d]: " fmt, \
-+ __func__, __LINE__, current->comm, current->pid, ##arg)
-+#define AuDbg(fmt, arg...) do { \
++#define AuDbg(fmt, ...) do { \
+ if (au_debug_test()) \
-+ AuDpri(KERN_DEBUG, "DEBUG: " fmt, ##arg); \
++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \
+} while (0)
-+#define AuLabel(l) AuDbg(#l "\n")
-+#define AuInfo(fmt, arg...) AuDpri(KERN_INFO, fmt, ##arg)
-+#define AuWarn(fmt, arg...) AuDpri(KERN_WARNING, fmt, ##arg)
-+#define AuErr(fmt, arg...) AuDpri(KERN_ERR, fmt, ##arg)
-+#define AuIOErr(fmt, arg...) AuErr("I/O Error, " fmt, ##arg)
-+#define AuWarn1(fmt, arg...) do { \
++#define AuLabel(l) AuDbg(#l "\n")
++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__)
++#define AuWarn1(fmt, ...) do { \
+ static unsigned char _c; \
+ if (!_c++) \
-+ AuWarn(fmt, ##arg); \
++ pr_warning(fmt, ##__VA_ARGS__); \
+} while (0)
+
-+#define AuErr1(fmt, arg...) do { \
++#define AuErr1(fmt, ...) do { \
+ static unsigned char _c; \
+ if (!_c++) \
-+ AuErr(fmt, ##arg); \
++ pr_err(fmt, ##__VA_ARGS__); \
+} while (0)
+
-+#define AuIOErr1(fmt, arg...) do { \
++#define AuIOErr1(fmt, ...) do { \
+ static unsigned char _c; \
+ if (!_c++) \
-+ AuIOErr(fmt, ##arg); \
++ AuIOErr(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define AuUnsupportMsg "This operation is not supported." \
+ " Please report this application to aufs-users ML."
-+#define AuUnsupport(fmt, args...) do { \
-+ AuErr(AuUnsupportMsg "\n" fmt, ##args); \
++#define AuUnsupport(fmt, ...) do { \
++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \
+ dump_stack(); \
+} while (0)
+
+ au_dbg_iattr(ia); \
+} while (0)
+#else
-+static inline void au_dbg_verify_dir_parent(struct dentry *dentry,
-+ unsigned int sigen)
-+{
-+ /* empty */
-+}
-+static inline void au_dbg_verify_nondir_parent(struct dentry *dentry,
-+ unsigned int sigen)
-+{
-+ /* empty */
-+}
-+static inline void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
-+{
-+ /* empty */
-+}
-+static inline void au_dbg_verify_hf(struct au_finfo *finfo)
-+{
-+ /* empty */
-+}
-+static inline void au_dbg_verify_kthread(void)
-+{
-+ /* empty */
-+}
++AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen)
++AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry,
++ unsigned int sigen)
++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen)
++AuStubVoid(au_dbg_verify_hf, struct au_finfo *finfo)
++AuStubVoid(au_dbg_verify_kthread, void)
++AuStubInt0(__init au_debug_init, void)
++AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo)
+
-+static inline int au_debug_init(void)
-+{
-+ return 0;
-+}
-+static inline void au_debug_sbinfo_init(struct au_sbinfo *sbinfo)
-+{
-+ /* empty */
-+}
+#define AuDbgWhlist(w) do {} while (0)
+#define AuDbgVdir(v) do {} while (0)
+#define AuDbgInode(i) do {} while (0)
+ handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \
+} while (0)
+#else
-+#define au_dbg_blocked() do {} while (0)
++AuStubVoid(au_dbg_blocked, void)
+#endif
+
+#else
-+static inline int au_sysrq_init(void)
-+{
-+ return 0;
-+}
-+#define au_sysrq_fin() do {} while (0)
-+#define au_dbg_blocked() do {} while (0)
++AuStubInt0(__init au_sysrq_init, void)
++AuStubVoid(au_sysrq_fin, void)
++AuStubVoid(au_dbg_blocked, void)
+#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DEBUG_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c
---- linux-2.6.31-vanilla/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dentry.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,879 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dentry.c linux-2.6.33.1/fs/aufs/dentry.c
+--- linux-2.6.33.1-vanilla/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dentry.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,874 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ path_put(&h_nd.path);
+ }
+
++ AuTraceErrPtr(h_dentry);
+ return h_dentry;
+}
+
+{
+ struct dentry *h_dentry;
+ struct inode *h_inode, *inode;
-+ struct qstr *name;
+ struct au_branch *br;
+ int wh_found, opq;
+ unsigned char wh_able;
+ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
+
-+ name = &dentry->d_name;
+ wh_found = 0;
+ br = au_sbr(dentry->d_sb, bindex);
+ wh_able = !!au_br_whable(br->br_perm);
+ return NULL; /* success */
+
+ real_lookup:
-+ h_dentry = au_lkup_one(name, h_parent, br, args->nd);
++ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd);
+ if (IS_ERR(h_dentry))
+ goto out;
+
+ struct dentry *parent;
+ struct inode *inode;
+
-+ parent = dget_parent(dentry);
+ err = au_test_shwh(dentry->d_sb, name);
+ if (unlikely(err))
+ goto out;
+ au_fset_lkup(args.flags, ALLOW_NEG);
+
+ npositive = 0;
++ parent = dget_parent(dentry);
+ btail = au_dbtaildir(parent);
+ for (bindex = bstart; bindex <= btail; bindex++) {
+ struct dentry *h_parent, *h_dentry;
+ mutex_unlock(&h_dir->i_mutex);
+ err = PTR_ERR(h_dentry);
+ if (IS_ERR(h_dentry))
-+ goto out_wh;
++ goto out_parent;
+ au_fclr_lkup(args.flags, ALLOW_NEG);
+
+ if (au_dbwh(dentry) >= 0)
+ /* both of real entry and whiteout found */
+ err = -EIO;
+
-+ out_wh:
++ out_parent:
++ dput(parent);
+ kfree(whname.name);
+ out:
-+ dput(parent);
+ return err;
+}
+
+{
+ int err;
+ struct dentry *parent, *h_parent, *h_dentry;
-+ struct qstr *name;
+
-+ name = &dentry->d_name;
+ parent = dget_parent(dentry);
+ h_parent = au_h_dptr(parent, bindex);
-+ h_dentry = au_sio_lkup_one(name, h_parent,
++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent,
+ au_sbr(dentry->d_sb, bindex));
+ err = PTR_ERR(h_dentry);
+ if (IS_ERR(h_dentry))
+ goto out;
+ }
+
++ err = 0;
+ if (bindex < au_dbstart(dentry))
+ au_set_dbstart(dentry, bindex);
+ if (au_dbend(dentry) < bindex)
+ au_set_dbend(dentry, bindex);
+ au_set_h_dptr(dentry, bindex, h_dentry);
-+ err = 0;
+
+ out:
+ dput(parent);
+ if (udba == AuOpt_UDBA_REVAL) {
+ IMustLock(h_dir);
+ err = (h_dentry->d_parent->d_inode != h_dir);
-+ } else if (udba == AuOpt_UDBA_HINOTIFY)
++ } else if (udba == AuOpt_UDBA_HNOTIFY)
+ err = au_h_verify_dentry(h_dentry, h_parent, br);
+
+ return err;
+ umode_t mode, h_mode;
+ aufs_bindex_t bindex, btail, bstart, ibs, ibe;
+ unsigned char plus, unhashed, is_root, h_plus;
-+ struct inode *first, *h_inode, *h_cached_inode;
++ struct inode *h_inode, *h_cached_inode;
+ struct dentry *h_dentry;
+ struct qstr *name, *h_name;
+
+ err = 0;
+ plus = 0;
+ mode = 0;
-+ first = NULL;
+ ibs = -1;
+ ibe = -1;
+ unhashed = !!d_unhashed(dentry);
+ if (do_udba && inode) {
+ mode = (inode->i_mode & S_IFMT);
+ plus = (inode->i_nlink > 0);
-+ first = au_h_iptr(inode, au_ibstart(inode));
+ ibs = au_ibstart(inode);
+ ibe = au_ibend(inode);
+ }
+ kfree(dinfo->di_hdentry);
+ AuRwDestroy(&dinfo->di_rwsem);
+ au_cache_free_dinfo(dinfo);
-+ au_hin_di_reinit(dentry);
++ au_hn_di_reinit(dentry);
+}
+
-+struct dentry_operations aufs_dop = {
++const struct dentry_operations aufs_dop = {
+ .d_revalidate = aufs_d_revalidate,
+ .d_release = aufs_d_release
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.h linux-2.6.31/fs/aufs/dentry.h
---- linux-2.6.31-vanilla/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dentry.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,231 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dentry.h linux-2.6.33.1/fs/aufs/dentry.h
+--- linux-2.6.33.1-vanilla/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dentry.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,228 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+/* ---------------------------------------------------------------------- */
+
+/* dentry.c */
-+extern struct dentry_operations aufs_dop;
++extern const struct dentry_operations aufs_dop;
+struct au_branch;
+struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
+ struct au_branch *br, struct nameidata *nd);
+/* lock subclass for dinfo */
+enum {
+ AuLsc_DI_CHILD, /* child first */
-+ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */
++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */
+ AuLsc_DI_CHILD3, /* copyup dirs */
+ AuLsc_DI_PARENT,
+ AuLsc_DI_PARENT2,
+
+/* ---------------------------------------------------------------------- */
+
-+#ifdef CONFIG_AUFS_HINOTIFY
++#ifdef CONFIG_AUFS_HNOTIFY
+static inline void au_digen_dec(struct dentry *d)
+{
+ atomic_dec_return(&au_di(d)->di_generation);
+}
+
-+static inline void au_hin_di_reinit(struct dentry *dentry)
++static inline void au_hn_di_reinit(struct dentry *dentry)
+{
+ dentry->d_fsdata = NULL;
+}
+#else
-+static inline void au_hin_di_reinit(struct dentry *dentry __maybe_unused)
-+{
-+ /* empty */
-+}
-+#endif /* CONFIG_AUFS_HINOTIFY */
++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DENTRY_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dinfo.c linux-2.6.31/fs/aufs/dinfo.c
---- linux-2.6.31-vanilla/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dinfo.c 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dinfo.c linux-2.6.33.1/fs/aufs/dinfo.c
+--- linux-2.6.33.1-vanilla/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dinfo.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,367 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ return bindex;
+ return -1;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c
---- linux-2.6.31-vanilla/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dir.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,593 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dir.c linux-2.6.33.1/fs/aufs/dir.c
+--- linux-2.6.33.1-vanilla/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dir.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,579 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ au_set_h_fptr(file, bindex, NULL);
+ au_set_fbend(file, btail);
+
-+ spin_lock(&file->f_lock);
-+ flags = file->f_flags;
-+ spin_unlock(&file->f_lock);
++ flags = vfsub_file_flags(file);
+ for (bindex = bstart; bindex <= btail; bindex++) {
+ h_dentry = au_h_dptr(dentry, bindex);
+ if (!h_dentry)
+ err = 0;
+ dentry = file->f_dentry;
+ au_set_fvdir_cache(file, NULL);
-+ au_fi(file)->fi_maintain_plink = 0;
+ file->f_version = dentry->d_inode->i_version;
+ bindex = au_dbstart(dentry);
+ au_set_fbstart(file, bindex);
+{
+ struct au_vdir *vdir_cache;
+ struct super_block *sb;
-+ struct au_sbinfo *sbinfo;
+
+ sb = file->f_dentry->d_sb;
-+ si_noflush_read_lock(sb);
-+ fi_write_lock(file);
-+ vdir_cache = au_fvdir_cache(file);
++ vdir_cache = au_fi(file)->fi_vdir_cache; /* lock-free */
+ if (vdir_cache)
+ au_vdir_free(vdir_cache);
-+ if (au_fi(file)->fi_maintain_plink) {
-+ sbinfo = au_sbi(sb);
-+ /* clear the flag without write-lock */
-+ sbinfo->au_si_status &= ~AuSi_MAINTAIN_PLINK;
-+ smp_mb();
-+ wake_up_all(&sbinfo->si_plink_wq);
-+ }
-+ fi_write_unlock(file);
++ au_plink_maint_leave(file);
+ au_finfo_fin(file);
-+ si_read_unlock(sb);
+ return 0;
+}
+
+
+ di_read_unlock(dentry, AuLock_IR);
+ si_read_unlock(sb);
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = au_vdir_fill_de(file, dirent, filldir);
-+ lockdep_on();
++ /* lockdep_on(); */
+ fsstack_copy_attr_atime(inode, h_inode);
+ fi_write_unlock(file);
+
+ .flush = aufs_flush,
+ .fsync = aufs_fsync_dir
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.h linux-2.6.31/fs/aufs/dir.h
---- linux-2.6.31-vanilla/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/dir.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/dir.h linux-2.6.33.1/fs/aufs/dir.h
+--- linux-2.6.33.1-vanilla/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/dir.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,127 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_DIR_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/export.c linux-2.6.31/fs/aufs/export.c
---- linux-2.6.31-vanilla/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/export.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,746 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/export.c linux-2.6.33.1/fs/aufs/export.c
+--- linux-2.6.33.1-vanilla/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/export.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,745 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ parent = path->dentry;
+ if (nsi_lock)
+ si_read_unlock(parent->d_sb);
-+ path_get(path);
-+ file = vfsub_dentry_open(path, au_dir_roflags, current_cred());
++ file = vfsub_dentry_open(path, au_dir_roflags);
+ dentry = (void *)file;
+ if (IS_ERR(file))
+ goto out;
+
+ dentry = ERR_PTR(-ENOMEM);
-+ arg.name = __getname();
++ arg.name = __getname_gfp(GFP_NOFS);
+ if (unlikely(!arg.name))
+ goto out_file;
+ arg.ino = ino;
+ BUILD_BUG_ON(sizeof(u) != sizeof(int));
+ atomic_set(&sbinfo->si_xigen_next, u);
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c
---- linux-2.6.31-vanilla/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/file.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,568 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/file.c linux-2.6.33.1/fs/aufs/file.c
+--- linux-2.6.33.1-vanilla/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/file.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,606 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ struct inode *h_inode;
+ struct super_block *sb;
+ struct au_branch *br;
-+ int err, exec_flag;
+ struct path h_path;
++ int err, exec_flag;
+
+ /* a race condition can happen between open and unlink/rmdir */
+ h_file = ERR_PTR(-ENOENT);
+ atomic_inc(&br->br_count);
+ h_path.dentry = h_dentry;
+ h_path.mnt = br->br_mnt;
-+ path_get(&h_path);
-+ h_file = vfsub_dentry_open(&h_path, flags, current_cred());
++ if (!au_special_file(h_inode->i_mode))
++ h_file = vfsub_dentry_open(&h_path, flags);
++ else {
++ /* this block depends upon the configuration */
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ h_file = vfsub_dentry_open(&h_path, flags);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ }
+ if (IS_ERR(h_file))
+ goto out_br;
+
+int au_do_open(struct file *file, int (*open)(struct file *file, int flags))
+{
+ int err;
-+ unsigned int flags;
+ struct dentry *dentry;
+ struct super_block *sb;
+
+ goto out;
+
+ di_read_lock_child(dentry, AuLock_IR);
-+ spin_lock(&file->f_lock);
-+ flags = file->f_flags;
-+ spin_unlock(&file->f_lock);
-+ err = open(file, flags);
++ err = open(file, vfsub_file_flags(file));
+ di_read_unlock(dentry, AuLock_IR);
+
+ fi_write_unlock(file);
+int au_reopen_nondir(struct file *file)
+{
+ int err;
-+ unsigned int flags;
+ aufs_bindex_t bstart, bindex, bend;
+ struct dentry *dentry;
+ struct file *h_file, *h_file_tmp;
+
+ dentry = file->f_dentry;
++ AuDebugOn(au_special_file(dentry->d_inode->i_mode));
+ bstart = au_dbstart(dentry);
+ h_file_tmp = NULL;
+ if (au_fbstart(file) == bstart) {
+ AuDebugOn(au_fbstart(file) < bstart
+ || au_fi(file)->fi_hfile[0 + bstart].hf_file);
+
-+ spin_lock(&file->f_lock);
-+ flags = file->f_flags & ~O_TRUNC;
-+ spin_unlock(&file->f_lock);
-+ h_file = au_h_open(dentry, bstart, flags, file);
++ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
++ file);
+ err = PTR_ERR(h_file);
+ if (IS_ERR(h_file))
+ goto out; /* todo: close all? */
+ int err;
+ struct inode *inode;
+ struct dentry *dentry, *hi_wh;
-+ struct super_block *sb;
+
+ dentry = file->f_dentry;
++ au_update_dbstart(dentry);
+ inode = dentry->d_inode;
+ hi_wh = au_hi_wh(inode, bcpup);
+ if (!hi_wh)
+ /* already copied-up after unlink */
+ err = au_reopen_wh(file, bcpup, hi_wh);
+
-+ sb = dentry->d_sb;
-+ if (!err && inode->i_nlink > 1 && au_opt_test(au_mntflags(sb), PLINK))
++ if (!err
++ && inode->i_nlink > 1
++ && au_opt_test(au_mntflags(dentry->d_sb), PLINK))
+ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
+
+ return err;
+ struct dentry *dentry, *parent, *h_dentry;
+ struct inode *h_inode, *inode;
+ struct super_block *sb;
++ struct file *h_file;
+
+ dentry = file->f_dentry;
+ sb = dentry->d_sb;
-+ bstart = au_fbstart(file);
+ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
++ bstart = au_fbstart(file);
+ err = au_test_ro(sb, bstart, inode);
+ if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) {
+ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
+ h_dentry = au_h_fptr(file, bstart)->f_dentry;
+ h_inode = h_dentry->d_inode;
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
-+ if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
+ /* || !h_inode->i_nlink */) {
+ err = au_ready_to_write_wh(file, len, bcpup);
+ di_downgrade_lock(parent, AuLock_IR);
+ err = au_reopen_nondir(file);
+ }
+ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
+
+ if (!err) {
+ au_pin_set_parent_lflag(pin, /*lflag*/0);
+ aufs_bindex_t bstart;
+ unsigned char pseudo_link;
+ struct dentry *dentry;
++ struct inode *inode;
+
+ err = 0;
+ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ AuDebugOn(au_special_file(inode->i_mode));
+ sigen = au_sigen(dentry->d_sb);
+ fi_write_lock(file);
+ figen = au_figen(file);
+ di_write_lock_child(dentry);
+ bstart = au_dbstart(dentry);
-+ pseudo_link = (bstart != au_ibstart(dentry->d_inode));
++ pseudo_link = (bstart != au_ibstart(inode));
+ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
+ if (!wlock) {
+ di_downgrade_lock(dentry, AuLock_IR);
+
+ AuDbg("sigen %d, figen %d\n", sigen, figen);
+ if (sigen != au_digen(dentry)
-+ || sigen != au_iigen(dentry->d_inode)) {
++ || sigen != au_iigen(inode)) {
+ err = au_reval_dpath(dentry, sigen);
+ if (unlikely(err < 0))
+ goto out;
+ AuDebugOn(au_digen(dentry) != sigen
-+ || au_iigen(dentry->d_inode) != sigen);
++ || au_iigen(inode) != sigen);
+ }
+
+ err = refresh_file(file, reopen);
+ const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs)
+{ AuUnsupport(); return 0; }
++static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff,
++ int create, void **kmem, unsigned long *pfn)
++{ AuUnsupport(); return 0; }
++static int aufs_migratepage(struct address_space *mapping, struct page *newpage,
++ struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_launder_page(struct page *page)
++{ AuUnsupport(); return 0; }
++static int aufs_is_partially_uptodate(struct page *page,
++ read_descriptor_t *desc,
++ unsigned long from)
++{ AuUnsupport(); return 0; }
++static int aufs_error_remove_page(struct address_space *mapping,
++ struct page *page)
++{ AuUnsupport(); return 0; }
+#endif /* CONFIG_AUFS_DEBUG */
+
-+struct address_space_operations aufs_aop = {
-+ .readpage = aufs_readpage,
++const struct address_space_operations aufs_aop = {
++ .readpage = aufs_readpage,
+#ifdef CONFIG_AUFS_DEBUG
-+ .writepage = aufs_writepage,
-+ .sync_page = aufs_sync_page,
-+ .set_page_dirty = aufs_set_page_dirty,
-+ .write_begin = aufs_write_begin,
-+ .write_end = aufs_write_end,
-+ .invalidatepage = aufs_invalidatepage,
-+ .releasepage = aufs_releasepage,
-+ .direct_IO = aufs_direct_IO,
++ .writepage = aufs_writepage,
++ .sync_page = aufs_sync_page,
++ /* no writepages, because of writepage */
++ .set_page_dirty = aufs_set_page_dirty,
++ /* no readpages, because of readpage */
++ .write_begin = aufs_write_begin,
++ .write_end = aufs_write_end,
++ /* no bmap, no block device */
++ .invalidatepage = aufs_invalidatepage,
++ .releasepage = aufs_releasepage,
++ .direct_IO = aufs_direct_IO, /* todo */
++ .get_xip_mem = aufs_get_xip_mem, /* todo */
++ .migratepage = aufs_migratepage,
++ .launder_page = aufs_launder_page,
++ .is_partially_uptodate = aufs_is_partially_uptodate,
++ .error_remove_page = aufs_error_remove_page
+#endif /* CONFIG_AUFS_DEBUG */
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h
---- linux-2.6.31-vanilla/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/file.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,174 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/file.h linux-2.6.33.1/fs/aufs/file.h
+--- linux-2.6.33.1-vanilla/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/file.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,211 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ struct {
+ struct vm_operations_struct *fi_h_vm_ops;
+ struct vm_operations_struct *fi_vm_ops;
++ struct mutex fi_vm_mtx;
++ struct mutex fi_mmap;
+ };
+
+ /* dir only */
+ struct {
+ struct au_vdir *fi_vdir_cache;
-+ int fi_maintain_plink;
+ };
+ };
+};
+/* ---------------------------------------------------------------------- */
+
+/* file.c */
-+extern struct address_space_operations aufs_aop;
++extern const struct address_space_operations aufs_aop;
+unsigned int au_file_roflags(unsigned int flags);
+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
+ struct file *file);
+unsigned int aufs_poll(struct file *file, poll_table *wait);
+#endif
+
++#ifdef CONFIG_AUFS_BR_HFSPLUS
++/* hfsplus.c */
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex);
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#else
++static inline
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return NULL;
++}
++
++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file);
++#endif
++
+/* f_op.c */
+extern const struct file_operations aufs_file_fop;
+int aufs_flush(struct file *file, fl_owner_t id);
++int au_do_open_nondir(struct file *file, int flags);
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
++
++#ifdef CONFIG_AUFS_SP_IATTR
++/* f_op_sp.c */
++int au_special_file(umode_t mode);
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev);
++#else
++AuStubInt0(au_special_file, umode_t mode)
++static inline void au_init_special_fop(struct inode *inode, umode_t mode,
++ dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++}
++#endif
+
+/* finfo.c */
+void au_hfput(struct au_hfile *hf, struct file *file);
+ struct file *h_file);
+
+void au_update_figen(struct file *file);
++void au_fi_mmap_lock(struct file *file);
++void au_fi_mmap_unlock(struct file *file);
+
+void au_finfo_fin(struct file *file);
+int au_finfo_init(struct file *file);
+int au_fi_realloc(struct au_finfo *finfo, int nbr);
+
++/* ioctl.c */
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
++
+/* ---------------------------------------------------------------------- */
+
+static inline struct au_finfo *au_fi(struct file *file)
+
+static inline int au_test_mmapped(struct file *f)
+{
-+ /* FiMustAnyLock(f); */
++ FiMustAnyLock(f);
+ return !!(au_fi(f)->fi_h_vm_ops);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FILE_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/finfo.c linux-2.6.31/fs/aufs/finfo.c
---- linux-2.6.31-vanilla/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/finfo.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,128 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/finfo.c linux-2.6.33.1/fs/aufs/finfo.c
+--- linux-2.6.33.1-vanilla/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/finfo.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,146 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+void au_hfput(struct au_hfile *hf, struct file *file)
+{
-+ if (file->f_flags & vfsub_fmode_to_uint(FMODE_EXEC))
++ /* todo: direct access f_flags */
++ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC))
+ allow_write_access(hf->hf_file);
+ fput(hf->hf_file);
+ hf->hf_file = NULL;
+ if (hf->hf_file)
+ au_hfput(hf, file);
+ if (val) {
++ FiMustWriteLock(file);
+ hf->hf_file = val;
+ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex);
+ }
+
+/* ---------------------------------------------------------------------- */
+
++void au_fi_mmap_lock(struct file *file)
++{
++ FiMustWriteLock(file);
++ lockdep_off();
++ mutex_lock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++void au_fi_mmap_unlock(struct file *file)
++{
++ lockdep_off();
++ mutex_unlock(&au_fi(file)->fi_mmap);
++ lockdep_on();
++}
++
++/* ---------------------------------------------------------------------- */
++
+void au_finfo_fin(struct file *file)
+{
+ struct au_finfo *finfo;
+ aufs_bindex_t bindex, bend;
+
-+ fi_write_lock(file);
-+ bend = au_fbend(file);
-+ bindex = au_fbstart(file);
-+ if (bindex >= 0)
++ finfo = au_fi(file);
++ bindex = finfo->fi_bstart;
++ if (bindex >= 0) {
+ /*
+ * calls fput() instead of filp_close(),
+ * since no dnotify or lock for the lower file.
+ */
++ bend = finfo->fi_bend;
+ for (; bindex <= bend; bindex++)
+ au_set_h_fptr(file, bindex, NULL);
++ }
+
-+ finfo = au_fi(file);
+ au_dbg_verify_hf(finfo);
+ kfree(finfo->fi_hfile);
-+ fi_write_unlock(file);
+ AuRwDestroy(&finfo->fi_rwsem);
+ au_cache_free_finfo(finfo);
+}
+
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c
---- linux-2.6.31-vanilla/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/f_op.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,823 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/f_op.c linux-2.6.33.1/fs/aufs/f_op.c
+--- linux-2.6.33.1-vanilla/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/f_op.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,921 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#include <linux/file.h>
+#include <linux/fs_stack.h>
-+#include <linux/ima.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/security.h>
+
+/* ---------------------------------------------------------------------- */
+
-+static int do_open_nondir(struct file *file, int flags)
++int au_do_open_nondir(struct file *file, int flags)
+{
+ int err;
+ aufs_bindex_t bindex;
+ finfo = au_fi(file);
+ finfo->fi_h_vm_ops = NULL;
+ finfo->fi_vm_ops = NULL;
++ mutex_init(&finfo->fi_mmap); /* regular file only? */
+ bindex = au_dbstart(dentry);
-+ /* O_TRUNC is processed already */
-+ BUG_ON(au_test_ro(dentry->d_sb, bindex, dentry->d_inode)
-+ && (flags & O_TRUNC));
-+
+ h_file = au_h_open(dentry, bindex, flags, file);
+ if (IS_ERR(h_file))
+ err = PTR_ERR(h_file);
+static int aufs_open_nondir(struct inode *inode __maybe_unused,
+ struct file *file)
+{
-+ return au_do_open(file, do_open_nondir);
++ AuDbg("%.*s, f_ flags 0x%x, f_mode 0x%x\n",
++ AuDLNPair(file->f_dentry), vfsub_file_flags(file),
++ file->f_mode);
++ return au_do_open(file, au_do_open_nondir);
+}
+
-+static int aufs_release_nondir(struct inode *inode __maybe_unused,
-+ struct file *file)
++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file)
+{
-+ struct super_block *sb = file->f_dentry->d_sb;
-+
-+ si_noflush_read_lock(sb);
+ kfree(au_fi(file)->fi_vm_ops);
+ au_finfo_fin(file);
-+ si_read_unlock(sb);
+ return 0;
+}
+
+ return err;
+}
+
++static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio,
++ const struct iovec *iov, unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file;
++
++ err = security_file_permission(h_file, rw);
++ if (unlikely(err))
++ goto out;
++
++ file = kio->ki_filp;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ if (rw == MAY_READ)
++ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ else if (rw == MAY_WRITE)
++ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ else
++ BUG();
++ /* do not restore kio->ki_filp */
++
++ out:
++ return err;
++}
++
+static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov,
+ unsigned long nv, loff_t pos)
+{
+ err = -ENOSYS;
+ h_file = au_h_fptr(file, au_fbstart(file));
+ if (h_file->f_op && h_file->f_op->aio_read) {
-+ err = security_file_permission(h_file, MAY_READ);
-+ if (unlikely(err))
-+ goto out_unlock;
-+ if (!is_sync_kiocb(kio)) {
-+ get_file(h_file);
-+ fput(file);
-+ }
-+ kio->ki_filp = h_file;
-+ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos);
+ /* todo: necessary? */
+ /* file->f_ra = h_file->f_ra; */
+ fsstack_copy_attr_atime(dentry->d_inode,
+ /* currently there is no such fs */
+ WARN_ON_ONCE(h_file->f_op && h_file->f_op->read);
+
-+ out_unlock:
+ di_read_unlock(dentry, AuLock_IR);
+ fi_read_unlock(file);
++
+ out:
+ si_read_unlock(sb);
+ return err;
+ unsigned long nv, loff_t pos)
+{
+ ssize_t err;
-+ aufs_bindex_t bstart;
+ struct au_pin pin;
+ struct dentry *dentry;
+ struct inode *inode;
+ goto out_unlock;
+
+ err = -ENOSYS;
-+ bstart = au_fbstart(file);
-+ h_file = au_h_fptr(file, bstart);
++ h_file = au_h_fptr(file, au_fbstart(file));
+ au_unpin(&pin);
+ if (h_file->f_op && h_file->f_op->aio_write) {
-+ err = security_file_permission(h_file, MAY_WRITE);
-+ if (unlikely(err))
-+ goto out_unlock;
-+ if (!is_sync_kiocb(kio)) {
-+ get_file(h_file);
-+ fput(file);
-+ }
-+ kio->ki_filp = h_file;
-+ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos);
+ au_cpup_attr_timesizes(inode);
+ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
+ } else
+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
+
-+ fi_write_lock(file);
++ mutex_lock(&finfo->fi_vm_mtx);
+ vma->vm_file = h_file;
+ err = finfo->fi_h_vm_ops->fault(vma, vmf);
+ /* todo: necessary? */
+ /* file->f_ra = h_file->f_ra; */
+ au_reset_file(vma, file);
-+ fi_write_unlock(file);
++ mutex_unlock(&finfo->fi_vm_mtx);
+#if 0 /* def CONFIG_SMP */
+ /* wake_up_nr(&wq, online_cpu - 1); */
+ wake_up_all(&wq);
+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
+
-+ fi_write_lock(file);
++ mutex_lock(&finfo->fi_vm_mtx);
+ vma->vm_file = h_file;
+ err = finfo->fi_h_vm_ops->page_mkwrite(vma, vmf);
+ au_reset_file(vma, file);
-+ fi_write_unlock(file);
++ mutex_unlock(&finfo->fi_vm_mtx);
+ wake_up(&wq);
+
+ return err;
+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
+
-+ fi_write_lock(file);
++ mutex_lock(&finfo->fi_vm_mtx);
+ vma->vm_file = h_file;
+ finfo->fi_h_vm_ops->close(vma);
+ au_reset_file(vma, file);
-+ fi_write_unlock(file);
++ mutex_unlock(&finfo->fi_vm_mtx);
+ wake_up(&wq);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
-+static unsigned long au_prot_conv(unsigned long flags)
-+{
-+ unsigned long prot;
++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */
++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b)
+
-+ prot = 0;
-+ if (flags & VM_READ)
-+ prot |= PROT_READ;
-+ if (flags & VM_WRITE)
-+ prot |= PROT_WRITE;
-+ if (flags & VM_EXEC)
-+ prot |= PROT_EXEC;
-+ return prot;
++static unsigned long au_arch_prot_conv(unsigned long flags)
++{
++ /* currently ppc64 only */
++#ifdef CONFIG_PPC64
++ /* cf. linux/arch/powerpc/include/asm/mman.h */
++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO);
++ return AuConv_VM_PROT(flags, SAO);
++#else
++ AuDebugOn(arch_calc_vm_prot_bits(-1));
++ return 0;
++#endif
+}
+
-+static struct vm_operations_struct *au_vm_ops(struct file *h_file,
++static unsigned long au_prot_conv(unsigned long flags)
++{
++ return AuConv_VM_PROT(flags, READ)
++ | AuConv_VM_PROT(flags, WRITE)
++ | AuConv_VM_PROT(flags, EXEC)
++ | au_arch_prot_conv(flags);
++}
++
++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */
++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b)
++
++static unsigned long au_flag_conv(unsigned long flags)
++{
++ return AuConv_VM_MAP(flags, GROWSDOWN)
++ | AuConv_VM_MAP(flags, DENYWRITE)
++ | AuConv_VM_MAP(flags, EXECUTABLE)
++ | AuConv_VM_MAP(flags, LOCKED);
++}
++
++static struct vm_operations_struct *au_vm_ops(struct file *h_file,
+ struct vm_area_struct *vma)
+{
+ struct vm_operations_struct *vm_ops;
++ unsigned long prot;
+ int err;
+
+ vm_ops = ERR_PTR(-ENODEV);
+ if (!h_file->f_op || !h_file->f_op->mmap)
+ goto out;
+
-+ err = ima_file_mmap(h_file, au_prot_conv(vma->vm_flags));
++ prot = au_prot_conv(vma->vm_flags);
++ err = security_file_mmap(h_file, /*reqprot*/prot, prot,
++ au_flag_conv(vma->vm_flags), vma->vm_start, 0);
+ vm_ops = ERR_PTR(err);
-+ if (err)
++ if (unlikely(err))
+ goto out;
+
+ err = h_file->f_op->mmap(h_file, vma);
+ if (unlikely(err))
+ goto out;
+
-+ vm_ops = vma->vm_ops;
++ /* oops, it became 'const' */
++ vm_ops = (struct vm_operations_struct *)vma->vm_ops;
+ err = do_munmap(current->mm, vma->vm_start,
+ vma->vm_end - vma->vm_start);
+ if (unlikely(err)) {
+ int err;
+ struct vm_operations_struct *h_ops;
+
-+ AuRwMustAnyLock(&finfo->fi_rwsem);
++ MtxMustLock(&finfo->fi_mmap);
+
+ err = 0;
+ h_ops = finfo->fi_h_vm_ops;
+ return err;
+}
+
-+static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++/*
++ * This is another ugly approach to keep the lock order, particularly
++ * mm->mmap_sem and aufs rwsem. The previous approach was reverted and you can
++ * find it in git-log, if you want.
++ *
++ * native readdir: i_mutex, copy_to_user, mmap_sem
++ * aufs readdir: i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
++ *
++ * Before aufs_mmap() mmap_sem is acquired already, but aufs_mmap() has to
++ * acquire aufs rwsem. It introduces a circular locking dependency.
++ * To address this problem, aufs_mmap() delegates the part which requires aufs
++ * rwsem to its internal workqueue.
++ */
++
++/* very ugly approach */
++#ifdef CONFIG_DEBUG_MUTEXES
++#include <../kernel/mutex-debug.h>
++#else
++#include <../kernel/mutex.h>
++#endif
++
++struct au_mmap_pre_args {
++ /* input */
++ struct file *file;
++ struct vm_area_struct *vma;
++
++ /* output */
++ int *errp;
++ struct file *h_file;
++ int mmapped;
++};
++
++static int au_mmap_pre(struct file *file, struct vm_area_struct *vma,
++ struct file **h_file, int *mmapped)
+{
+ int err;
-+ unsigned char wlock, mmapped;
++ const unsigned char wlock
++ = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+ struct dentry *dentry;
+ struct super_block *sb;
-+ struct file *h_file;
-+ struct vm_operations_struct *vm_ops;
+
+ dentry = file->f_dentry;
-+ wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+ sb = dentry->d_sb;
-+ si_read_lock(sb, AuLock_FLUSH);
++ si_read_lock(sb, !AuLock_FLUSH);
+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ if (unlikely(err))
+ goto out;
+
-+ mmapped = !!au_test_mmapped(file);
++ *mmapped = !!au_test_mmapped(file);
+ if (wlock) {
+ struct au_pin pin;
+
+ err = au_ready_to_write(file, -1, &pin);
-+ di_downgrade_lock(dentry, AuLock_IR);
++ di_write_unlock(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ au_unpin(&pin);
+ } else
-+ di_downgrade_lock(dentry, AuLock_IR);
++ di_write_unlock(dentry);
++ *h_file = au_h_fptr(file, au_fbstart(file));
++ get_file(*h_file);
++ au_fi_mmap_lock(file);
+
-+ h_file = au_h_fptr(file, au_fbstart(file));
-+ if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) {
++out_unlock:
++ fi_write_unlock(file);
++out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static void au_call_mmap_pre(void *args)
++{
++ struct au_mmap_pre_args *a = args;
++ *a->errp = au_mmap_pre(a->file, a->vma, &a->h_file, &a->mmapped);
++}
++
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int err, wkq_err;
++ struct au_finfo *finfo;
++ struct dentry *h_dentry;
++ struct vm_operations_struct *vm_ops;
++ struct au_mmap_pre_args args = {
++ .file = file,
++ .vma = vma,
++ .errp = &err
++ };
++
++ wkq_err = au_wkq_wait(au_call_mmap_pre, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ if (unlikely(err))
++ goto out;
++ finfo = au_fi(file);
++ mutex_set_owner(&finfo->fi_mmap);
++
++ h_dentry = args.h_file->f_dentry;
++ if (!args.mmapped && au_test_fs_bad_mapping(h_dentry->d_sb)) {
+ /*
+ * by this assignment, f_mapping will differs from aufs inode
+ * i_mapping.
+ * if someone else mixes the use of f_dentry->d_inode and
+ * f_mapping->host, then a problem may arise.
+ */
-+ file->f_mapping = h_file->f_mapping;
++ file->f_mapping = args.h_file->f_mapping;
+ }
+
+ vm_ops = NULL;
-+ if (!mmapped) {
-+ vm_ops = au_vm_ops(h_file, vma);
++ if (!args.mmapped) {
++ vm_ops = au_vm_ops(args.h_file, vma);
+ err = PTR_ERR(vm_ops);
+ if (IS_ERR(vm_ops))
+ goto out_unlock;
+ goto out_unlock;
+
+ vma->vm_ops = &aufs_vm_ops;
-+ /* test again */
-+ if (!au_test_mmapped(file))
-+ au_fi(file)->fi_h_vm_ops = vm_ops;
++ if (!args.mmapped) {
++ finfo->fi_h_vm_ops = vm_ops;
++ mutex_init(&finfo->fi_vm_mtx);
++ }
+
-+ err = au_custom_vm_ops(au_fi(file), vma);
++ err = au_custom_vm_ops(finfo, vma);
+ if (unlikely(err))
+ goto out_unlock;
+
-+ vfsub_file_accessed(h_file);
-+ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++ vfsub_file_accessed(args.h_file);
++ /* update without lock, I don't think it a problem */
++ fsstack_copy_attr_atime(file->f_dentry->d_inode, h_dentry->d_inode);
+
+ out_unlock:
-+ di_read_unlock(dentry, AuLock_IR);
-+ fi_write_unlock(file);
++ au_fi_mmap_unlock(file);
++ fput(args.h_file);
+ out:
-+ si_read_unlock(sb);
+ return err;
+}
+
+#ifdef CONFIG_AUFS_POLL
+ .poll = aufs_poll,
+#endif
++ .unlocked_ioctl = aufs_ioctl_nondir,
+ .mmap = aufs_mmap,
+ .open = aufs_open_nondir,
+ .flush = aufs_flush,
+ .aio_splice_read = aufs_aio_splice_read
+#endif
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.h
---- linux-2.6.31-vanilla/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/fstype.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,485 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/f_op_sp.c linux-2.6.33.1/fs/aufs/f_op_sp.c
+--- linux-2.6.33.1-vanilla/fs/aufs/f_op_sp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/f_op_sp.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,290 @@
++/*
++ * Copyright (C) 2005-2010 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 operations for special files.
++ * while they exist in aufs virtually,
++ * their file I/O is handled out of aufs.
++ */
++
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct file *file, *h_file;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_h_fptr(file, bstart);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read);
++ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_accessed(h_file);
++
++ return err;
++}
++
++static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ unsigned char wbr;
++ struct super_block *sb;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ fi_read_lock(file);
++ bstart = au_fbstart(file);
++ h_file = au_h_fptr(file, bstart);
++ fi_read_unlock(file);
++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
++ si_read_unlock(sb);
++
++ /* do not change the file in kio */
++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write);
++ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ if (err > 0 && wbr)
++ file_update_time(h_file);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_release_sp(struct inode *inode, struct file *file)
++{
++ int err;
++ struct file *h_file;
++
++ fi_read_lock(file);
++ h_file = au_h_fptr(file, au_fbstart(file));
++ fi_read_unlock(file);
++ /* close this fifo in aufs */
++ err = h_file->f_op->release(inode, file); /* ignore */
++ aufs_release_nondir(inode, file); /* ignore */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* currently, support only FIFO */
++enum {AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW,
++ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */
++ AuSp_Last};
++static int aufs_open_sp(struct inode *inode, struct file *file);
++static struct au_sp_fop {
++ int done;
++ struct file_operations fop; /* not 'const' */
++ spinlock_t spin;
++} au_sp_fop[AuSp_Last] = {
++ [AuSp_FIFO] = {
++ .fop = {
++ .open = aufs_open_sp
++ }
++ }
++};
++
++static void au_init_fop_sp(struct file *file)
++{
++ struct au_sp_fop *p;
++ int i;
++ struct file *h_file;
++
++ p = au_sp_fop;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ static DEFINE_SPINLOCK(spin);
++
++ spin_lock(&spin);
++ if (!p->done) {
++ BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop)
++ != AuSp_Last);
++ for (i = 0; i < AuSp_Last; i++)
++ spin_lock_init(&p[i].spin);
++ p->done = 1;
++ }
++ spin_unlock(&spin);
++ }
++
++ switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
++ case FMODE_READ:
++ i = AuSp_FIFO_R;
++ break;
++ case FMODE_WRITE:
++ i = AuSp_FIFO_W;
++ break;
++ case FMODE_READ | FMODE_WRITE:
++ i = AuSp_FIFO_RW;
++ break;
++ default:
++ BUG();
++ }
++
++ p += i;
++ if (unlikely(!p->done)) {
++ /* initialize first time only */
++ h_file = au_h_fptr(file, au_fbstart(file));
++ spin_lock(&p->spin);
++ if (!p->done) {
++ p->fop = *h_file->f_op;
++ if (p->fop.aio_read)
++ p->fop.aio_read = aufs_aio_read_sp;
++ if (p->fop.aio_write)
++ p->fop.aio_write = aufs_aio_write_sp;
++ p->fop.release = aufs_release_sp;
++ p->done = 1;
++ }
++ spin_unlock(&p->spin);
++ }
++ file->f_op = &p->fop;
++}
++
++static int au_cpup_sp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bcpup;
++ struct au_pin pin;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ di_read_unlock(dentry, AuLock_IR);
++ di_write_lock_child(dentry);
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out;
++ bcpup = err;
++ err = 0;
++ if (bcpup == au_dbstart(dentry))
++ goto out; /* success */
++
++ err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb),
++ AuPin_MNT_WRITE);
++ if (!err) {
++ err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME);
++ au_unpin(&pin);
++ }
++
++ out:
++ di_downgrade_lock(dentry, AuLock_IR);
++ return err;
++}
++
++static int au_do_open_sp(struct file *file, int flags)
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct file *h_file;
++ struct inode *h_inode;
++
++ dentry = file->f_dentry;
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
++ /*
++ * try copying-up.
++ * operate on the ro branch is not an error.
++ */
++ au_cpup_sp(dentry); /* ignore */
++
++ /* prepare h_file */
++ err = au_do_open_nondir(file, vfsub_file_flags(file));
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ h_file = au_h_fptr(file, au_fbstart(file));
++ h_inode = h_file->f_dentry->d_inode;
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ si_read_unlock(sb);
++ /* open this fifo in aufs */
++ err = h_inode->i_fop->open(file->f_dentry->d_inode, file);
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ di_read_lock_child(dentry, AuLock_IR);
++ if (!err)
++ au_init_fop_sp(file);
++ else
++ au_finfo_fin(file);
++
++ out:
++ return err;
++}
++
++static int aufs_open_sp(struct inode *inode, struct file *file)
++{
++ return au_do_open(file, au_do_open_sp);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev)
++{
++ init_special_inode(inode, mode, rdev);
++
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++ inode->i_fop = &au_sp_fop[AuSp_FIFO].fop;
++ /*FALLTHROUGH*/
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++ break;
++ default:
++ AuDebugOn(1);
++ }
++}
++
++int au_special_file(umode_t mode)
++{
++ int ret;
++
++ ret = 0;
++ switch (mode & S_IFMT) {
++ case S_IFIFO:
++#if 0
++ case S_IFCHR:
++ case S_IFBLK:
++ case S_IFSOCK:
++#endif
++ ret = 1;
++ }
++
++ return ret;
++}
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/fstype.h linux-2.6.33.1/fs/aufs/fstype.h
+--- linux-2.6.33.1-vanilla/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/fstype.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,497 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#ifdef __KERNEL__
+
-+#include <linux/cramfs_fs.h>
+#include <linux/fs.h>
+#include <linux/magic.h>
+#include <linux/romfs_fs.h>
+#endif
+}
+
-+/* ---------------------------------------------------------------------- */
++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE)
++ return sb->s_magic == HFSPLUS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
+/*
+ * they can't be an aufs branch.
+ */
+static inline int au_test_fs_bad_iattr_size(struct super_block *sb)
+{
+ return au_test_xfs(sb)
++ || au_test_btrfs(sb)
++ || au_test_ubifs(sb)
++ || au_test_hfsplus(sb) /* maintained, but incorrect */
+ /* || au_test_ext4(sb) */ /* untested */
+ /* || au_test_ocfs2(sb) */ /* untested */
+ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */
+ /* || au_test_sysv(sb) */ /* untested */
-+ /* || au_test_ubifs(sb) */ /* untested */
+ /* || au_test_minix(sb) */ /* untested */
+ ;
+}
+#ifdef CONFIG_AUFS_BR_RAMFS
+ || au_test_ramfs(sb)
+#endif
-+ || au_test_ubifs(sb);
++ || au_test_ubifs(sb)
++ || au_test_btrfs(sb)
++ || au_test_hfsplus(sb);
+}
+
+/*
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_FSTYPE_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify.c
---- linux-2.6.31-vanilla/fs/aufs/hinotify.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/hinotify.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,755 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/hfsnotify.c linux-2.6.33.1/fs/aufs/hfsnotify.c
+--- linux-2.6.33.1-vanilla/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/hfsnotify.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,230 @@
++/*
++ * Copyright (C) 2005-2010 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
++ */
++
++/*
++ * fsnotify for the lower directories
++ */
++
++#include "aufs.h"
++
++/* FS_IN_IGNORED is unnecessary */
++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
++ | FS_CREATE | FS_EVENT_ON_CHILD);
++static struct fsnotify_group *au_hfsn_group;
++
++static void au_hfsn_free_mark(struct fsnotify_mark_entry *entry)
++{
++#if 0
++ struct au_hnotify *hn = container_of(entry, struct au_hnotify,
++ hn_entry);
++ au_cache_free_hnotify(hn);
++#endif
++ AuDbg("here\n");
++}
++
++static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode)
++{
++ struct fsnotify_mark_entry *entry;
++
++ entry = &hn->hn_entry;
++ fsnotify_init_mark(entry, au_hfsn_free_mark);
++ entry->mask = AuHfsnMask;
++ return fsnotify_add_mark(entry, au_hfsn_group, h_inode);
++}
++
++static void au_hfsn_free(struct au_hnotify *hn)
++{
++ struct fsnotify_mark_entry *entry;
++
++ entry = &hn->hn_entry;
++ fsnotify_destroy_mark_by_entry(entry);
++ fsnotify_put_mark(entry);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set)
++{
++ struct fsnotify_mark_entry *entry;
++
++ entry = &hinode->hi_notify->hn_entry;
++ spin_lock(&entry->lock);
++ if (do_set) {
++ AuDebugOn(entry->mask & AuHfsnMask);
++ entry->mask |= AuHfsnMask;
++ } else {
++ AuDebugOn(!(entry->mask & AuHfsnMask));
++ entry->mask &= ~AuHfsnMask;
++ }
++ spin_unlock(&entry->lock);
++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* #define AuDbgHnotify */
++#ifdef AuDbgHnotify
++static char *au_hfsn_name(u32 mask)
++{
++#ifdef CONFIG_AUFS_DEBUG
++#define test_ret(flag) if (mask & flag) \
++ return #flag;
++ test_ret(FS_ACCESS);
++ test_ret(FS_MODIFY);
++ test_ret(FS_ATTRIB);
++ test_ret(FS_CLOSE_WRITE);
++ test_ret(FS_CLOSE_NOWRITE);
++ test_ret(FS_OPEN);
++ test_ret(FS_MOVED_FROM);
++ test_ret(FS_MOVED_TO);
++ test_ret(FS_CREATE);
++ test_ret(FS_DELETE);
++ test_ret(FS_DELETE_SELF);
++ test_ret(FS_MOVE_SELF);
++ test_ret(FS_UNMOUNT);
++ test_ret(FS_Q_OVERFLOW);
++ test_ret(FS_IN_IGNORED);
++ test_ret(FS_IN_ISDIR);
++ test_ret(FS_IN_ONESHOT);
++ test_ret(FS_EVENT_ON_CHILD);
++ return "";
++#undef test_ret
++#else
++ return "??";
++#endif
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int au_hfsn_handle_event(struct fsnotify_group *group,
++ struct fsnotify_event *event)
++{
++ int err;
++ struct au_hnotify *hnotify;
++ struct inode *h_dir, *h_inode;
++ __u32 mask;
++ struct fsnotify_mark_entry *entry;
++ struct qstr h_child_qstr = {
++ .name = event->file_name,
++ .len = event->name_len
++ };
++
++ AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE);
++
++ err = 0;
++ /* if IN_UNMOUNT happens, there must be another bug */
++ mask = event->mask;
++ AuDebugOn(mask & FS_UNMOUNT);
++ if (mask & (IN_IGNORED | IN_UNMOUNT))
++ goto out;
++
++ h_dir = event->to_tell;
++ h_inode = event->inode;
++#ifdef AuDbgHnotify
++ au_debug(1);
++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1
++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) {
++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n",
++ h_dir->i_ino, mask, au_hfsn_name(mask),
++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0);
++ /* WARN_ON(1); */
++ }
++ au_debug(0);
++#endif
++
++ spin_lock(&h_dir->i_lock);
++ entry = fsnotify_find_mark_entry(group, h_dir);
++ spin_unlock(&h_dir->i_lock);
++ if (entry) {
++ hnotify = container_of(entry, struct au_hnotify, hn_entry);
++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode);
++ fsnotify_put_mark(entry);
++ }
++
++out:
++ return err;
++}
++
++/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
++/* it should be exported to modules */
++static bool au_hfsn_should_send_event(struct fsnotify_group *group,
++ struct inode *h_inode, __u32 mask)
++{
++ struct fsnotify_mark_entry *entry;
++ bool send;
++
++ spin_lock(&h_inode->i_lock);
++ entry = fsnotify_find_mark_entry(group, h_inode);
++ spin_unlock(&h_inode->i_lock);
++ if (!entry)
++ return false;
++
++ mask = (mask & ~FS_EVENT_ON_CHILD);
++ send = (entry->mask & mask);
++
++ /* find took a reference */
++ fsnotify_put_mark(entry);
++
++ return send;
++}
++
++static struct fsnotify_ops au_hfsn_ops = {
++ .should_send_event = au_hfsn_should_send_event,
++ .handle_event = au_hfsn_handle_event
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int __init au_hfsn_init(void)
++{
++ int err;
++ unsigned int gn;
++ const unsigned int gn_max = 10;
++
++ gn = 0;
++ for (gn = 0; gn < gn_max; gn++) {
++ au_hfsn_group = fsnotify_obtain_group(gn, AuHfsnMask,
++ &au_hfsn_ops);
++ if (au_hfsn_group != ERR_PTR(-EEXIST))
++ break;
++ }
++
++ err = 0;
++ if (IS_ERR(au_hfsn_group)) {
++ pr_err("fsnotify_obtain_group() failed %u times\n", gn_max);
++ err = PTR_ERR(au_hfsn_group);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++static void au_hfsn_fin(void)
++{
++ fsnotify_put_group(au_hfsn_group);
++}
++
++const struct au_hnotify_op au_hnotify_op = {
++ .ctl = au_hfsn_ctl,
++ .alloc = au_hfsn_alloc,
++ .free = au_hfsn_free,
++
++ .fin = au_hfsn_fin,
++ .init = au_hfsn_init
++};
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/hfsplus.c linux-2.6.33.1/fs/aufs/hfsplus.c
+--- linux-2.6.33.1-vanilla/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/hfsplus.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,58 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2010 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
+ */
+
+/*
-+ * inotify for the lower directories
++ * special support for filesystems which aqucires an inode mutex
++ * at final closing a file, eg, hfsplus.
++ *
++ * This trick is very simple and stupid, just to open the file before really
++ * neceeary open to tell hfsplus that this is not the final closing.
++ * The caller should call au_h_open_pre() after acquiring the inode mutex,
++ * and au_h_open_post() after releasing it.
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ AuDebugOn(!h_dentry);
++ AuDebugOn(!h_dentry->d_inode);
++ IMustLock(h_dentry->d_inode);
++
++ h_file = NULL;
++ if (au_test_hfsplus(h_dentry->d_sb)
++ && S_ISREG(h_dentry->d_inode->i_mode))
++ h_file = au_h_open(dentry, bindex,
++ O_RDONLY | O_NOATIME | O_LARGEFILE,
++ /*file*/NULL);
++ return h_file;
++}
++
++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex,
++ struct file *h_file)
++{
++ if (h_file) {
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, bindex);
++ }
++}
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/hinotify.c linux-2.6.33.1/fs/aufs/hinotify.c
+--- linux-2.6.33.1-vanilla/fs/aufs/hinotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/hinotify.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,227 @@
++/*
++ * Copyright (C) 2005-2010 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
++ */
++
++/*
++ * inotify for the lower directories (deprecated)
+ */
+
+#include "aufs.h"
+static const __u32 AuHinMask = (IN_MOVE | IN_DELETE | IN_CREATE);
+static struct inotify_handle *au_hin_handle;
+
-+AuCacheFuncs(hinotify, HINOTIFY);
++/* ---------------------------------------------------------------------- */
+
-+int au_hin_alloc(struct au_hinode *hinode, struct inode *inode,
-+ struct inode *h_inode)
++static int au_hin_alloc(struct au_hnotify *hn, struct inode *h_inode)
+{
+ int err;
-+ struct au_hinotify *hin;
+ s32 wd;
++ struct inotify_watch *watch;
+
-+ err = -ENOMEM;
-+ hin = au_cache_alloc_hinotify();
-+ if (hin) {
-+ AuDebugOn(hinode->hi_notify);
-+ hinode->hi_notify = hin;
-+ hin->hin_aufs_inode = inode;
-+
-+ inotify_init_watch(&hin->hin_watch);
-+ wd = inotify_add_watch(au_hin_handle, &hin->hin_watch, h_inode,
-+ AuHinMask);
-+ if (wd >= 0)
-+ return 0; /* success */
++ err = -EEXIST;
++ wd = inotify_find_watch(au_hin_handle, h_inode, &watch);
++ if (wd >= 0) {
++ put_inotify_watch(watch);
++ goto out;
++ }
+
++ err = 0;
++ inotify_init_watch(&hn->hn_watch);
++ wd = inotify_add_watch(au_hin_handle, &hn->hn_watch, h_inode,
++ AuHinMask);
++ if (unlikely(wd < 0)) {
+ err = wd;
-+ put_inotify_watch(&hin->hin_watch);
-+ au_cache_free_hinotify(hin);
-+ hinode->hi_notify = NULL;
++ put_inotify_watch(&hn->hn_watch);
+ }
+
++out:
+ return err;
+}
+
-+void au_hin_free(struct au_hinode *hinode)
++static void au_hin_free(struct au_hnotify *hn)
+{
+ int err;
-+ struct au_hinotify *hin;
+
-+ hin = hinode->hi_notify;
-+ if (hin) {
-+ err = 0;
-+ if (atomic_read(&hin->hin_watch.count))
-+ err = inotify_rm_watch(au_hin_handle, &hin->hin_watch);
-+ if (unlikely(err))
-+ /* it means the watch is already removed */
-+ AuWarn("failed inotify_rm_watch() %d\n", err);
-+ au_cache_free_hinotify(hin);
-+ hinode->hi_notify = NULL;
-+ }
++ err = 0;
++ if (atomic_read(&hn->hn_watch.count))
++ err = inotify_rm_watch(au_hin_handle, &hn->hn_watch);
++ if (unlikely(err))
++ /* it means the watch is already removed */
++ pr_warning("failed inotify_rm_watch() %d\n", err);
+}
+
+/* ---------------------------------------------------------------------- */
+
-+void au_hin_ctl(struct au_hinode *hinode, int do_set)
++static void au_hin_ctl(struct au_hinode *hinode, int do_set)
+{
+ struct inode *h_inode;
+ struct inotify_watch *watch;
+
-+ if (!hinode->hi_notify)
-+ return;
-+
+ h_inode = hinode->hi_inode;
+ IMustLock(h_inode);
+
+ /* todo: try inotify_find_update_watch()? */
-+ watch = &hinode->hi_notify->hin_watch;
++ watch = &hinode->hi_notify->hn_watch;
+ mutex_lock(&h_inode->inotify_mutex);
+ /* mutex_lock(&watch->ih->mutex); */
+ if (do_set) {
+ mutex_unlock(&h_inode->inotify_mutex);
+}
+
-+void au_reset_hinotify(struct inode *inode, unsigned int flags)
++/* ---------------------------------------------------------------------- */
++
++#ifdef AuDbgHnotify
++static char *in_name(u32 mask)
++{
++#ifdef CONFIG_AUFS_DEBUG
++#define test_ret(flag) if (mask & flag) \
++ return #flag;
++ test_ret(IN_ACCESS);
++ test_ret(IN_MODIFY);
++ test_ret(IN_ATTRIB);
++ test_ret(IN_CLOSE_WRITE);
++ test_ret(IN_CLOSE_NOWRITE);
++ test_ret(IN_OPEN);
++ test_ret(IN_MOVED_FROM);
++ test_ret(IN_MOVED_TO);
++ test_ret(IN_CREATE);
++ test_ret(IN_DELETE);
++ test_ret(IN_DELETE_SELF);
++ test_ret(IN_MOVE_SELF);
++ test_ret(IN_UNMOUNT);
++ test_ret(IN_Q_OVERFLOW);
++ test_ret(IN_IGNORED);
++ return "";
++#undef test_ret
++#else
++ return "??";
++#endif
++}
++#endif
++
++static u32 au_hin_conv_mask(u32 mask)
++{
++ u32 conv;
++
++ conv = 0;
++#define do_conv(flag) conv |= (mask & IN_ ## flag) ? FS_ ## flag : 0
++ do_conv(ACCESS);
++ do_conv(MODIFY);
++ do_conv(ATTRIB);
++ do_conv(CLOSE_WRITE);
++ do_conv(CLOSE_NOWRITE);
++ do_conv(OPEN);
++ do_conv(MOVED_FROM);
++ do_conv(MOVED_TO);
++ do_conv(CREATE);
++ do_conv(DELETE);
++ do_conv(DELETE_SELF);
++ do_conv(MOVE_SELF);
++ do_conv(UNMOUNT);
++ do_conv(Q_OVERFLOW);
++#undef do_conv
++#define do_conv(flag) conv |= (mask & IN_ ## flag) ? FS_IN_ ## flag : 0
++ do_conv(IGNORED);
++ /* do_conv(ISDIR); */
++ /* do_conv(ONESHOT); */
++#undef do_conv
++
++ return conv;
++}
++
++static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused,
++ u32 mask, u32 cookie __maybe_unused,
++ const char *h_child_name, struct inode *h_child_inode)
++{
++ struct au_hnotify *hnotify;
++ struct qstr h_child_qstr = {
++ .name = h_child_name
++ };
++
++ /* if IN_UNMOUNT happens, there must be another bug */
++ AuDebugOn(mask & IN_UNMOUNT);
++ if (mask & (IN_IGNORED | IN_UNMOUNT)) {
++ put_inotify_watch(watch);
++ return;
++ }
++
++#ifdef AuDbgHnotify
++ au_debug(1);
++ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) {
++ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s,"
++ " hi%lu\n",
++ watch->inode->i_ino, wd, mask, in_name(mask), cookie,
++ h_child_name ? h_child_name : "",
++ h_child_inode ? h_child_inode->i_ino : 0);
++ WARN_ON(1);
++ }
++ au_debug(0);
++#endif
++
++ if (h_child_name)
++ h_child_qstr.len = strlen(h_child_name);
++ hnotify = container_of(watch, struct au_hnotify, hn_watch);
++ mask = au_hin_conv_mask(mask);
++ au_hnotify(watch->inode, hnotify, mask, &h_child_qstr, h_child_inode);
++}
++
++static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused)
++{
++ return;
++}
++
++static struct inotify_operations aufs_inotify_ops = {
++ .handle_event = aufs_inotify,
++ .destroy_watch = aufs_inotify_destroy
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int __init au_hin_init(void)
++{
++ int err;
++
++ err = 0;
++ au_hin_handle = inotify_init(&aufs_inotify_ops);
++ if (IS_ERR(au_hin_handle))
++ err = PTR_ERR(au_hin_handle);
++
++ AuTraceErr(err);
++ return err;
++}
++
++static void au_hin_fin(void)
++{
++ inotify_destroy(au_hin_handle);
++}
++
++const struct au_hnotify_op au_hnotify_op = {
++ .ctl = au_hin_ctl,
++ .alloc = au_hin_alloc,
++ .free = au_hin_free,
++
++ .fin = au_hin_fin,
++ .init = au_hin_init
++};
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/hnotify.c linux-2.6.33.1/fs/aufs/hnotify.c
+--- linux-2.6.33.1-vanilla/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/hnotify.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,671 @@
++/*
++ * Copyright (C) 2005-2010 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
++ */
++
++/*
++ * abstraction to notify the direct changes on lower directories
++ */
++
++#include "aufs.h"
++
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
++ struct inode *h_inode)
++{
++ int err;
++ struct au_hnotify *hn;
++
++ err = -ENOMEM;
++ hn = au_cache_alloc_hnotify();
++ if (hn) {
++ hn->hn_aufs_inode = inode;
++ err = au_hnotify_op.alloc(hn, h_inode);
++ if (!err)
++ hinode->hi_notify = hn;
++ else {
++ au_cache_free_hnotify(hn);
++ /*
++ * The upper dir was removed by udba, but the same named
++ * dir left. In this case, aufs assignes a new inode
++ * number and set the monitor again.
++ * For the lower dir, the old monitnor is still left.
++ */
++ if (err == -EEXIST)
++ err = 0;
++ }
++ }
++
++ return err;
++}
++
++void au_hn_free(struct au_hinode *hinode)
++{
++ struct au_hnotify *hn;
++
++ hn = hinode->hi_notify;
++ if (hn) {
++ au_hnotify_op.free(hn);
++ au_cache_free_hnotify(hn);
++ hinode->hi_notify = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_hn_ctl(struct au_hinode *hinode, int do_set)
++{
++ if (hinode->hi_notify)
++ au_hnotify_op.ctl(hinode, do_set);
++}
++
++void au_hn_reset(struct inode *inode, unsigned int flags)
+{
+ aufs_bindex_t bindex, bend;
+ struct inode *hi;
+
+/* ---------------------------------------------------------------------- */
+
-+static int hin_xino(struct inode *inode, struct inode *h_inode)
++static int hn_xino(struct inode *inode, struct inode *h_inode)
+{
+ int err;
+ aufs_bindex_t bindex, bend, bfound, bstart;
+
+ err = 0;
+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
-+ AuWarn("branch root dir was changed\n");
++ pr_warning("branch root dir was changed\n");
+ goto out;
+ }
+
+ goto out;
+ }
+#endif
-+ for (bindex = bstart; bindex <= bend; bindex++) {
++ for (bindex = bstart; bindex <= bend; bindex++)
+ if (au_h_iptr(inode, bindex) == h_inode) {
+ bfound = bindex;
+ break;
+ }
-+ }
+ if (bfound < 0)
+ goto out;
+
+ return err;
+}
+
-+static int hin_gen_tree(struct dentry *dentry)
++static int hn_gen_tree(struct dentry *dentry)
+{
+ int err, i, j, ndentry;
+ struct au_dcsub_pages dpages;
+/*
+ * return 0 if processed.
+ */
-+static int hin_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
-+ const unsigned int isdir)
++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
++ const unsigned int isdir)
+{
+ int err;
+ struct dentry *d;
+
+ err = 1;
+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
-+ AuWarn("branch root dir was changed\n");
++ pr_warning("branch root dir was changed\n");
+ err = 0;
+ goto out;
+ }
+
+ dname = &d->d_name;
+ if (dname->len == nlen && !memcmp(dname->name, name, nlen))
-+ err = hin_gen_tree(d);
++ err = hn_gen_tree(d);
+ dput(d);
+ }
+
+ return err;
+}
+
-+static int hin_gen_by_name(struct dentry *dentry, const unsigned int isdir)
++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
+{
+ int err;
+ struct inode *inode;
+ if (IS_ROOT(dentry)
+ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */
+ ) {
-+ AuWarn("branch root dir was changed\n");
++ pr_warning("branch root dir was changed\n");
+ return 0;
+ }
+
+ } else {
+ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS);
+ if (inode)
-+ err = hin_gen_tree(dentry);
++ err = hn_gen_tree(dentry);
+ }
+
+ AuTraceErr(err);
+
+/* ---------------------------------------------------------------------- */
+
-+/* hinotify job flags */
-+#define AuHinJob_XINO0 1
-+#define AuHinJob_GEN (1 << 1)
-+#define AuHinJob_DIRENT (1 << 2)
-+#define AuHinJob_ISDIR (1 << 3)
-+#define AuHinJob_TRYXINO0 (1 << 4)
-+#define AuHinJob_MNTPNT (1 << 5)
-+#define au_ftest_hinjob(flags, name) ((flags) & AuHinJob_##name)
-+#define au_fset_hinjob(flags, name) { (flags) |= AuHinJob_##name; }
-+#define au_fclr_hinjob(flags, name) { (flags) &= ~AuHinJob_##name; }
-+
-+struct hin_job_args {
++/* hnotify job flags */
++#define AuHnJob_XINO0 1
++#define AuHnJob_GEN (1 << 1)
++#define AuHnJob_DIRENT (1 << 2)
++#define AuHnJob_ISDIR (1 << 3)
++#define AuHnJob_TRYXINO0 (1 << 4)
++#define AuHnJob_MNTPNT (1 << 5)
++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name)
++#define au_fset_hnjob(flags, name) { (flags) |= AuHnJob_##name; }
++#define au_fclr_hnjob(flags, name) { (flags) &= ~AuHnJob_##name; }
++
++enum {
++ AuHn_CHILD,
++ AuHn_PARENT,
++ AuHnLast
++};
++
++struct au_hnotify_args {
++ struct inode *h_dir, *dir, *h_child_inode;
++ u32 mask;
++ unsigned int flags[AuHnLast];
++ unsigned int h_child_nlen;
++ char h_child_name[];
++};
++
++struct hn_job_args {
+ unsigned int flags;
+ struct inode *inode, *h_inode, *dir, *h_dir;
+ struct dentry *dentry;
+ int h_nlen;
+};
+
-+static int hin_job(struct hin_job_args *a)
++static int hn_job(struct hn_job_args *a)
+{
-+ const unsigned int isdir = au_ftest_hinjob(a->flags, ISDIR);
++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR);
+
+ /* reset xino */
-+ if (au_ftest_hinjob(a->flags, XINO0) && a->inode)
-+ hin_xino(a->inode, a->h_inode); /* ignore this error */
++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode)
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
+
-+ if (au_ftest_hinjob(a->flags, TRYXINO0)
++ if (au_ftest_hnjob(a->flags, TRYXINO0)
+ && a->inode
+ && a->h_inode) {
+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+ if (!a->h_inode->i_nlink)
-+ hin_xino(a->inode, a->h_inode); /* ignore this error */
++ hn_xino(a->inode, a->h_inode); /* ignore this error */
+ mutex_unlock(&a->h_inode->i_mutex);
+ }
+
+ /* make the generation obsolete */
-+ if (au_ftest_hinjob(a->flags, GEN)) {
++ if (au_ftest_hnjob(a->flags, GEN)) {
+ int err = -1;
+ if (a->inode)
-+ err = hin_gen_by_inode(a->h_name, a->h_nlen, a->inode,
-+ isdir);
++ err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode,
++ isdir);
+ if (err && a->dentry)
-+ hin_gen_by_name(a->dentry, isdir);
++ hn_gen_by_name(a->dentry, isdir);
+ /* ignore this error */
+ }
+
+ /* make dir entries obsolete */
-+ if (au_ftest_hinjob(a->flags, DIRENT) && a->inode) {
++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) {
+ struct au_vdir *vdir;
+
+ vdir = au_ivdir(a->inode);
+ }
+
+ /* can do nothing but warn */
-+ if (au_ftest_hinjob(a->flags, MNTPNT)
++ if (au_ftest_hnjob(a->flags, MNTPNT)
+ && a->dentry
+ && d_mountpoint(a->dentry))
-+ AuWarn("mount-point %.*s is removed or renamed\n",
-+ AuDLNPair(a->dentry));
++ pr_warning("mount-point %.*s is removed or renamed\n",
++ AuDLNPair(a->dentry));
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
-+static char *in_name(u32 mask)
-+{
-+#ifdef CONFIG_AUFS_DEBUG
-+#define test_ret(flag) if (mask & flag) \
-+ return #flag;
-+ test_ret(IN_ACCESS);
-+ test_ret(IN_MODIFY);
-+ test_ret(IN_ATTRIB);
-+ test_ret(IN_CLOSE_WRITE);
-+ test_ret(IN_CLOSE_NOWRITE);
-+ test_ret(IN_OPEN);
-+ test_ret(IN_MOVED_FROM);
-+ test_ret(IN_MOVED_TO);
-+ test_ret(IN_CREATE);
-+ test_ret(IN_DELETE);
-+ test_ret(IN_DELETE_SELF);
-+ test_ret(IN_MOVE_SELF);
-+ test_ret(IN_UNMOUNT);
-+ test_ret(IN_Q_OVERFLOW);
-+ test_ret(IN_IGNORED);
-+ return "";
-+#undef test_ret
-+#else
-+ return "??";
-+#endif
-+}
-+
+static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
+ struct inode *dir)
+{
+ goto out;
+
+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
-+ AuWarn("wrong root branch\n");
++ pr_warning("wrong root branch\n");
+ iput(inode);
+ inode = NULL;
+ goto out;
+ return inode;
+}
+
-+enum { CHILD, PARENT };
-+struct postproc_args {
-+ struct inode *h_dir, *dir, *h_child_inode;
-+ u32 mask;
-+ unsigned int flags[2];
-+ unsigned int h_child_nlen;
-+ char h_child_name[];
-+};
-+
-+static void postproc(void *_args)
++static void au_hn_bh(void *_args)
+{
-+ struct postproc_args *a = _args;
++ struct au_hnotify_args *a = _args;
+ struct super_block *sb;
+ aufs_bindex_t bindex, bend, bfound;
+ unsigned char xino, try_iput;
+ int err;
+ struct inode *inode;
+ ino_t h_ino;
-+ struct hin_job_args args;
++ struct hn_job_args args;
+ struct dentry *dentry;
+ struct au_sbinfo *sbinfo;
+
+ AuDebugOn(!a->h_dir);
+ AuDebugOn(!a->dir);
+ AuDebugOn(!a->mask);
-+ AuDbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n",
-+ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino,
++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n",
++ a->mask, a->dir->i_ino, a->h_dir->i_ino,
+ a->h_child_inode ? a->h_child_inode->i_ino : 0);
+
+ inode = NULL;
+ h_ino = a->h_child_inode->i_ino;
+
+ if (a->h_child_nlen
-+ && (au_ftest_hinjob(a->flags[CHILD], GEN)
-+ || au_ftest_hinjob(a->flags[CHILD], MNTPNT)))
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT)))
+ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
+ a->dir);
+ try_iput = 0;
+ if (dentry)
+ inode = dentry->d_inode;
+ if (xino && !inode && h_ino
-+ && (au_ftest_hinjob(a->flags[CHILD], XINO0)
-+ || au_ftest_hinjob(a->flags[CHILD], TRYXINO0)
-+ || au_ftest_hinjob(a->flags[CHILD], GEN))) {
++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0)
++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
+ inode = lookup_wlock_by_ino(sb, bfound, h_ino);
+ try_iput = 1;
+ }
+
-+ args.flags = a->flags[CHILD];
++ args.flags = a->flags[AuHn_CHILD];
+ args.dentry = dentry;
+ args.inode = inode;
+ args.h_inode = a->h_child_inode;
+ args.h_dir = a->h_dir;
+ args.h_name = a->h_child_name;
+ args.h_nlen = a->h_child_nlen;
-+ err = hin_job(&args);
++ err = hn_job(&args);
+ if (dentry) {
+ if (dentry->d_fsdata)
+ di_write_unlock(dentry);
+ }
+
+ ii_write_lock_parent(a->dir);
-+ args.flags = a->flags[PARENT];
++ args.flags = a->flags[AuHn_PARENT];
+ args.dentry = NULL;
+ args.inode = a->dir;
+ args.h_inode = a->h_dir;
+ args.h_dir = NULL;
+ args.h_name = NULL;
+ args.h_nlen = 0;
-+ err = hin_job(&args);
++ err = hn_job(&args);
+ ii_write_unlock(a->dir);
+
+ out:
+
+/* ---------------------------------------------------------------------- */
+
-+static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused,
-+ u32 mask, u32 cookie __maybe_unused,
-+ const char *h_child_name, struct inode *h_child_inode)
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode)
+{
-+ struct au_hinotify *hinotify;
-+ struct postproc_args *args;
-+ int len, wkq_err;
++ int err, len;
++ unsigned int flags[AuHnLast];
+ unsigned char isdir, isroot, wh;
-+ char *p;
+ struct inode *dir;
-+ unsigned int flags[2];
-+
-+ /* if IN_UNMOUNT happens, there must be another bug */
-+ AuDebugOn(mask & IN_UNMOUNT);
-+ if (mask & (IN_IGNORED | IN_UNMOUNT)) {
-+ put_inotify_watch(watch);
-+ return;
-+ }
-+#ifdef AuDbgHinotify
-+ au_debug(1);
-+ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) {
-+ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s,"
-+ " hi%lu\n",
-+ watch->inode->i_ino, wd, mask, in_name(mask), cookie,
-+ h_child_name ? h_child_name : "",
-+ h_child_inode ? h_child_inode->i_ino : 0);
-+ WARN_ON(1);
-+ }
-+ au_debug(0);
-+#endif
++ struct au_hnotify_args *args;
++ char *p, *h_child_name;
+
-+ hinotify = container_of(watch, struct au_hinotify, hin_watch);
-+ AuDebugOn(!hinotify || !hinotify->hin_aufs_inode);
-+ dir = igrab(hinotify->hin_aufs_inode);
++ err = 0;
++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode);
++ dir = igrab(hnotify->hn_aufs_inode);
+ if (!dir)
-+ return;
++ goto out;
+
+ isroot = (dir->i_ino == AUFS_ROOT_INO);
-+ len = 0;
+ wh = 0;
++ h_child_name = (void *)h_child_qstr->name;
++ len = h_child_qstr->len;
+ if (h_child_name) {
-+ len = strlen(h_child_name);
-+ if (!memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (len > AUFS_WH_PFX_LEN
++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
+ h_child_name += AUFS_WH_PFX_LEN;
+ len -= AUFS_WH_PFX_LEN;
+ wh = 1;
+ isdir = 0;
+ if (h_child_inode)
+ isdir = !!S_ISDIR(h_child_inode->i_mode);
-+ flags[PARENT] = AuHinJob_ISDIR;
-+ flags[CHILD] = 0;
++ flags[AuHn_PARENT] = AuHnJob_ISDIR;
++ flags[AuHn_CHILD] = 0;
+ if (isdir)
-+ flags[CHILD] = AuHinJob_ISDIR;
-+ switch (mask & IN_ALL_EVENTS) {
-+ case IN_MOVED_FROM:
-+ case IN_MOVED_TO:
-+ AuDebugOn(!h_child_name || !h_child_inode);
-+ au_fset_hinjob(flags[CHILD], GEN);
-+ au_fset_hinjob(flags[CHILD], XINO0);
-+ au_fset_hinjob(flags[CHILD], MNTPNT);
-+ au_fset_hinjob(flags[PARENT], DIRENT);
-+ break;
-+
-+ case IN_CREATE:
++ flags[AuHn_CHILD] = AuHnJob_ISDIR;
++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT);
++ au_fset_hnjob(flags[AuHn_CHILD], GEN);
++ switch (mask & FS_EVENTS_POSS_ON_CHILD) {
++ case FS_MOVED_FROM:
++ case FS_MOVED_TO:
++ au_fset_hnjob(flags[AuHn_CHILD], XINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
++ /*FALLTHROUGH*/
++ case FS_CREATE:
+ AuDebugOn(!h_child_name || !h_child_inode);
-+ au_fset_hinjob(flags[PARENT], DIRENT);
-+ au_fset_hinjob(flags[CHILD], GEN);
+ break;
+
-+ case IN_DELETE:
++ case FS_DELETE:
+ /*
+ * aufs never be able to get this child inode.
+ * revalidation should be in d_revalidate()
+ * by checking i_nlink, i_generation or d_unhashed().
+ */
+ AuDebugOn(!h_child_name);
-+ au_fset_hinjob(flags[PARENT], DIRENT);
-+ au_fset_hinjob(flags[CHILD], GEN);
-+ au_fset_hinjob(flags[CHILD], TRYXINO0);
-+ au_fset_hinjob(flags[CHILD], MNTPNT);
++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0);
++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
+ break;
+
+ default:
+ if (wh)
+ h_child_inode = NULL;
+
-+ /* iput() and kfree() will be called in postproc() */
++ err = -ENOMEM;
++ /* iput() and kfree() will be called in au_hnotify() */
+ /*
+ * inotify_mutex is already acquired and kmalloc/prune_icache may lock
+ * iprune_mutex. strange.
+ */
-+ lockdep_off();
++ /* lockdep_off(); */
+ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (unlikely(!args)) {
+ AuErr1("no memory\n");
+ iput(dir);
-+ return;
++ goto out;
+ }
-+ args->flags[PARENT] = flags[PARENT];
-+ args->flags[CHILD] = flags[CHILD];
++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT];
++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD];
+ args->mask = mask;
+ args->dir = dir;
-+ args->h_dir = igrab(watch->inode);
++ args->h_dir = igrab(h_dir);
+ if (h_child_inode)
+ h_child_inode = igrab(h_child_inode); /* can be NULL */
+ args->h_child_inode = h_child_inode;
+ if (len) {
+ p = (void *)args;
+ p += sizeof(*args);
-+ memcpy(p, h_child_name, len + 1);
++ memcpy(p, h_child_name, len);
++ p[len] = 0;
+ }
+
-+ lockdep_off();
-+ wkq_err = au_wkq_nowait(postproc, args, dir->i_sb);
-+ lockdep_on();
-+ if (unlikely(wkq_err))
-+ AuErr("wkq %d\n", wkq_err);
-+}
++ /* lockdep_off(); */
++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb);
++ /* lockdep_on(); */
++ if (unlikely(err)) {
++ pr_err("wkq %d\n", err);
++ iput(args->h_child_inode);
++ iput(args->h_dir);
++ iput(args->dir);
++ kfree(args);
++ }
+
-+static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused)
-+{
-+ return;
++out:
++ return err;
+}
+
-+static struct inotify_operations aufs_inotify_ops = {
-+ .handle_event = aufs_inotify,
-+ .destroy_watch = aufs_inotify_destroy
-+};
-+
-+/* ---------------------------------------------------------------------- */
-+
-+static void au_hin_destroy_cache(void)
++static void au_hn_destroy_cache(void)
+{
-+ kmem_cache_destroy(au_cachep[AuCache_HINOTIFY]);
-+ au_cachep[AuCache_HINOTIFY] = NULL;
++ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
++ au_cachep[AuCache_HNOTIFY] = NULL;
+}
+
-+int __init au_hinotify_init(void)
++int __init au_hnotify_init(void)
+{
+ int err;
+
+ err = -ENOMEM;
-+ au_cachep[AuCache_HINOTIFY] = AuCache(au_hinotify);
-+ if (au_cachep[AuCache_HINOTIFY]) {
-+ err = 0;
-+ au_hin_handle = inotify_init(&aufs_inotify_ops);
-+ if (IS_ERR(au_hin_handle)) {
-+ err = PTR_ERR(au_hin_handle);
-+ au_hin_destroy_cache();
-+ }
++ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
++ if (au_cachep[AuCache_HNOTIFY]) {
++ err = au_hnotify_op.init();
++ if (unlikely(err))
++ au_hn_destroy_cache();
+ }
+ AuTraceErr(err);
+ return err;
+}
+
-+void au_hinotify_fin(void)
++void au_hnotify_fin(void)
+{
-+ inotify_destroy(au_hin_handle);
-+ if (au_cachep[AuCache_HINOTIFY])
-+ au_hin_destroy_cache();
++ au_hnotify_op.fin();
++ /* cf. au_cache_fin() */
++ if (au_cachep[AuCache_HNOTIFY])
++ au_hn_destroy_cache();
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c
---- linux-2.6.31-vanilla/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/iinfo.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,283 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/iinfo.c linux-2.6.33.1/fs/aufs/iinfo.c
+--- linux-2.6.33.1-vanilla/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/iinfo.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,282 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+void au_hiput(struct au_hinode *hinode)
+{
-+ au_hin_free(hinode);
++ au_hn_free(hinode);
+ dput(hinode->hi_whdentry);
+ iput(hinode->hi_inode);
+}
+ flags = 0;
+ if (au_opt_test(mnt_flags, XINO))
+ au_fset_hi(flags, XINO);
-+ if (isdir && au_opt_test(mnt_flags, UDBA_HINOTIFY))
-+ au_fset_hi(flags, HINOTIFY);
++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY))
++ au_fset_hi(flags, HNOTIFY);
+ return flags;
+}
+
+ hinode = iinfo->ii_hinode + bindex;
+ hi = hinode->hi_inode;
+ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
-+ AuDebugOn(h_inode && hi);
+
+ if (hi)
+ au_hiput(hinode);
+ AuIOErr1("failed au_xino_write() %d\n", err);
+ }
+
-+ if (au_ftest_hi(flags, HINOTIFY)
-+ && au_br_hinotifyable(br->br_perm)) {
-+ err = au_hin_alloc(hinode, inode, h_inode);
++ if (au_ftest_hi(flags, HNOTIFY)
++ && au_br_hnotifyable(br->br_perm)) {
++ err = au_hn_alloc(hinode, inode, h_inode);
+ if (unlikely(err))
-+ AuIOErr1("au_hin_alloc() %d\n", err);
++ AuIOErr1("au_hn_alloc() %d\n", err);
+ }
+ }
+}
+ kfree(iinfo->ii_hinode);
+ AuRwDestroy(&iinfo->ii_rwsem);
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c
---- linux-2.6.31-vanilla/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/inode.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,413 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/inode.c linux-2.6.33.1/fs/aufs/inode.c
+--- linux-2.6.33.1-vanilla/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/inode.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,412 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ int err;
+ aufs_bindex_t bindex, new_bindex;
+ unsigned char update;
-+ struct inode *first;
+ struct au_hinode *p, *q, tmp;
+ struct super_block *sb;
+ struct au_iinfo *iinfo;
+ goto out;
+
+ p = iinfo->ii_hinode + iinfo->ii_bstart;
-+ first = p->hi_inode;
+ err = 0;
+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
+ bindex++, p++) {
+ continue;
+
+ if (new_bindex < 0) {
-+ update++;
++ update = 1;
+ au_hiput(p);
+ p->hi_inode = NULL;
+ continue;
+
+int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
+{
-+ int err, update;
++ int err;
+ unsigned int flags;
+ aufs_bindex_t bindex, bend;
-+ unsigned char isdir;
-+ struct inode *first;
++ unsigned char isdir, update;
+ struct au_hinode *p;
+ struct au_iinfo *iinfo;
+
+ update = 0;
+ iinfo = au_ii(inode);
+ p = iinfo->ii_hinode + iinfo->ii_bstart;
-+ first = p->hi_inode;
+ isdir = S_ISDIR(inode->i_mode);
+ flags = au_hi_flags(inode, isdir);
+ bend = au_dbend(dentry);
+ au_refresh_hinode_attr(inode, update && isdir);
+
+ out:
++ AuTraceErr(err);
+ return err;
+}
+
+ case S_IFSOCK:
+ btail = au_dbtail(dentry);
+ inode->i_op = &aufs_iop;
-+ init_special_inode(inode, mode, h_inode->i_rdev);
++ au_init_special_fop(inode, mode, h_inode->i_rdev);
+ break;
+ default:
+ AuIOErr("Unknown file type 0%o\n", mode);
+ goto out;
+ }
+
-+ /* do not set inotify for whiteouted dirs (SHWH mode) */
++ /* do not set hnotify for whiteouted dirs (SHWH mode) */
+ flags = au_hi_flags(inode, isdir);
+ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
-+ && au_ftest_hi(flags, HINOTIFY)
++ && au_ftest_hi(flags, HNOTIFY)
+ && dentry->d_name.len > AUFS_WH_PFX_LEN
+ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
-+ au_fclr_hi(flags, HINOTIFY);
++ au_fclr_hi(flags, HNOTIFY);
+ iinfo = au_ii(inode);
+ iinfo->ii_bstart = bstart;
+ iinfo->ii_bend = btail;
+ if (inode->i_state & I_NEW) {
+ ii_write_lock_new_child(inode);
+ err = set_inode(inode, dentry);
-+ unlock_new_inode(inode);
-+ if (!err)
++ if (!err) {
++ unlock_new_inode(inode);
+ goto out; /* success */
++ }
+
-+ iget_failed(inode);
+ ii_write_unlock(inode);
-+ goto out_iput;
++ iget_failed(inode);
++ goto out_err;
+ } else if (!must_new) {
+ err = reval_inode(inode, dentry, &match);
+ if (!err)
+
+ out_iput:
+ iput(inode);
++ out_err:
+ inode = ERR_PTR(err);
+ out:
+ return inode;
+ mask |= MAY_READ; /* force permission check */
+ return au_test_h_perm(h_inode, mask);
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h
---- linux-2.6.31-vanilla/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/inode.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,497 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/inode.h linux-2.6.33.1/fs/aufs/inode.h
+--- linux-2.6.33.1-vanilla/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/inode.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,492 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
-+#include <linux/inotify.h>
++#include <linux/fsnotify.h>
+#include <linux/aufs_type.h>
+#include "rwsem.h"
+
+struct vfsmount;
+
-+struct au_hinotify {
-+#ifdef CONFIG_AUFS_HINOTIFY
-+ struct inotify_watch hin_watch;
-+ struct inode *hin_aufs_inode; /* no get/put */
++struct au_hnotify {
++#ifdef CONFIG_AUFS_HNOTIFY
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ struct fsnotify_mark_entry hn_entry;
++#else
++ struct inotify_watch hn_watch;
++#endif
++ struct inode *hn_aufs_inode; /* no get/put */
+#endif
+};
+
+struct au_hinode {
+ struct inode *hi_inode;
+ aufs_bindex_t hi_id;
-+#ifdef CONFIG_AUFS_HINOTIFY
-+ struct au_hinotify *hi_notify;
++#ifdef CONFIG_AUFS_HNOTIFY
++ struct au_hnotify *hi_notify;
+#endif
+
+ /* reference to the copied-up whiteout with get/put */
+
+/* hinode flags */
+#define AuHi_XINO 1
-+#define AuHi_HINOTIFY (1 << 1)
++#define AuHi_HNOTIFY (1 << 1)
+#define au_ftest_hi(flags, name) ((flags) & AuHi_##name)
+#define au_fset_hi(flags, name) { (flags) |= AuHi_##name; }
+#define au_fclr_hi(flags, name) { (flags) &= ~AuHi_##name; }
+
-+#ifndef CONFIG_AUFS_HINOTIFY
-+#undef AuHi_HINOTIFY
-+#define AuHi_HINOTIFY 0
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuHi_HNOTIFY
++#define AuHi_HNOTIFY 0
+#endif
+
+void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
+int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
+
+/* plink.c */
-+void au_plink_block_maintain(struct super_block *sb);
++void au_plink_maint_block(struct super_block *sb);
++void au_plink_maint_leave(struct file *file);
+#ifdef CONFIG_AUFS_DEBUG
+void au_plink_list(struct super_block *sb);
+#else
-+static inline void au_plink_list(struct super_block *sb)
-+{
-+ /* nothing */
-+}
++AuStubVoid(au_plink_list, struct super_block *sb)
+#endif
+int au_plink_test(struct inode *inode);
+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
+/* lock subclass for iinfo */
+enum {
+ AuLsc_II_CHILD, /* child first */
-+ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */
++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */
+ AuLsc_II_CHILD3, /* copyup dirs */
+ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */
+ AuLsc_II_PARENT2,
+ && iinfo->ii_higen == h_inode->i_generation);
+}
+
++static inline void au_iigen_dec(struct inode *inode)
++{
++#ifdef CONFIG_AUFS_HNOTIFY
++ atomic_dec_return(&au_ii(inode)->ii_generation);
++#endif
++}
++
+/* ---------------------------------------------------------------------- */
+
+static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
+
+/* ---------------------------------------------------------------------- */
+
-+#ifdef CONFIG_AUFS_HINOTIFY
-+/* hinotify.c */
-+int au_hin_alloc(struct au_hinode *hinode, struct inode *inode,
-+ struct inode *h_inode);
-+void au_hin_free(struct au_hinode *hinode);
-+void au_hin_ctl(struct au_hinode *hinode, int do_set);
-+void au_reset_hinotify(struct inode *inode, unsigned int flags);
++#ifdef CONFIG_AUFS_HNOTIFY
++struct au_hnotify_op {
++ void (*ctl)(struct au_hinode *hinode, int do_set);
++ int (*alloc)(struct au_hnotify *hn, struct inode *h_inode);
++ void (*free)(struct au_hnotify *hn);
+
-+int __init au_hinotify_init(void);
-+void au_hinotify_fin(void);
++ void (*fin)(void);
++ int (*init)(void);
++};
+
-+static inline
-+void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val)
-+{
-+ hinode->hi_notify = val;
-+}
++/* hnotify.c */
++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
++ struct inode *h_inode);
++void au_hn_free(struct au_hinode *hinode);
++void au_hn_ctl(struct au_hinode *hinode, int do_set);
++void au_hn_reset(struct inode *inode, unsigned int flags);
++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
++ struct qstr *h_child_qstr, struct inode *h_child_inode);
++int __init au_hnotify_init(void);
++void au_hnotify_fin(void);
+
-+static inline void au_iigen_dec(struct inode *inode)
++/* hinotify.c */
++extern const struct au_hnotify_op au_hnotify_op;
++
++static inline
++void au_hn_init(struct au_hinode *hinode)
+{
-+ atomic_dec_return(&au_ii(inode)->ii_generation);
++ hinode->hi_notify = NULL;
+}
+
+#else
+static inline
-+int au_hin_alloc(struct au_hinode *hinode __maybe_unused,
-+ struct inode *inode __maybe_unused,
-+ struct inode *h_inode __maybe_unused)
++int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
++ struct inode *inode __maybe_unused,
++ struct inode *h_inode __maybe_unused)
+{
+ return -EOPNOTSUPP;
+}
+
-+static inline void au_hin_free(struct au_hinode *hinode __maybe_unused)
-+{
-+ /* nothing */
-+}
-+
-+static inline void au_hin_ctl(struct au_hinode *hinode __maybe_unused,
-+ int do_set __maybe_unused)
-+{
-+ /* nothing */
-+}
-+
-+static inline void au_reset_hinotify(struct inode *inode __maybe_unused,
-+ unsigned int flags __maybe_unused)
-+{
-+ /* nothing */
-+}
-+
-+static inline int au_hinotify_init(void)
-+{
-+ return 0;
-+}
-+
-+#define au_hinotify_fin() do {} while (0)
-+
-+static inline
-+void au_hin_init(struct au_hinode *hinode __maybe_unused,
-+ struct au_hinotify *val __maybe_unused)
-+{
-+ /* empty */
-+}
-+#endif /* CONFIG_AUFS_HINOTIFY */
++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused)
++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
++ int do_set __maybe_unused)
++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
++ unsigned int flags __maybe_unused)
++AuStubInt0(__init au_hnotify_init, void)
++AuStubVoid(au_hnotify_fin, void)
++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
++#endif /* CONFIG_AUFS_HNOTIFY */
+
-+static inline void au_hin_suspend(struct au_hinode *hdir)
++static inline void au_hn_suspend(struct au_hinode *hdir)
+{
-+ au_hin_ctl(hdir, /*do_set*/0);
++ au_hn_ctl(hdir, /*do_set*/0);
+}
+
-+static inline void au_hin_resume(struct au_hinode *hdir)
++static inline void au_hn_resume(struct au_hinode *hdir)
+{
-+ au_hin_ctl(hdir, /*do_set*/1);
++ au_hn_ctl(hdir, /*do_set*/1);
+}
+
-+static inline void au_hin_imtx_lock(struct au_hinode *hdir)
++static inline void au_hn_imtx_lock(struct au_hinode *hdir)
+{
+ mutex_lock(&hdir->hi_inode->i_mutex);
-+ au_hin_suspend(hdir);
++ au_hn_suspend(hdir);
+}
+
-+static inline void au_hin_imtx_lock_nested(struct au_hinode *hdir,
-+ unsigned int sc __maybe_unused)
++static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir,
++ unsigned int sc __maybe_unused)
+{
+ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc);
-+ au_hin_suspend(hdir);
++ au_hn_suspend(hdir);
+}
+
-+static inline void au_hin_imtx_unlock(struct au_hinode *hdir)
++static inline void au_hn_imtx_unlock(struct au_hinode *hdir)
+{
-+ au_hin_resume(hdir);
++ au_hn_resume(hdir);
+ mutex_unlock(&hdir->hi_inode->i_mutex);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_INODE_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/ioctl.c linux-2.6.31/fs/aufs/ioctl.c
---- linux-2.6.31-vanilla/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/ioctl.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,47 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/ioctl.c linux-2.6.33.1/fs/aufs/ioctl.c
+--- linux-2.6.33.1-vanilla/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/ioctl.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,129 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+/*
+ * ioctl
+ * plink-management and readdir in userspace.
++ * assist the pathconf(3) wrapper library.
+ */
+
++#include <linux/file.h>
+#include "aufs.h"
+
++static int au_wbr_fd(struct path *path)
++{
++ int err, fd, flags;
++ aufs_bindex_t wbi, bindex, bend;
++ struct file *h_file;
++ struct super_block *sb;
++ struct dentry *root;
++ struct au_branch *wbr;
++
++ err = get_unused_fd();
++ if (unlikely(err < 0))
++ goto out;
++ fd = err;
++
++ flags = O_RDONLY | O_DIRECTORY;
++ if (force_o_largefile())
++ flags |= O_LARGEFILE;
++
++ wbi = 0;
++ sb = path->dentry->d_sb;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_IR);
++ wbr = au_sbr(sb, wbi);
++ if (!(path->mnt->mnt_flags & MNT_READONLY)
++ && !au_br_writable(wbr->br_perm)) {
++ bend = au_sbend(sb);
++ for (bindex = 1; bindex <= bend; bindex++) {
++ wbr = au_sbr(sb, bindex);
++ if (au_br_writable(wbr->br_perm)) {
++ wbi = bindex;
++ break;
++ }
++ }
++ wbr = au_sbr(sb, wbi);
++ }
++ AuDbg("wbi %d\n", wbi);
++ h_file = au_h_open(root, wbi, flags, NULL);
++ aufs_read_unlock(root, AuLock_IR);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out_fd;
++
++ atomic_dec(&wbr->br_count); /* cf. au_h_open() */
++ fd_install(fd, h_file);
++ err = fd;
++ goto out; /* success */
++
++ out_fd:
++ put_unused_fd(fd);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long err;
+ err = au_rdu_ioctl(file, cmd, arg);
+ break;
+
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
+ default:
-+ err = -EINVAL;
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_WBR_FD:
++ err = au_wbr_fd(&file->f_path);
++ break;
++
++ default:
++ /* do not call the lower */
++ AuDbg("0x%x\n", cmd);
++ err = -ENOTTY;
+ }
+
+ AuTraceErr(err);
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add.c
---- linux-2.6.31-vanilla/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/i_op_add.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,649 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/i_op_add.c linux-2.6.33.1/fs/aufs/i_op_add.c
+--- linux-2.6.33.1-vanilla/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/i_op_add.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,672 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ struct dentry *h_dentry;
+ struct inode *h_inode;
+
++ err = -ENAMETOOLONG;
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out;
++
+ h_dentry = au_h_dptr(dentry, bindex);
+ h_inode = h_dentry->d_inode;
+ if (!dentry->d_inode) {
+ }
+ }
+
-+ err = -EIO;
++ err = 0;
+ /* expected parent dir is locked */
+ if (unlikely(h_parent != h_dentry->d_parent))
-+ goto out;
-+ err = 0;
++ err = -EIO;
+
+ out:
++ AuTraceErr(err);
+ return err;
+}
+
+ unsigned int udba;
+ aufs_bindex_t bcpup;
+
++ AuDbg("%.*s\n", AuDLNPair(dentry));
++
+ err = au_wr_dir(dentry, src_dentry, wr_dir_args);
+ bcpup = err;
+ wh_dentry = ERR_PTR(err);
+
+ h_parent = au_pinned_h_parent(pin);
+ if (udba != AuOpt_UDBA_NONE
-+ && au_dbstart(dentry) == bcpup) {
++ && au_dbstart(dentry) == bcpup)
+ err = au_may_add(dentry, bcpup, h_parent,
+ au_ftest_wrdir(wr_dir_args->flags, ISDIR));
-+ wh_dentry = ERR_PTR(err);
-+ if (unlikely(err))
-+ goto out_unpin;
-+ }
++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
+
+ br = au_sbr(sb, bcpup);
+ if (dt) {
+ .flags = AuWrDir_ADD_ENTRY
+ };
+
++ AuDbg("%.*s\n", AuDLNPair(dentry));
+ IMustLock(dir);
+
+ parent = dentry->d_parent; /* dir inode is locked */
+ int err;
+ struct dentry *h_src_dentry;
+ struct mutex *h_mtx;
++ struct file *h_file;
+
+ di_read_lock_parent(a->src_parent, AuLock_IR);
+ err = au_test_and_cpup_dirs(src_dentry, a->bdst);
+ if (unlikely(err))
+ goto out;
+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
-+ err = au_sio_cpup_simple(src_dentry, a->bdst, -1,
-+ AuCpup_DTIME /* | AuCpup_KEEPLINO */);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(src_dentry, a->bdst, a->bsrc,
++ AuCpup_DTIME /* | AuCpup_KEEPLINO */);
+ mutex_unlock(h_mtx);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
+ au_unpin(&a->pin);
+
+ out:
+ struct inode *h_inode, *inode;
+ struct dentry *h_src_dentry;
+ struct super_block *sb;
++ struct file *h_file;
+
+ plink = 0;
+ h_inode = NULL;
+ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry));
+ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode;
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
-+ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1,
-+ AuCpup_KEEPLINO, a->parent);
++ h_file = au_h_open_pre(src_dentry, a->bsrc);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc,
++ -1, AuCpup_KEEPLINO,
++ a->parent);
+ mutex_unlock(&h_inode->i_mutex);
++ au_h_open_post(src_dentry, a->bsrc, h_file);
+ au_set_h_dptr(src_dentry, a->bdst, NULL);
+ au_set_dbstart(src_dentry, a->bsrc);
+ } else {
+ out:
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c
---- linux-2.6.31-vanilla/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/i_op.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,891 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/i_op.c linux-2.6.33.1/fs/aufs/i_op.c
+--- linux-2.6.33.1-vanilla/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/i_op.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,909 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ && write_mask && !(mask & MAY_READ))
+ || !h_inode->i_op->permission) {
+ /* AuLabel(generic_permission); */
-+ err = generic_permission(h_inode, mask, NULL);
++ err = generic_permission(h_inode, mask,
++ h_inode->i_op->check_acl);
+ } else {
+ /* AuLabel(h_inode->permission); */
+ err = h_inode->i_op->permission(h_inode, mask);
+
+ if (!err)
+ err = devcgroup_inode_permission(h_inode, mask);
-+ if (!err)
-+ err = security_inode_permission
-+ (h_inode, mask & (MAY_READ | MAY_WRITE | MAY_EXEC
-+ | MAY_APPEND));
++ if (!err) {
++ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND);
++ err = security_inode_permission(h_inode, mask);
++ }
+
+#if 0
+ if (!err) {
+{
+ int err;
+ aufs_bindex_t bindex, bend;
-+ const unsigned char isdir = !!S_ISDIR(inode->i_mode);
-+ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++ const unsigned char isdir = !!S_ISDIR(inode->i_mode),
++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
+ struct inode *h_inode;
+ struct super_block *sb;
+ struct au_branch *br;
+ bindex = au_ibstart(inode);
+ br = au_sbr(sb, bindex);
+ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
-+ if (write_mask && !err) {
++ if (write_mask
++ && !err
++ && !special_file(h_inode->i_mode)) {
+ /* test whether the upper writable branch exists */
+ err = -EROFS;
+ for (; bindex >= 0; bindex--)
+
+ sb = dir->i_sb;
+ si_read_lock(sb, AuLock_FLUSH);
++ ret = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
++ goto out;
+ err = au_alloc_dinfo(dentry);
+ ret = ERR_PTR(err);
+ if (unlikely(err))
+ if (!p->hdir)
+ return;
+
-+ au_hin_imtx_unlock(p->hdir);
++ au_hn_imtx_unlock(p->hdir);
+ if (!au_ftest_pin(p->flags, DI_LOCKED))
+ di_read_unlock(p->parent, AuLock_IR);
+ iput(p->hdir->hi_inode);
+ }
+
+ au_igrab(h_dir);
-+ au_hin_imtx_lock_nested(p->hdir, p->lsc_hi);
++ au_hn_imtx_lock_nested(p->hdir, p->lsc_hi);
+
+ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) {
+ err = -EBUSY;
+ out_unpin:
+ au_unpin(p);
+ out_err:
-+ AuErr("err %d\n", err);
++ pr_err("err %d\n", err);
+ err = au_busy_or_stale();
+ out:
+ return err;
+ aufs_bindex_t bstart;
+ struct dentry *hi_wh, *parent;
+ struct inode *inode;
++ struct file *h_file;
+ struct au_wr_dir_args wr_dir_args = {
+ .force_btgt = -1,
+ .flags = 0
+ if (d_unhashed(dentry) || (ia->ia_valid & ATTR_FILE))
+ udba = AuOpt_UDBA_NONE;
+ err = au_pin(&a->pin, dentry, a->btgt, udba, a->pin_flags);
-+ if (unlikely(err)) {
-+ if (parent) {
-+ di_write_unlock(parent);
-+ dput(parent);
-+ }
-+ goto out_dentry;
-+ }
++ if (unlikely(err))
++ goto out_parent;
++
+ a->h_path.dentry = au_h_dptr(dentry, bstart);
+ a->h_inode = a->h_path.dentry->d_inode;
+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode))
+ sz = ia->ia_size;
+
++ h_file = NULL;
+ hi_wh = NULL;
+ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unhashed(dentry)) {
+ hi_wh = au_hi_wh(inode, a->btgt);
+ au_pin_set_parent_lflag(&a->pin, /*lflag*/0);
+ di_downgrade_lock(parent, AuLock_IR);
+ dput(parent);
++ parent = NULL;
+ }
+ if (!au_ftest_icpup(a->flags, DID_CPUP))
+ goto out; /* success */
+
+ if (!d_unhashed(dentry)) {
-+ err = au_sio_cpup_simple(dentry, a->btgt, sz, AuCpup_DTIME);
++ h_file = au_h_open_pre(dentry, bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(dentry, a->btgt, sz,
++ AuCpup_DTIME);
+ if (!err)
+ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
+ } else if (!hi_wh)
+
+ out_unlock:
+ mutex_unlock(&a->h_inode->i_mutex);
++ au_h_open_post(dentry, bstart, h_file);
+ a->h_inode = a->h_path.dentry->d_inode;
+ if (!err) {
+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
+ }
+
+ au_unpin(&a->pin);
-+
++ out_parent:
++ if (parent) {
++ di_write_unlock(parent);
++ dput(parent);
++ }
+ out_dentry:
+ di_write_unlock(dentry);
+ out:
+ }
+
+ a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
++ == (ATTR_MODE | ATTR_CTIME)) {
++ err = security_path_chmod(a->h_path.dentry, a->h_path.mnt,
++ ia->ia_mode);
++ if (unlikely(err))
++ goto out_unlock;
++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
++ && (ia->ia_valid & ATTR_CTIME)) {
++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++
+ if (ia->ia_valid & ATTR_SIZE) {
+ struct file *f;
+
+ di_read_lock_parent(parent, AuLock_IR);
+ /* returns a number of positive dentries */
+ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
-+ if (err > 0)
++ if (err >= 0)
+ err = au_refresh_hinode(inode, dentry);
+ di_read_unlock(parent, AuLock_IR);
+ dput(parent);
-+ if (unlikely(!err))
-+ err = -EIO;
+ }
+ di_downgrade_lock(dentry, AuLock_IR);
+ if (unlikely(err))
+ di_read_unlock(dentry, AuLock_IR);
+
++ AuTraceErr(err);
+ return err;
+}
+
+ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
+ di_read_lock_child(dentry, AuLock_IR);
+ else {
-+ /* NFSD may skip the revalidation */
-+ if (!au_test_nfsd(current))
-+ AuDebugOn(!IS_ROOT(dentry));
-+ else {
-+ err = au_busy_or_stale();
-+ if (unlikely(!IS_ROOT(dentry)))
-+ goto out;
-+ }
++ AuDebugOn(IS_ROOT(dentry));
+ err = au_getattr_lock_reval(dentry, sigen);
+ if (unlikely(err))
+ goto out;
+
+ err = -EINVAL;
+ h_dentry = au_h_dptr(dentry, bindex);
-+ if (unlikely(/* !h_dentry
-+ || !h_dentry->d_inode
-+ || !h_dentry->d_inode->i_op
-+ || */ !h_dentry->d_inode->i_op->readlink))
++ if (unlikely(!h_dentry->d_inode->i_op->readlink))
+ goto out;
+
+ err = security_inode_readlink(h_dentry);
+ mm_segment_t old_fs;
+
+ err = -ENOMEM;
-+ buf = __getname();
++ buf = __getname_gfp(GFP_NOFS);
+ if (unlikely(!buf))
+ goto out;
+
+ .getattr = aufs_getattr,
+ .truncate_range = aufs_truncate_range
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del.c
---- linux-2.6.31-vanilla/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/i_op_del.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,468 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/i_op_del.c linux-2.6.33.1/fs/aufs/i_op_del.c
+--- linux-2.6.33.1-vanilla/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/i_op_del.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,472 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ goto out; /* success, no need to create whiteout */
+
+ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
-+ if (!IS_ERR(wh_dentry))
-+ goto out; /* success */
++ if (IS_ERR(wh_dentry))
++ goto out_unpin;
++
+ /* returns with the parent is locked and wh_dentry is dget-ed */
++ goto out; /* success */
+
+ out_unpin:
+ au_unpin(pin);
+ goto out;
+
+ /* stop monitoring */
-+ au_hin_free(au_hi(dentry->d_inode, bindex));
++ au_hn_free(au_hi(dentry->d_inode, bindex));
+
+ if (!au_test_fs_remote(h_dentry->d_sb)) {
+ dirwh = au_sbi(sb)->si_dirwh;
+ }
+
+ out:
++ AuTraceErr(err);
+ return err;
+}
+
+ }
+ } else {
+ /* stop monitoring */
-+ au_hin_free(au_hi(inode, bstart));
++ au_hn_free(au_hi(inode, bstart));
+
+ /* dir inode is locked */
+ IMustLock(wh_dentry->d_parent->d_inode);
+ out_unlock:
+ aufs_read_unlock(dentry, AuLock_DW);
+ out:
++ AuTraceErr(err);
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren.c
---- linux-2.6.31-vanilla/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/i_op_ren.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,957 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/i_op_ren.c linux-2.6.33.1/fs/aufs/i_op_ren.c
+--- linux-2.6.33.1-vanilla/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/i_op_ren.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,977 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ * harmless.
+ */
+
-+#define RevertFailure(fmt, args...) do { \
++#define RevertFailure(fmt, ...) do { \
+ AuIOErr("revert failure: " fmt " (%d, %d)\n", \
-+ ##args, err, rerr); \
++ ##__VA_ARGS__, err, rerr); \
+ err = -EIO; \
+} while (0)
+
+{
+ int rerr;
+
-+ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
+ rerr = au_diropq_remove(a->src_dentry, a->btgt);
-+ au_hin_imtx_unlock(a->src_hinode);
++ au_hn_imtx_unlock(a->src_hinode);
+ if (rerr)
+ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
+}
+
-+
+static void au_ren_rev_rename(int err, struct au_ren_args *a)
+{
+ int rerr;
+ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry));
+}
+
-+
+static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
+{
+ int rerr;
+ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path);
+ d_drop(a->h_path.dentry);
+ dput(a->h_path.dentry);
-+ if (!rerr) {
-+ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
++ if (!rerr)
+ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst));
-+ } else
++ else
+ RevertFailure("rename %.*s", AuDLNPair(a->h_dst));
+}
+
+ a->dst_h_dir, &a->h_path);
+ } else {
+ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
+
+ au_fset_ren(a->flags, CPUP);
+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
+ au_set_dbstart(d, a->btgt);
+ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
-+ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
-+ !AuCpup_DTIME, a->dst_parent);
-+ if (unlikely(err)) {
++ h_file = au_h_open_pre(d, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
++ !AuCpup_DTIME, a->dst_parent);
++ mutex_unlock(h_mtx);
++ au_h_open_post(d, a->src_bstart, h_file);
++ if (!err) {
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_update_dbstart(d);
++ } else {
+ au_set_h_dptr(d, a->btgt, NULL);
+ au_set_dbstart(d, a->src_bstart);
+ }
-+ mutex_unlock(h_mtx);
+ }
+
+ return err;
+ || au_test_fs_remote(a->h_dst->d_sb)) {
+ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
+ if (unlikely(err))
-+ AuWarn("failed removing whtmp dir %.*s (%d), "
-+ "ignored.\n", AuDLNPair(a->h_dst), err);
++ pr_warning("failed removing whtmp dir %.*s (%d), "
++ "ignored.\n", AuDLNPair(a->h_dst), err);
+ } else {
+ au_nhash_wh_free(&a->thargs->whlist);
+ a->thargs->whlist = a->whlist;
+
+ err = 0;
+ a->src_hinode = au_hi(a->src_inode, a->btgt);
-+ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
+ diropq = au_diropq_create(a->src_dentry, a->btgt);
-+ au_hin_imtx_unlock(a->src_hinode);
++ au_hn_imtx_unlock(a->src_hinode);
+ if (IS_ERR(diropq))
+ err = PTR_ERR(diropq);
+ dput(diropq);
+ /* cpup src */
+ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) {
+ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++ struct file *h_file;
+
+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
-+ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
-+ !AuCpup_DTIME);
++ AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart);
++ h_file = au_h_open_pre(a->src_dentry, a->src_bstart);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ h_file = NULL;
++ } else
++ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
++ !AuCpup_DTIME);
+ mutex_unlock(h_mtx);
++ au_h_open_post(a->src_dentry, a->src_bstart, h_file);
+ if (unlikely(err))
+ goto out_whtmp;
+ }
+ out:
+ if (unlikely(err == -ENOENT || err == -EEXIST))
+ err = -EIO;
++ AuTraceErr(err);
+ return err;
+}
+
+ /* reduce stack space */
+ struct au_ren_args *a;
+
++ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry));
+ IMustLock(_src_dir);
+ IMustLock(_dst_dir);
+
+ if (unlikely(err))
+ goto out_children;
+
-+ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) {
++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE))
+ err = au_may_ren(a);
-+ if (unlikely(err))
-+ goto out_hdir;
-+ }
++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN))
++ err = -ENAMETOOLONG;
++ if (unlikely(err))
++ goto out_hdir;
+
+ /* store timestamps to be revertible */
+ au_ren_dt(a);
+ au_whtmp_rmdir_free(a->thargs);
+ kfree(a);
+ out:
++ AuTraceErr(err);
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig
---- linux-2.6.31-vanilla/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/Kconfig 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,140 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/Kconfig linux-2.6.33.1/fs/aufs/Kconfig
+--- linux-2.6.33.1-vanilla/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/Kconfig 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,172 @@
+config AUFS_FS
+ tristate "Aufs (Advanced multi layered unification filesystem) support"
+ depends on EXPERIMENTAL
+ resources and has a minor impact to performance.
+endchoice
+
-+config AUFS_HINOTIFY
-+ bool "Use inotify to detect actions on a branch"
-+ depends on INOTIFY
++config AUFS_HNOTIFY
++ bool "Detect direct branch access (bypassing aufs)"
+ help
+ If you want to modify files on branches directly, eg. bypassing aufs,
+ and want aufs to detect the changes of them fully, then enable this
-+ option and use 'udba=inotify' mount option.
++ option and use 'udba=notify' mount option.
+ It will have a negative impact to the performance.
+ See detail in aufs.5.
+
++if AUFS_HNOTIFY
++choice
++ prompt ""
++ default AUFS_HFSNOTIFY
++config AUFS_HFSNOTIFY
++ bool "fsnotify"
++ select FSNOTIFY
++config AUFS_HINOTIFY
++ bool "inotify (DEPRECATED)"
++ depends on INOTIFY
++endchoice
++endif
++
+config AUFS_EXPORT
+ bool "NFS-exportable aufs"
+ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS)
+ option. There are several requirements for this configuration.
+ See detail in aufs.5.
+
++config AUFS_INO_T_64
++ bool
++ depends on AUFS_EXPORT
++ depends on 64BIT && !(ALPHA || S390)
++ default y
++ help
++ Automatic configuration for internal use.
++ /* typedef unsigned long/int __kernel_ino_t */
++ /* alpha and s390x are int */
++
+config AUFS_RDU
+ bool "Readdir in userspace"
+ help
+ environment variables for your readdir(3).
+ See detail in aufs.5.
+
++config AUFS_SP_IATTR
++ bool "Respect the attributes (mtime/ctime mainly) of special files"
++ help
++ When you write something to a special file, some attributes of it
++ (mtime/ctime mainly) may be updated. Generally such updates are
++ less important (actually some device drivers and NFS ignore
++ it). But some applications (such like test program) requires
++ such updates. If you need these updates, then enable this
++ configuration which introduces some overhead.
++ Currently this configuration handles FIFO only.
++
+config AUFS_SHWH
+ bool "Show whiteouts"
+ help
+ It implements the internal poll(2) operation which is
+ implemented by fuse only (curretnly).
+
-+config AUFS_DEBUG
-+ bool "Debug aufs"
++config AUFS_POLL
++ bool
+ help
-+ Enable this to compile aufs internal debug code.
-+ It will have a negative impact to the performance.
++ Automatic configuration for internal use.
+
-+config AUFS_MAGIC_SYSRQ
-+ bool
-+ depends on AUFS_DEBUG && MAGIC_SYSRQ
++config AUFS_BR_HFSPLUS
++ bool "Hfsplus as an aufs branch"
++ depends on HFSPLUS_FS
+ default y
+ help
-+ Automatic configuration for internal use.
-+ When aufs supports Magic SysRq, enabled automatically.
++ If you want to use hfsplus fs as an aufs branch fs, then enable
++ this option. This option introduces a small overhead at
++ copying-up a file on hfsplus.
+
+config AUFS_BDEV_LOOP
+ bool
+ Automatic configuration for internal use.
+ Convert =[ym] into =y.
+
-+config AUFS_INO_T_64
-+ bool
-+ depends on AUFS_EXPORT
-+ depends on 64BIT && !(ALPHA || S390)
-+ default y
++config AUFS_DEBUG
++ bool "Debug aufs"
+ help
-+ Automatic configuration for internal use.
-+ /* typedef unsigned long/int __kernel_ino_t */
-+ /* alpha and s390x are int */
++ Enable this to compile aufs internal debug code.
++ It will have a negative impact to the performance.
+
-+config AUFS_POLL
++config AUFS_MAGIC_SYSRQ
+ bool
++ depends on AUFS_DEBUG && MAGIC_SYSRQ
++ default y
+ help
+ Automatic configuration for internal use.
++ When aufs supports Magic SysRq, enabled automatically.
+endif
-diff -Nur linux-2.6.31-vanilla/fs/aufs/loop.c linux-2.6.31/fs/aufs/loop.c
---- linux-2.6.31-vanilla/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/loop.c 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/loop.c linux-2.6.33.1/fs/aufs/loop.c
+--- linux-2.6.33.1-vanilla/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/loop.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,55 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ && '0' <= c && c <= '9'
+ && strncmp(current->comm, "loop", 4) == 0;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/loop.h linux-2.6.31/fs/aufs/loop.h
---- linux-2.6.31-vanilla/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/loop.h 2009-09-16 13:55:29.000000000 +0200
-@@ -0,0 +1,51 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/loop.h linux-2.6.33.1/fs/aufs/loop.h
+--- linux-2.6.33.1-vanilla/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/loop.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,43 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ struct dentry *h_d2);
+int au_test_loopback_kthread(void);
+#else
-+static inline
-+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1,
-+ struct dentry *h_d2)
-+{
-+ return 0;
-+}
-+
-+static inline int au_test_loopback_kthread(void)
-+{
-+ return 0;
-+}
++AuStubInt0(au_test_loopback_overlap, struct super_block *sb,
++ struct dentry *h_d1, struct dentry *h_d2)
++AuStubInt0(au_test_loopback_kthread, void)
+#endif /* BLK_DEV_LOOP */
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_LOOP_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/magic.mk linux-2.6.31/fs/aufs/magic.mk
---- linux-2.6.31-vanilla/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/magic.mk 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,52 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/magic.mk linux-2.6.33.1/fs/aufs/magic.mk
+--- linux-2.6.33.1-vanilla/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/magic.mk 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,54 @@
+
+# defined in ${srctree}/fs/fuse/inode.c
+# tristate
+ccflags-y += -DDLMFS_MAGIC=0x76a9f425
+endif
+
-+# defined in ${srctree}/fs/ramfs/inode.c
-+# always true
-+ccflags-y += -DRAMFS_MAGIC=0x858458f6
-+
+# defined in ${srctree}/fs/cifs/cifsfs.c
+# tristate
+ifdef CONFIG_CIFS_FS
+ifdef CONFIG_UBIFS_FS
+ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905
+endif
-diff -Nur linux-2.6.31-vanilla/fs/aufs/Makefile linux-2.6.31/fs/aufs/Makefile
---- linux-2.6.31-vanilla/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/Makefile 2009-09-16 13:55:29.000000000 +0200
-@@ -0,0 +1,24 @@
++
++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h
++# tristate
++ifdef CONFIG_HFSPLUS_FS
++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b
++endif
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/Makefile linux-2.6.33.1/fs/aufs/Makefile
+--- linux-2.6.33.1-vanilla/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/Makefile 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,37 @@
+
+include ${src}/magic.mk
++ifeq (${CONFIG_AUFS_FS},m)
++include ${src}/conf.mk
++endif
+-include ${src}/priv_def.mk
+
++# cf. include/linux/kernel.h
++# enable pr_debug
++ccflags-y += -DDEBUG
++ccflags-y += -D'pr_fmt(fmt)="aufs %s:%d:%s[%d]: " fmt, \
++ __func__, __LINE__, current->comm, current->pid'
++
+obj-$(CONFIG_AUFS_FS) += aufs.o
+aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
+ wkq.o vfsub.o dcsub.o \
+aufs-$(CONFIG_SYSFS) += sysfs.o
+aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
+aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o
++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o
+aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o
+aufs-$(CONFIG_AUFS_EXPORT) += export.o
+aufs-$(CONFIG_AUFS_POLL) += poll.o
+aufs-$(CONFIG_AUFS_RDU) += rdu.o
++aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o
++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
+aufs-$(CONFIG_AUFS_DEBUG) += debug.o
+aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
-diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c
---- linux-2.6.31-vanilla/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/module.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,173 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/module.c linux-2.6.33.1/fs/aufs/module.c
+--- linux-2.6.33.1-vanilla/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/module.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,166 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+static void au_cache_fin(void)
+{
+ int i;
++
++ /* including AuCache_HNOTIFY */
+ for (i = 0; i < AuCache_Last; i++)
+ if (au_cachep[i]) {
+ kmem_cache_destroy(au_cachep[i]);
+ " -- Advanced multi layered unification filesystem");
+MODULE_VERSION(AUFS_VERSION);
+
-+/* it should be 'byte', but param_set_byte() prints it by "%c" */
-+short aufs_nwkq = AUFS_NWKQ_DEF;
-+MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME);
-+module_param_named(nwkq, aufs_nwkq, short, S_IRUGO);
-+
+/* this module parameter has no meaning when SYSFS is disabled */
+int sysaufs_brs = 1;
+MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
+
+ sysaufs_brs_init();
+ au_debug_init();
-+
-+ err = -EINVAL;
-+ if (unlikely(aufs_nwkq <= 0))
-+ goto out;
-+
+ err = sysaufs_init();
+ if (unlikely(err))
+ goto out;
+ err = au_wkq_init();
+ if (unlikely(err))
+ goto out_sysaufs;
-+ err = au_hinotify_init();
++ err = au_hnotify_init();
+ if (unlikely(err))
+ goto out_wkq;
+ err = au_sysrq_init();
+ err = register_filesystem(&aufs_fs_type);
+ if (unlikely(err))
+ goto out_cache;
-+ pr_info(AUFS_NAME " " AUFS_VERSION "\n");
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
+ goto out; /* success */
+
+ out_cache:
+ out_sysrq:
+ au_sysrq_fin();
+ out_hin:
-+ au_hinotify_fin();
++ au_hnotify_fin();
+ out_wkq:
+ au_wkq_fin();
+ out_sysaufs:
+ unregister_filesystem(&aufs_fs_type);
+ au_cache_fin();
+ au_sysrq_fin();
-+ au_hinotify_fin();
++ au_hnotify_fin();
+ au_wkq_fin();
+ sysaufs_fin();
+}
+
+module_init(aufs_init);
+module_exit(aufs_exit);
-diff -Nur linux-2.6.31-vanilla/fs/aufs/module.h linux-2.6.31/fs/aufs/module.h
---- linux-2.6.31-vanilla/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/module.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/module.h linux-2.6.33.1/fs/aufs/module.h
+--- linux-2.6.33.1-vanilla/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/module.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,78 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+struct seq_file;
+
+/* module parameters */
-+extern short aufs_nwkq;
+extern int sysaufs_brs;
+
+/* ---------------------------------------------------------------------- */
+ AuCache_FINFO,
+ AuCache_VDIR,
+ AuCache_DEHSTR,
-+#ifdef CONFIG_AUFS_HINOTIFY
-+ AuCache_HINOTIFY,
++#ifdef CONFIG_AUFS_HNOTIFY
++ AuCache_HNOTIFY,
+#endif
+ AuCache_Last
+};
+
-+#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT)
++#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD)
+
+extern struct kmem_cache *au_cachep[];
+
+#define AuCacheFuncs(name, index) \
-+static inline void *au_cache_alloc_##name(void) \
++static inline struct au_##name *au_cache_alloc_##name(void) \
+{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
-+static inline void au_cache_free_##name(void *p) \
++static inline void au_cache_free_##name(struct au_##name *p) \
+{ kmem_cache_free(au_cachep[AuCache_##index], p); }
+
+AuCacheFuncs(dinfo, DINFO);
+AuCacheFuncs(icntnr, ICNTNR);
+AuCacheFuncs(finfo, FINFO);
+AuCacheFuncs(vdir, VDIR);
-+AuCacheFuncs(dehstr, DEHSTR);
-+
-+/* ---------------------------------------------------------------------- */
++AuCacheFuncs(vdir_dehstr, DEHSTR);
++#ifdef CONFIG_AUFS_HNOTIFY
++AuCacheFuncs(hnotify, HNOTIFY);
++#endif
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_MODULE_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c
---- linux-2.6.31-vanilla/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/opts.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,1546 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/opts.c linux-2.6.33.1/fs/aufs/opts.c
+--- linux-2.6.33.1-vanilla/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/opts.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,1565 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ {AuBrPerm_RO, NULL}
+};
+
-+static int br_perm_val(char *perm)
++static int noinline_for_stack br_perm_val(char *perm)
+{
+ int val;
+ substring_t args[MAX_OPT_ARGS];
+static match_table_t udbalevel = {
+ {AuOpt_UDBA_REVAL, "reval"},
+ {AuOpt_UDBA_NONE, "none"},
-+#ifdef CONFIG_AUFS_HINOTIFY
-+ {AuOpt_UDBA_HINOTIFY, "inotify"},
++#ifdef CONFIG_AUFS_HNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
++#ifdef CONFIG_AUFS_HFSNOTIFY
++ {AuOpt_UDBA_HNOTIFY, "fsnotify"},
++#else
++ {AuOpt_UDBA_HNOTIFY, "inotify"},
++#endif
+#endif
+ {-1, NULL}
+};
+
-+static int udba_val(char *str)
++static void au_warn_inotify(int val, char *str)
++{
++#ifdef CONFIG_AUFS_HINOTIFY
++ if (val == AuOpt_UDBA_HNOTIFY
++ && !strcmp(str, "inotify"))
++ AuWarn1("udba=inotify is deprecated, use udba=notify\n");
++#endif
++}
++
++static int noinline_for_stack udba_val(char *str)
+{
++ int val;
+ substring_t args[MAX_OPT_ARGS];
+
-+ return match_token(str, udbalevel, args);
++ val = match_token(str, udbalevel, args);
++ au_warn_inotify(val, str);
++ return val;
+}
+
+const char *au_optstr_udba(int udba)
+ * gave up calling memparse() since it uses simple_strtoull() instead of
+ * strict_...().
+ */
-+static int au_match_ull(substring_t *s, unsigned long long *result)
++static int noinline_for_stack
++au_match_ull(substring_t *s, unsigned long long *result)
+{
+ int err;
+ unsigned int len;
+ if (!au_match_ull(arg, &ull))
+ create->mfsrr_watermark = ull;
+ else {
-+ AuErr("bad integer in %s\n", str);
++ pr_err("bad integer in %s\n", str);
+ err = -EINVAL;
+ }
+
+ if (!match_int(arg, &n) && 0 <= n)
+ create->mfs_second = n;
+ else {
-+ AuErr("bad integer in %s\n", str);
++ pr_err("bad integer in %s\n", str);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
-+static int au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
++static int noinline_for_stack
++au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
+{
+ int err, e;
+ substring_t args[MAX_OPT_ARGS];
+ {-1, NULL}
+};
+
-+static int au_wbr_copyup_val(char *str)
++static int noinline_for_stack au_wbr_copyup_val(char *str)
+{
+ substring_t args[MAX_OPT_ARGS];
+
+ opt->type = Opt_add;
+ goto out;
+ }
-+ AuErr("lookup failed %s (%d)\n", add->pathname, err);
++ pr_err("lookup failed %s (%d)\n", add->pathname, err);
+ err = -EINVAL;
+
+ out:
+
+ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
+ if (unlikely(err))
-+ AuErr("lookup failed %s (%d)\n", del->pathname, err);
++ pr_err("lookup failed %s (%d)\n", del->pathname, err);
+
+ return err;
+}
+ root = sb->s_root;
+ aufs_read_lock(root, AuLock_FLUSH);
+ if (bindex < 0 || au_sbend(sb) < bindex) {
-+ AuErr("out of bounds, %d\n", bindex);
++ pr_err("out of bounds, %d\n", bindex);
+ goto out;
+ }
+
+}
+#endif
+
-+static int au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
++static int noinline_for_stack
++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
+{
+ int err;
+ struct path path;
+ mod->path = args[0].from;
+ p = strchr(mod->path, '=');
+ if (unlikely(!p)) {
-+ AuErr("no permssion %s\n", args[0].from);
++ pr_err("no permssion %s\n", args[0].from);
+ goto out;
+ }
+
+ *p++ = 0;
+ err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
+ if (unlikely(err)) {
-+ AuErr("lookup failed %s (%d)\n", mod->path, err);
++ pr_err("lookup failed %s (%d)\n", mod->path, err);
+ goto out;
+ }
+
+ root = sb->s_root;
+ aufs_read_lock(root, AuLock_FLUSH);
+ if (bindex < 0 || au_sbend(sb) < bindex) {
-+ AuErr("out of bounds, %d\n", bindex);
++ pr_err("out of bounds, %d\n", bindex);
+ goto out;
+ }
+
+ err = -EINVAL;
+ if (unlikely(file->f_dentry->d_sb == sb)) {
+ fput(file);
-+ AuErr("%s must be outside\n", args[0].from);
++ pr_err("%s must be outside\n", args[0].from);
+ goto out;
+ }
+
+ return err;
+}
+
-+static
-+int au_opts_parse_xino_itrunc_path(struct super_block *sb,
-+ struct au_opt_xino_itrunc *xino_itrunc,
-+ substring_t args[])
++static int noinline_for_stack
++au_opts_parse_xino_itrunc_path(struct super_block *sb,
++ struct au_opt_xino_itrunc *xino_itrunc,
++ substring_t args[])
+{
+ int err;
+ aufs_bindex_t bend, bindex;
+
+ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
+ if (unlikely(err)) {
-+ AuErr("lookup failed %s (%d)\n", args[0].from, err);
++ pr_err("lookup failed %s (%d)\n", args[0].from, err);
+ goto out;
+ }
+
+ path_put(&path);
+
+ if (unlikely(xino_itrunc->bindex < 0)) {
-+ AuErr("no such branch %s\n", args[0].from);
++ pr_err("no such branch %s\n", args[0].from);
+ err = -EINVAL;
+ }
+
+ break;
+ case Opt_add:
+ if (unlikely(match_int(&a->args[0], &n))) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ bindex = n;
+ case Opt_idel:
+ del->pathname = "(indexed)";
+ if (unlikely(match_int(&args[0], &n))) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ err = au_opts_parse_idel(sb, n, &opt->del, a->args);
+ case Opt_imod:
+ u.mod->path = "(indexed)";
+ if (unlikely(match_int(&a->args[0], &n))) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
+ case Opt_itrunc_xino:
+ u.xino_itrunc = &opt->xino_itrunc;
+ if (unlikely(match_int(&a->args[0], &n))) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ u.xino_itrunc->bindex = n;
+ aufs_read_lock(root, AuLock_FLUSH);
+ if (n < 0 || au_sbend(sb) < n) {
-+ AuErr("out of bounds, %d\n", n);
++ pr_err("out of bounds, %d\n", n);
+ aufs_read_unlock(root, !AuLock_IR);
+ break;
+ }
+ if (unlikely(match_int(&a->args[0], &n)
+ || n < 0
+ || n > KMALLOC_MAX_SIZE)) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ if (unlikely(n && n < NAME_MAX)) {
-+ AuErr("rdblk must be larger than %d\n",
-+ NAME_MAX);
++ pr_err("rdblk must be larger than %d\n",
++ NAME_MAX);
+ break;
+ }
+ opt->rdblk = n;
+ || n < 0
+ || n * sizeof(struct hlist_head)
+ > KMALLOC_MAX_SIZE)) {
-+ AuErr("bad integer in %s\n", opt_str);
++ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ opt->rdhash = n;
+ err = 0;
+ opt->type = token;
+ } else
-+ AuErr("wrong value, %s\n", opt_str);
++ pr_err("wrong value, %s\n", opt_str);
+ break;
+
+ case Opt_wbr_create:
+ err = 0;
+ opt->type = token;
+ } else
-+ AuErr("wrong value, %s\n", opt_str);
++ pr_err("wrong value, %s\n", opt_str);
+ break;
+ case Opt_wbr_copyup:
+ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
+ err = 0;
+ opt->type = token;
+ } else
-+ AuErr("wrong value, %s\n", opt_str);
++ pr_err("wrong value, %s\n", opt_str);
+ break;
+
+ case Opt_ignore:
-+ AuWarn("ignored %s\n", opt_str);
++ pr_warning("ignored %s\n", opt_str);
+ /*FALLTHROUGH*/
+ case Opt_ignore_silent:
+ skipped = 1;
+ err = 0;
+ break;
+ case Opt_err:
-+ AuErr("unknown option %s\n", opt_str);
++ pr_err("unknown option %s\n", opt_str);
+ break;
+ }
+
+
+ if (!(sb_flags & MS_RDONLY)) {
+ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
-+ AuWarn("first branch should be rw\n");
++ pr_warning("first branch should be rw\n");
+ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
-+ AuWarn("shwh should be used with ro\n");
++ pr_warning("shwh should be used with ro\n");
+ }
+
-+ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HINOTIFY)
++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
+ && !au_opt_test(sbinfo->si_mntflags, XINO))
-+ AuWarn("udba=inotify requires xino\n");
++ pr_warning("udba=*notify requires xino\n");
+
+ err = 0;
+ root = sb->s_root;
+ continue;
+
+ hdir = au_hi(dir, bindex);
-+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+ if (wbr)
+ wbr_wh_write_lock(wbr);
+ err = au_wh_init(au_h_dptr(root, bindex), br, sb);
+ if (wbr)
+ wbr_wh_write_unlock(wbr);
-+ au_hin_imtx_unlock(hdir);
++ au_hn_imtx_unlock(hdir);
+
+ if (!err && do_free) {
+ kfree(wbr);
+ bend = au_sbend(sb);
+ if (unlikely(bend < 0)) {
+ err = -EINVAL;
-+ AuErr("no branches\n");
++ pr_err("no branches\n");
+ goto out;
+ }
+
+ /* restore udba */
+ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
+ sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA);
-+ if (au_opt_test(tmp, UDBA_HINOTIFY)) {
++ if (au_opt_test(tmp, UDBA_HNOTIFY)) {
+ struct inode *dir = sb->s_root->d_inode;
-+ au_reset_hinotify(dir,
-+ au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
+ }
+
+ out:
+{
+ return au_mntflags(sb) & AuOptMask_UDBA;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.h linux-2.6.31/fs/aufs/opts.h
---- linux-2.6.31-vanilla/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/opts.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/opts.h linux-2.6.33.1/fs/aufs/opts.h
+--- linux-2.6.33.1-vanilla/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/opts.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,196 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */
+#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */
+#define AuOpt_UDBA_REVAL (1 << 3)
-+#define AuOpt_UDBA_HINOTIFY (1 << 4)
++#define AuOpt_UDBA_HNOTIFY (1 << 4)
+#define AuOpt_SHWH (1 << 5) /* show whiteout */
+#define AuOpt_PLINK (1 << 6) /* pseudo-link */
+#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */
+#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */
+#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */
+
-+#ifndef CONFIG_AUFS_HINOTIFY
-+#undef AuOpt_UDBA_HINOTIFY
-+#define AuOpt_UDBA_HINOTIFY 0
++#ifndef CONFIG_AUFS_HNOTIFY
++#undef AuOpt_UDBA_HNOTIFY
++#define AuOpt_UDBA_HNOTIFY 0
+#endif
+#ifndef CONFIG_AUFS_SHWH
+#undef AuOpt_SHWH
+ | AuOpt_WARN_PERM)
+#define AuOptMask_UDBA (AuOpt_UDBA_NONE \
+ | AuOpt_UDBA_REVAL \
-+ | AuOpt_UDBA_HINOTIFY)
++ | AuOpt_UDBA_HNOTIFY)
+
+#define au_opt_test(flags, name) (flags & AuOpt_##name)
+#define au_opt_set(flags, name) do { \
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_OPTS_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/plink.c linux-2.6.31/fs/aufs/plink.c
---- linux-2.6.31-vanilla/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/plink.c 2009-09-16 13:55:29.000000000 +0200
-@@ -0,0 +1,396 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/plink.c linux-2.6.33.1/fs/aufs/plink.c
+--- linux-2.6.33.1-vanilla/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/plink.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,430 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ * during a user process maintains the pseudo-links,
+ * prohibit adding a new plink and branch manipulation.
+ */
-+void au_plink_block_maintain(struct super_block *sb)
++void au_plink_maint_block(struct super_block *sb)
+{
+ struct au_sbinfo *sbi = au_sbi(sb);
+
+ SiMustAnyLock(sb);
+
+ /* gave up wake_up_bit() */
-+ wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK));
++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint);
++}
++
++void au_plink_maint_leave(struct file *file)
++{
++ struct au_sbinfo *sbinfo;
++ int iam;
++
++ AuDebugOn(atomic_long_read(&file->f_count));
++
++ sbinfo = au_sbi(file->f_dentry->d_sb);
++ spin_lock(&sbinfo->si_plink_maint_lock);
++ iam = (sbinfo->si_plink_maint == file);
++ if (iam)
++ sbinfo->si_plink_maint = NULL;
++ spin_unlock(&sbinfo->si_plink_maint_lock);
++ if (iam)
++ wake_up_all(&sbinfo->si_plink_wq);
++}
++
++static int au_plink_maint_enter(struct file *file)
++{
++ int err;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ sb = file->f_dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ /* make sure i am the only one in this fs */
++ si_write_lock(sb);
++ /* spin_lock(&sbinfo->si_plink_maint_lock); */
++ if (!sbinfo->si_plink_maint)
++ sbinfo->si_plink_maint = file;
++ else
++ err = -EBUSY;
++ /* spin_unlock(&sbinfo->si_plink_maint_lock); */
++ si_write_unlock(sb);
++
++ return err;
+}
+
+/* ---------------------------------------------------------------------- */
+ spin_unlock(&sbinfo->si_plink.spin);
+
+ if (!err) {
-+ au_plink_block_maintain(sb);
++ au_plink_maint_block(sb);
+ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
+ }
+
+ if (unlikely(cnt > AUFS_PLINK_WARN))
+ AuWarn1("unexpectedly many pseudo links, %d\n", cnt);
+ if (unlikely(err)) {
-+ AuWarn("err %d, damaged pseudo link.\n", err);
++ pr_warning("err %d, damaged pseudo link.\n", err);
+ if (!found && plink)
+ do_put_plink(plink, /*do_del*/1);
+ }
+ * pseudo-link maintenance mode,
+ * cleared by aufs_release_dir()
+ */
-+ si_write_lock(sb);
-+ if (!au_ftest_si(sbinfo, MAINTAIN_PLINK)) {
-+ au_fset_si(sbinfo, MAINTAIN_PLINK);
-+ au_fi(file)->fi_maintain_plink = 1;
-+ } else
-+ err = -EBUSY;
-+ si_write_unlock(sb);
++ err = au_plink_maint_enter(file);
+ break;
+ case AUFS_CTL_PLINK_CLEAN:
+ aufs_write_lock(sb->s_root);
+ aufs_write_unlock(sb->s_root);
+ break;
+ default:
++ /* err = -ENOTTY; */
+ err = -EINVAL;
+ }
+ out:
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/poll.c linux-2.6.31/fs/aufs/poll.c
---- linux-2.6.31-vanilla/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/poll.c 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/poll.c linux-2.6.33.1/fs/aufs/poll.c
+--- linux-2.6.33.1-vanilla/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/poll.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,56 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ AuTraceErr((int)mask);
+ return mask;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c
---- linux-2.6.31-vanilla/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/rdu.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,331 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/rdu.c linux-2.6.33.1/fs/aufs/rdu.c
+--- linux-2.6.33.1-vanilla/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/rdu.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,330 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ * readdir in userspace.
+ */
+
++#include <linux/fs_stack.h>
+#include <linux/security.h>
+#include <linux/uaccess.h>
+#include <linux/aufs_type.h>
+ ent.bindex = rdu->cookie.bindex;
+ ent.type = d_type;
+ ent.nlen = nlen;
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ ent.type = DT_UNKNOWN;
+
+ err = -EFAULT;
+ if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
+ sb = file->f_dentry->d_sb;
+ si_read_lock(sb, AuLock_FLUSH);
+ while (nent-- > 0) {
-+ err = !access_ok(VERIFY_WRITE, u->e, sizeof(ent));
-+ if (unlikely(err)) {
-+ err = -EFAULT;
-+ AuTraceErr(err);
-+ break;
-+ }
-+
+ err = copy_from_user(&ent, u->e, sizeof(ent));
++ if (!err)
++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
+ if (unlikely(err)) {
+ err = -EFAULT;
+ AuTraceErr(err);
+ break;
+
+ default:
++ /* err = -ENOTTY; */
+ err = -EINVAL;
+ }
+
+ AuTraceErr(err);
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/rwsem.h linux-2.6.31/fs/aufs/rwsem.h
---- linux-2.6.31-vanilla/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/rwsem.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,186 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/rwsem.h linux-2.6.33.1/fs/aufs/rwsem.h
+--- linux-2.6.33.1-vanilla/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/rwsem.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,187 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#ifdef __KERNEL__
+
+#include <linux/rwsem.h>
++#include "debug.h"
+
+struct au_rwsem {
+ struct rw_semaphore rwsem;
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_RWSEM_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c
---- linux-2.6.31-vanilla/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/sbinfo.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,208 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/sbinfo.c linux-2.6.33.1/fs/aufs/sbinfo.c
+--- linux-2.6.33.1-vanilla/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/sbinfo.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,202 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+ AuDebugOn(!list_empty(&sbinfo->si_plink.head));
++ AuDebugOn(sbinfo->si_plink_maint);
+
+ sb = sbinfo->si_sb;
+ si_write_lock(sb);
+ struct au_sbinfo *sbinfo;
+
+ err = -ENOMEM;
-+ sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS);
++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS);
+ if (unlikely(!sbinfo))
+ goto out;
+
+ if (unlikely(!sbinfo->si_branch))
+ goto out_sbinfo;
+
-+ memset(&sbinfo->si_kobj, 0, sizeof(sbinfo->si_kobj));
+ err = sysaufs_si_init(sbinfo);
+ if (unlikely(err))
+ goto out_br;
+
+ au_nwt_init(&sbinfo->si_nowait);
+ au_rw_init_wlock(&sbinfo->si_rwsem);
-+ sbinfo->si_generation = 0;
-+ sbinfo->au_si_status = 0;
+ sbinfo->si_bend = -1;
-+ sbinfo->si_last_br_id = 0;
+
+ sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
+ sbinfo->si_wbr_create = AuWbrCreate_Def;
-+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + AuWbrCopyup_Def;
-+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + AuWbrCreate_Def;
++ 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;
+
+ sbinfo->si_mntflags = AuOpt_Def;
+
-+ sbinfo->si_xread = NULL;
-+ sbinfo->si_xwrite = NULL;
-+ sbinfo->si_xib = NULL;
+ mutex_init(&sbinfo->si_xib_mtx);
-+ sbinfo->si_xib_buf = NULL;
+ sbinfo->si_xino_brid = -1;
+ /* leave si_xib_last_pindex and si_xib_next_bit */
+
+
+ au_spl_init(&sbinfo->si_plink);
+ init_waitqueue_head(&sbinfo->si_plink_wq);
++ spin_lock_init(&sbinfo->si_plink_maint_lock);
+
+ /* leave other members for sysaufs and si_mnt. */
+ sbinfo->si_sb = sb;
+ di_write_unlock2(d1, d2);
+ si_read_unlock(d1->d_sb);
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/spl.h linux-2.6.31/fs/aufs/spl.h
---- linux-2.6.31-vanilla/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/spl.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/spl.h linux-2.6.33.1/fs/aufs/spl.h
+--- linux-2.6.33.1-vanilla/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/spl.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,57 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_SPL_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c
---- linux-2.6.31-vanilla/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/super.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,874 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/super.c linux-2.6.33.1/fs/aufs/super.c
+--- linux-2.6.33.1-vanilla/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/super.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,838 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ si_read_unlock(sb);
+ return 0;
+
-+#undef Deleted
+#undef AuBool
+#undef AuStr
++#undef AuUInt
+}
+
+/* ---------------------------------------------------------------------- */
+
+ if (!err) {
+ buf->f_type = AUFS_SUPER_MAGIC;
-+ buf->f_namelen -= AUFS_WH_PFX_LEN;
++ buf->f_namelen = AUFS_MAX_NAMELEN;
+ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid));
+ }
+ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */
+
+/* ---------------------------------------------------------------------- */
+
-+/* try flushing the lower fs at aufs remount/unmount time */
-+
-+static void au_fsync_br(struct super_block *sb)
-+{
-+ aufs_bindex_t bend, bindex;
-+ int brperm;
-+ struct au_branch *br;
-+ struct super_block *h_sb;
-+
-+ bend = au_sbend(sb);
-+ for (bindex = 0; bindex < bend; bindex++) {
-+ br = au_sbr(sb, bindex);
-+ brperm = br->br_perm;
-+ if (brperm == AuBrPerm_RR || brperm == AuBrPerm_RRWH)
-+ continue;
-+ h_sb = br->br_mnt->mnt_sb;
-+ if (bdev_read_only(h_sb->s_bdev))
-+ continue;
-+
-+ lockdep_off();
-+ down_write(&h_sb->s_umount);
-+ shrink_dcache_sb(h_sb);
-+ sync_filesystem(h_sb);
-+ up_write(&h_sb->s_umount);
-+ lockdep_on();
-+ }
-+}
-+
+/*
+ * this IS NOT for super_operations.
+ * I guess it will be reverted someday.
+ return;
+
+ si_write_lock(sb);
-+ au_fsync_br(sb);
+ if (au_opt_test(au_mntflags(sb), PLINK))
+ au_plink_put(sb);
+ if (sbinfo->si_wbr_create_ops->fin)
+ struct inode *inode = dentry->d_inode;
+ err = au_refresh_hinode(inode, dentry);
+ if (!err && type == S_IFDIR)
-+ au_reset_hinotify(inode, dir_flags);
++ au_hn_reset(inode, dir_flags);
+ }
+ if (unlikely(err))
-+ AuErr("unrecoverable error %d, %.*s\n", err, AuDLNPair(dentry));
++ pr_err("unrecoverable error %d, %.*s\n",
++ err, AuDLNPair(dentry));
+
+ di_read_unlock(parent, AuLock_IR);
+ dput(parent);
+ DiMustNoWaiters(root);
+ inode = root->d_inode;
+ IiMustNoWaiters(inode);
-+ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1));
++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
+ di_write_unlock(root);
+
+ err = refresh_dir(root, sigen);
+ if (unlikely(err)) {
+ au_fset_si(sbinfo, FAILED_REFRESH_DIRS);
-+ AuWarn("Refreshing directories failed, ignored (%d)\n", err);
++ pr_warning("Refreshing directories failed, ignored (%d)\n",
++ err);
+ }
+
+ if (au_ftest_opts(flags, REFRESH_NONDIR)) {
+ err = refresh_nondir(root, sigen, !err);
+ if (unlikely(err))
-+ AuWarn("Refreshing non-directories failed, ignored"
-+ "(%d)\n", err);
++ pr_warning("Refreshing non-directories failed, ignored"
++ "(%d)\n", err);
+ }
+
+ /* aufs_write_lock() calls ..._child() */
+ if (!data || !*data) {
+ aufs_write_lock(root);
+ err = au_opts_verify(sb, *flags, /*pending*/0);
-+ if (!err)
-+ au_fsync_br(sb);
+ aufs_write_unlock(root);
+ goto out;
+ }
+ inode = root->d_inode;
+ mutex_lock(&inode->i_mutex);
+ aufs_write_lock(root);
-+ au_fsync_br(sb);
+
+ /* au_opts_remount() may return an error */
+ err = au_opts_remount(sb, &opts);
+ return err;
+}
+
-+static struct super_operations aufs_sop = {
++static const struct super_operations aufs_sop = {
+ .alloc_inode = aufs_alloc_inode,
+ .destroy_inode = aufs_destroy_inode,
+ .drop_inode = generic_delete_inode,
+
+ if (unlikely(!arg || !*arg)) {
+ err = -EINVAL;
-+ AuErr("no arg\n");
++ pr_err("no arg\n");
+ goto out;
+ }
+
+
+ /* lock vfs_inode first, then aufs. */
+ mutex_lock(&inode->i_mutex);
-+ inode->i_op = &aufs_dir_iop;
-+ inode->i_fop = &aufs_dir_fop;
+ aufs_write_lock(root);
+ err = au_opts_mount(sb, &opts);
+ au_opts_free(&opts);
-+ if (unlikely(err))
-+ goto out_unlock;
+ aufs_write_unlock(root);
+ mutex_unlock(&inode->i_mutex);
-+ goto out_opts; /* success */
++ if (!err)
++ goto out_opts; /* success */
+
-+ out_unlock:
-+ aufs_write_unlock(root);
-+ mutex_unlock(&inode->i_mutex);
+ out_root:
+ dput(root);
+ sb->s_root = NULL;
+ /* no need to __module_get() and module_put(). */
+ .owner = THIS_MODULE,
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h
---- linux-2.6.31-vanilla/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/super.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,384 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/super.h linux-2.6.33.1/fs/aufs/super.h
+--- linux-2.6.33.1-vanilla/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/super.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,361 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ /* pseudo_link list */
+ struct au_splhead si_plink;
+ wait_queue_head_t si_plink_wq;
++ spinlock_t si_plink_maint_lock;
++ struct file *si_plink_maint;
+
+ /*
+ * sysfs and lifetime management.
+ * if it is false, refreshing dirs at access time is unnecesary
+ */
+#define AuSi_FAILED_REFRESH_DIRS 1
-+#define AuSi_MAINTAIN_PLINK (1 << 1) /* ioctl */
+static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
+ unsigned int flag)
+{
+/* ---------------------------------------------------------------------- */
+
+/* policy to select one among writable branches */
-+#define AuWbrCopyup(sbinfo, args...) \
-+ ((sbinfo)->si_wbr_copyup_ops->copyup(args))
-+#define AuWbrCreate(sbinfo, args...) \
-+ ((sbinfo)->si_wbr_create_ops->create(args))
++#define AuWbrCopyup(sbinfo, ...) \
++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__))
++#define AuWbrCreate(sbinfo, ...) \
++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__))
+
+/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */
+#define AuLock_DW 1 /* write-lock dentry */
+ return -ESTALE;
+}
+#else
-+static inline void au_export_init(struct super_block *sb)
-+{
-+ /* nothing */
-+}
-+
-+static inline int au_test_nfsd(struct task_struct *tsk)
-+{
-+ return 0;
-+}
-+
-+static inline int au_xigen_inc(struct inode *inode)
-+{
-+ return 0;
-+}
-+
-+static inline int au_xigen_new(struct inode *inode)
-+{
-+ return 0;
-+}
-+
-+static inline int au_xigen_set(struct super_block *sb, struct file *base)
-+{
-+ return 0;
-+}
-+
-+static inline void au_xigen_clr(struct super_block *sb)
-+{
-+ /* empty */
-+}
-+
++AuStubVoid(au_export_init, struct super_block *sb)
++AuStubInt0(au_test_nfsd, struct task_struct *tsk)
++AuStubInt0(au_xigen_inc, struct inode *inode)
++AuStubInt0(au_xigen_new, struct inode *inode)
++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
++AuStubVoid(au_xigen_clr, struct super_block *sb)
+static inline int au_busy_or_stale(void)
+{
+ return -EBUSY;
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_SUPER_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.c linux-2.6.31/fs/aufs/sysaufs.c
---- linux-2.6.31-vanilla/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/sysaufs.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,104 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/sysaufs.c linux-2.6.33.1/fs/aufs/sysaufs.c
+--- linux-2.6.33.1-vanilla/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/sysaufs.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,107 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask));
+ } while (!sysaufs_si_mask);
+
++ err = -EINVAL;
+ sysaufs_ket = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
++ if (unlikely(!sysaufs_ket))
++ goto out;
+ err = PTR_ERR(sysaufs_ket);
+ if (IS_ERR(sysaufs_ket))
+ goto out;
+ out:
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.h linux-2.6.31/fs/aufs/sysaufs.h
---- linux-2.6.31-vanilla/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/sysaufs.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,120 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/sysaufs.h linux-2.6.33.1/fs/aufs/sysaufs.h
+--- linux-2.6.33.1-vanilla/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/sysaufs.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,105 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#else
+#define sysaufs_attr_group NULL
+
-+static inline
-+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
-+{
-+ return 0;
-+}
++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb)
+
+static inline
+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
+ return 0;
+}
+
-+static inline void sysaufs_br_init(struct au_branch *br)
-+{
-+ /* empty */
-+}
-+
-+static inline void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
-+{
-+ /* nothing */
-+}
-+
-+static inline void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
-+{
-+ /* nothing */
-+}
++AuStubVoid(sysaufs_br_init, struct au_branch *br)
++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex)
++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex)
+
+static inline void sysaufs_brs_init(void)
+{
+
+#endif /* __KERNEL__ */
+#endif /* __SYSAUFS_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c
---- linux-2.6.31-vanilla/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/sysfs.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,210 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/sysfs.c linux-2.6.33.1/fs/aufs/sysfs.c
+--- linux-2.6.33.1-vanilla/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/sysfs.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,248 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#include <linux/sysfs.h>
+#include "aufs.h"
+
++#ifdef CONFIG_AUFS_FS_MODULE
++/* this entry violates the "one line per file" policy of sysfs */
++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ static char *conf =
++/* this file is generated at compiling */
++#include "conf.str"
++ ;
++
++ err = snprintf(buf, PAGE_SIZE, conf);
++ if (unlikely(err >= PAGE_SIZE))
++ err = -EFBIG;
++ return err;
++}
++
++static struct kobj_attribute au_config_attr = __ATTR_RO(config);
++#endif
++
+static struct attribute *au_attr[] = {
++#ifdef CONFIG_AUFS_FS_MODULE
++ &au_config_attr.attr,
++#endif
+ NULL, /* need to NULL terminate the list of attributes */
+};
+
+
+/* todo: file size may exceed PAGE_SIZE */
+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
-+ char *buf)
++ char *buf)
+{
+ ssize_t err;
+ long l;
+
+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
+ sb = sbinfo->si_sb;
-+ si_noflush_read_lock(sb);
++
++ /*
++ * prevent a race condition between sysfs and aufs.
++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which
++ * prohibits maintaining the sysfs entries.
++ * hew we acquire read lock after sysfs_get_active_two().
++ * on the other hand, the remount process may maintain the sysfs/aufs
++ * entries after acquiring write lock.
++ * it can cause a deadlock.
++ * simply we gave up processing read here.
++ */
++ err = -EBUSY;
++ if (unlikely(!si_noflush_read_trylock(sb)))
++ goto out;
+
+ seq = au_seq(buf, PAGE_SIZE);
+ err = PTR_ERR(seq);
+ if (IS_ERR(seq))
-+ goto out;
++ goto out_unlock;
+
+ name = (void *)attr->name;
+ cattr = sysaufs_si_attrs;
+ err = -EFBIG;
+ }
+ kfree(seq);
-+ out:
++ out_unlock:
+ si_read_unlock(sb);
++ out:
+ return err;
+}
+
+ "%d", bindex);
+ err = sysfs_create_file(kobj, &br->br_attr);
+ if (unlikely(err))
-+ AuWarn("failed %s under sysfs(%d)\n", br->br_name, err);
++ pr_warning("failed %s under sysfs(%d)\n",
++ br->br_name, err);
+ }
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/sysrq.c linux-2.6.31/fs/aufs/sysrq.c
---- linux-2.6.31-vanilla/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/sysrq.c 2009-09-16 13:55:29.000000000 +0200
-@@ -0,0 +1,115 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/sysrq.c linux-2.6.33.1/fs/aufs/sysrq.c
+--- linux-2.6.33.1-vanilla/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/sysrq.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,119 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ au_debug(1);
+
+ sbinfo = au_sbi(sb);
-+ pr_warning("si=%lx\n", sysaufs_si_id(sbinfo));
-+ pr_warning(AUFS_NAME ": superblock\n");
++ /* since we define pr_fmt, call printk directly */
++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
++ printk(KERN_WARNING AUFS_NAME ": superblock\n");
+ au_dpri_sb(sb);
-+ pr_warning(AUFS_NAME ": root dentry\n");
++ printk(KERN_WARNING AUFS_NAME ": root dentry\n");
+ au_dpri_dentry(sb->s_root);
-+ pr_warning(AUFS_NAME ": root inode\n");
++ printk(KERN_WARNING AUFS_NAME ": root inode\n");
+ au_dpri_inode(sb->s_root->d_inode);
+#if 0
+ struct inode *i;
-+ pr_warning(AUFS_NAME ": isolated inode\n");
++ printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
+ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
+ if (list_empty(&i->i_dentry))
+ au_dpri_inode(i);
+#endif
-+ pr_warning(AUFS_NAME ": files\n");
-+ list_for_each_entry(file, &sb->s_files, f_u.fu_list)
-+ if (!special_file(file->f_dentry->d_inode->i_mode))
++ printk(KERN_WARNING AUFS_NAME ": files\n");
++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
++ umode_t mode;
++ mode = file->f_dentry->d_inode->i_mode;
++ if (!special_file(mode) || au_special_file(mode))
+ au_dpri_file(file);
++ }
+
+ au_plevel = plevel;
+ au_debug(0);
+ if ('a' <= key && key <= 'z')
+ err = register_sysrq_key(key, &au_sysrq_op);
+ if (unlikely(err))
-+ AuErr("err %d, sysrq=%c\n", err, key);
++ pr_err("err %d, sysrq=%c\n", err, key);
+ return err;
+}
+
+ int err;
+ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op);
+ if (unlikely(err))
-+ AuErr("err %d (ignored)\n", err);
++ pr_err("err %d (ignored)\n", err);
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c
---- linux-2.6.31-vanilla/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/vdir.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,879 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/vdir.c linux-2.6.33.1/fs/aufs/vdir.c
+--- linux-2.6.33.1-vanilla/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/vdir.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,884 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+static unsigned int calc_size(int nlen)
+{
-+ BUILD_BUG_ON(sizeof(ino_t) != sizeof(long));
+ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
+}
+
+ n = sz;
+ if (sz < AUFS_RDHASH_DEF)
+ n = AUFS_RDHASH_DEF;
-+ /* AuInfo("n %u\n", n); */
++ /* pr_info("n %u\n", n); */
+ return n;
+}
+
+ n = 0;
+ hlist_for_each(pos, head)
+ n++;
-+ AuInfo("%lu\n", n);
++ pr_info("%lu\n", n);
+#endif
+}
+
+
+ hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
+ /* hlist_del(pos); */
-+ au_cache_free_dehstr(tpos);
++ au_cache_free_vdir_dehstr(tpos);
+ }
+}
+
+ }
+
+ err = -ENOMEM;
-+ dehstr = au_cache_alloc_dehstr();
++ dehstr = au_cache_alloc_vdir_dehstr();
+ if (unlikely(!dehstr))
+ goto out;
+
+ if (!vdir->vd_deblk_sz) {
+ /* estimate the apropriate size for deblk */
+ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
-+ /* AuInfo("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
+ }
+ vdir->vd_nblk = 0;
+ vdir->vd_version = 0;
+
+ sb = arg->file->f_dentry->d_sb;
+ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
-+ if (!arg->err)
++ if (!arg->err) {
++ if (unlikely(nlen > AUFS_MAX_NAMELEN))
++ d_type = DT_UNKNOWN;
+ arg->err = append_de(arg->vdir, name, nlen, ino,
+ d_type, &arg->delist);
++ }
+ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
+ name += AUFS_WH_PFX_LEN;
+ nlen -= AUFS_WH_PFX_LEN;
+ if (shwh)
+ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
+ &ino);
-+ if (!arg->err)
++ if (!arg->err) {
++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN)
++ d_type = DT_UNKNOWN;
+ arg->err = au_nhash_append_wh
+ (&arg->whlist, name, nlen, ino, d_type,
+ arg->bindex, shwh);
++ }
+ }
+
+ out:
+ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
+
+ err = -ENOMEM;
-+ o = p = __getname();
++ o = p = __getname_gfp(GFP_NOFS);
+ if (unlikely(!p))
+ goto out;
+
+ /* smp_mb(); */
+ return 0;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c
---- linux-2.6.31-vanilla/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/vfsub.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,755 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/vfsub.c linux-2.6.33.1/fs/aufs/vfsub.c
+--- linux-2.6.33.1-vanilla/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/vfsub.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,790 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ * sub-routines for VFS
+ */
+
++#include <linux/file.h>
+#include <linux/ima.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+
+/* ---------------------------------------------------------------------- */
+
++static int au_conv_oflags(int flags)
++{
++ int mask = 0;
++
+#ifdef CONFIG_IMA
-+#error IMA is not supported since it does not work well. Wait for their fixing.
++ fmode_t fmode;
++
++ /* mask = MAY_OPEN; */
++ fmode = OPEN_FMODE(flags);
++ if (fmode & FMODE_READ)
++ mask |= MAY_READ;
++ if ((fmode & FMODE_WRITE)
++ || (flags & O_TRUNC))
++ mask |= MAY_WRITE;
++ /*
++ * if (flags & O_APPEND)
++ * mask |= MAY_APPEND;
++ */
++ if (flags & vfsub_fmode_to_uint(FMODE_EXEC))
++ mask |= MAY_EXEC;
++
++ AuDbg("flags 0x%x, mask 0x%x\n", flags, mask);
+#endif
+
-+struct file *vfsub_dentry_open(struct path *path, int flags,
-+ const struct cred *cred)
++ return mask;
++}
++
++struct file *vfsub_dentry_open(struct path *path, int flags)
+{
+ struct file *file;
++ int err;
+
-+ file = dentry_open(path->dentry, path->mnt, flags, cred);
++ path_get(path);
++ file = dentry_open(path->dentry, path->mnt, flags, current_cred());
+ if (IS_ERR(file))
-+ return file;
-+ /* as NFSD does, just call ima_..._get() simply after dentry_open */
-+ ima_counts_get(file);
++ goto out;
++
++ err = ima_file_check(file, au_conv_oflags(flags));
++ if (unlikely(err)) {
++ fput(file);
++ file = ERR_PTR(err);
++ }
++out:
+ return file;
+}
+
+{
+ struct file *file;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ file = filp_open(path, oflags, mode);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (IS_ERR(file))
+ goto out;
+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
+
+ out:
++ AuTraceErrPtr(path.dentry);
+ return path.dentry;
+}
+
+ IMustLock(nd->path.dentry->d_inode);
+
+ path.dentry = lookup_hash(nd);
-+ if (!IS_ERR(path.dentry) && path.dentry->d_inode)
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
+
++ out:
++ AuTraceErrPtr(path.dentry);
+ return path.dentry;
+}
+
+ lockdep_off();
+ d = lock_rename(d1, d2);
+ lockdep_on();
-+ au_hin_suspend(hdir1);
++ au_hn_suspend(hdir1);
+ if (hdir1 != hdir2)
-+ au_hin_suspend(hdir2);
++ au_hn_suspend(hdir2);
+
+ return d;
+}
+void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
+ struct dentry *d2, struct au_hinode *hdir2)
+{
-+ au_hin_resume(hdir1);
++ au_hn_resume(hdir1);
+ if (hdir1 != hdir2)
-+ au_hin_resume(hdir2);
++ au_hn_resume(hdir2);
+ lockdep_off();
+ unlock_rename(d1, d2);
+ lockdep_on();
+ if (unlikely(err))
+ goto out;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_link(src_dentry, dir, path->dentry);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (!err) {
+ struct path tmp = *path;
+ int did;
+ if (unlikely(err))
+ goto out;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_rename(src_dir, src_dentry, dir, path->dentry);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (!err) {
+ int did;
+
+ if (unlikely(err))
+ goto out;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_rmdir(dir, path->dentry);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (!err) {
+ struct path tmp = {
+ .dentry = path->dentry->d_parent,
+{
+ ssize_t err;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_write(file, ubuf, count, ppos);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (err >= 0)
+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+ return err;
+{
+ int err;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_readdir(file, filldir, arg);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (err >= 0)
+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
+ return err;
+{
+ long err;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = do_splice_to(in, ppos, pipe, len, flags);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (err >= 0)
+ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
+ return err;
+{
+ long err;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = do_splice_from(pipe, out, ppos, len, flags);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (err >= 0)
+ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
+ return err;
+ if (!err)
+ err = security_path_truncate(h_path, length, attr);
+ if (!err) {
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = do_truncate(h_path->dentry, length, attr, h_file);
-+ lockdep_on();
++ /* lockdep_on(); */
+ }
+
+ out_inode:
+
+ *a->errp = -EPERM;
+ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
-+ lockdep_off();
++ /* lockdep_off(); */
+ *a->errp = notify_change(a->path->dentry, a->ia);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (!*a->errp)
+ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
+ }
+ if (h_inode)
+ atomic_inc(&h_inode->i_count);
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ *a->errp = vfs_unlink(a->dir, d);
-+ lockdep_on();
++ /* lockdep_on(); */
+ if (!*a->errp) {
+ struct path tmp = {
+ .dentry = d->d_parent,
+
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h
---- linux-2.6.31-vanilla/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/vfsub.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,172 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/vfsub.h linux-2.6.33.1/fs/aufs/vfsub.h
+--- linux-2.6.33.1-vanilla/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/vfsub.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,175 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
-+#include <linux/fs_stack.h>
+
+/* ---------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------- */
+
-+static inline void vfsub_copy_inode_size(struct inode *inode,
-+ struct inode *h_inode)
-+{
-+ spin_lock(&inode->i_lock);
-+ fsstack_copy_inode_size(inode, h_inode);
-+ spin_unlock(&inode->i_lock);
-+}
-+
+int vfsub_update_h_iattr(struct path *h_path, int *did);
++struct file *vfsub_dentry_open(struct path *path, int flags);
+struct file *vfsub_filp_open(const char *path, int oflags, int mode);
-+struct file *vfsub_dentry_open(struct path *path, int flags,
-+ const struct cred *cred);
+int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
+ int len);
+int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
+int vfsub_rmdir(struct inode *dir, struct path *path);
+
-+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
-+int vfsub_sio_rmdir(struct inode *dir, struct path *path);
-+int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
-+int vfsub_notify_change(struct path *path, struct iattr *ia);
-+int vfsub_unlink(struct inode *dir, struct path *path, int force);
-+
+/* ---------------------------------------------------------------------- */
+
+ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
+ loff_t *ppos);
+int vfsub_readdir(struct file *file, filldir_t filldir, void *arg);
+
-+long vfsub_splice_to(struct file *in, loff_t *ppos,
-+ struct pipe_inode_info *pipe, size_t len,
-+ unsigned int flags);
-+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
-+ loff_t *ppos, size_t len, unsigned int flags);
-+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
-+ struct file *h_file);
++static inline unsigned int vfsub_file_flags(struct file *file)
++{
++ unsigned int flags;
++
++ spin_lock(&file->f_lock);
++ flags = file->f_flags;
++ spin_unlock(&file->f_lock);
++
++ return flags;
++}
+
+static inline void vfsub_file_accessed(struct file *h_file)
+{
+ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
+}
+
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file);
++
+/* ---------------------------------------------------------------------- */
+
+static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
+{
+ loff_t err;
+
-+ lockdep_off();
++ /* lockdep_off(); */
+ err = vfs_llseek(file, offset, origin);
-+ lockdep_on();
++ /* lockdep_on(); */
+ return err;
+}
+
+ return u.fm;
+}
+
++/* ---------------------------------------------------------------------- */
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_sio_rmdir(struct inode *dir, struct path *path);
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
++int vfsub_notify_change(struct path *path, struct iattr *ia);
++int vfsub_unlink(struct inode *dir, struct path *path, int force);
++
+#endif /* __KERNEL__ */
+#endif /* __AUFS_VFSUB_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/wbr_policy.c linux-2.6.31/fs/aufs/wbr_policy.c
---- linux-2.6.31-vanilla/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/wbr_policy.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,641 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/wbr_policy.c linux-2.6.33.1/fs/aufs/wbr_policy.c
+--- linux-2.6.33.1-vanilla/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/wbr_policy.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,637 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+ struct dentry *h_parent, void *arg)
+{
+ int err, rerr;
-+ aufs_bindex_t bend, bopq, bstart;
-+ unsigned char parent_opq;
++ aufs_bindex_t bopq, bstart;
+ struct path h_path;
+ struct dentry *parent;
+ struct inode *h_dir, *h_inode, *inode, *dir;
+ goto out_put;
+ au_fset_cpdown(args->flags, MADE_DIR);
+
-+ bend = au_dbend(dentry);
+ bopq = au_dbdiropq(dentry);
+ au_fclr_cpdown(args->flags, WHED);
+ au_fclr_cpdown(args->flags, DIROPQ);
+ au_fset_cpdown(args->flags, WHED);
+ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
+ au_fset_cpdown(args->flags, PARENT_OPQ);
-+ parent_opq = (au_ftest_cpdown(args->flags, PARENT_OPQ)
-+ && args->parent == dentry);
+ h_inode = h_path.dentry->d_inode;
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
+ if (au_ftest_cpdown(args->flags, WHED)) {
+ .fin = au_wbr_create_fin_mfs
+ }
+};
-diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c
---- linux-2.6.31-vanilla/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/whout.c 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/whout.c linux-2.6.33.1/fs/aufs/whout.c
+--- linux-2.6.33.1-vanilla/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/whout.c 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,1052 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+{
+ int err;
+ struct dentry *wh_dentry;
-+ struct inode *h_dir;
+
-+ h_dir = h_parent->d_inode;
+ if (!try_sio)
+ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL);
+ else
+struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
+ struct qstr *prefix)
+{
-+#define HEX_LEN 4
+ struct dentry *dentry;
+ int i;
-+ char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1
-+ + HEX_LEN + 1], *name, *p;
++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1],
++ *name, *p;
+ static unsigned short cnt;
+ struct qstr qs;
+
++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
++
+ name = defname;
+ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1;
+ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) {
+ dentry = ERR_PTR(-ENAMETOOLONG);
-+ if (unlikely(qs.len >= PATH_MAX))
++ if (unlikely(qs.len > NAME_MAX))
+ goto out;
+ dentry = ERR_PTR(-ENOMEM);
+ name = kmalloc(qs.len + 1, GFP_NOFS);
+ memcpy(p, prefix->name, prefix->len);
+ p += prefix->len;
+ *p++ = '.';
-+ AuDebugOn(name + qs.len + 1 - p <= HEX_LEN);
++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
+
+ qs.name = name;
+ for (i = 0; i < 3; i++) {
-+ sprintf(p, "%.*d", HEX_LEN, cnt++);
++ sprintf(p, "%.*d", AUFS_WH_TMP_LEN, cnt++);
+ dentry = au_sio_lkup_one(&qs, h_parent, br);
+ if (IS_ERR(dentry) || !dentry->d_inode)
+ goto out_name;
+ dput(dentry);
+ }
-+ /* AuWarn("could not get random name\n"); */
++ /* pr_warning("could not get random name\n"); */
+ dentry = ERR_PTR(-EEXIST);
+ AuDbg("%.*s\n", AuLNPair(&qs));
+ BUG();
+ if (name != defname)
+ kfree(name);
+ out:
++ AuTraceErrPtr(dentry);
+ return dentry;
-+#undef HEX_LEN
+}
+
+/*
+ dput(h_path.dentry);
+
+ out:
++ AuTraceErr(err);
+ return err;
+}
+
+ mnt_drop_write(whpath->mnt);
+ }
+ if (unlikely(err))
-+ AuWarn("failed removing %.*s (%d), ignored.\n",
-+ AuDLNPair(whpath->dentry), err);
++ pr_warning("failed removing %.*s (%d), ignored.\n",
++ AuDLNPair(whpath->dentry), err);
+}
+
+static int test_linkable(struct dentry *h_root)
+ if (h_dir->i_op->link)
+ return 0;
+
-+ AuErr("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n",
-+ AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n",
++ AuDLNPair(h_root), au_sbtype(h_root->d_sb));
+ return -ENOSYS;
+}
+
+ } else if (S_ISDIR(path->dentry->d_inode->i_mode))
+ err = 0;
+ else
-+ AuErr("unknown %.*s exists\n", AuDLNPair(path->dentry));
++ pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry));
+
+ return err;
+}
+ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode))
+ err = 0;
+ else
-+ AuErr("unknown %.*s/%.*s exists\n",
-+ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry));
++ pr_err("unknown %.*s/%.*s exists\n",
++ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry));
+ if (unlikely(err))
+ goto out;
+
+ if (wbr)
+ WbrWhMustWriteLock(wbr);
+
-+ h_dir = h_root->d_inode;
+ for (i = 0; i < AuBrWh_Last; i++) {
+ /* doubly whiteouted */
+ struct dentry *d;
+ }
+
+ err = 0;
-+
+ switch (br->br_perm) {
+ case AuBrPerm_RO:
+ case AuBrPerm_ROWH:
+ case AuBrPerm_RR:
+ case AuBrPerm_RRWH:
++ h_dir = h_root->d_inode;
+ au_wh_init_ro(h_dir, base, &path);
+ break;
+
+ goto out; /* success */
+
+ out_err:
-+ AuErr("an error(%d) on the writable branch %.*s(%s)\n",
-+ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ pr_err("an error(%d) on the writable branch %.*s(%s)\n",
++ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
+ out:
+ for (i = 0; i < AuBrWh_Last; i++)
+ dput(base[i].dentry);
+ hdir = au_hi(dir, bindex);
+ h_root = au_h_dptr(a->sb->s_root, bindex);
+
-+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+ wbr_wh_write_lock(wbr);
+ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode,
+ h_root, a->br);
+ mnt_drop_write(a->br->br_mnt);
+ }
+ } else {
-+ AuWarn("%.*s is moved, ignored\n", AuDLNPair(wbr->wbr_whbase));
++ pr_warning("%.*s is moved, ignored\n",
++ AuDLNPair(wbr->wbr_whbase));
+ err = 0;
+ }
+ dput(wbr->wbr_whbase);
+ if (!err)
+ err = au_wh_init(h_root, a->br, a->sb);
+ wbr_wh_write_unlock(wbr);
-+ au_hin_imtx_unlock(hdir);
++ au_hn_imtx_unlock(hdir);
+ di_read_unlock(a->sb->s_root, AuLock_IR);
+
+ out:
+ struct au_vdir_destr *str;
+
+ err = -ENOMEM;
-+ p = __getname();
++ p = __getname_gfp(GFP_NOFS);
+ wh_name.name = p;
+ if (unlikely(!wh_name.name))
+ goto out;
+ return 0; /* success */
+ }
+
-+ AuWarn("failed removing %.*s(%d), ignored\n",
-+ AuDLNPair(wh_dentry), err);
++ pr_warning("failed removing %.*s(%d), ignored\n",
++ AuDLNPair(wh_dentry), err);
+ return err;
+}
+
+ h_parent = dget_parent(a->wh_dentry);
+ h_dir = h_parent->d_inode;
+ hdir = au_hi(a->dir, a->bindex);
-+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
+ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, br);
+ if (!err) {
+ err = mnt_want_write(br->br_mnt);
+ mnt_drop_write(br->br_mnt);
+ }
+ }
-+ au_hin_imtx_unlock(hdir);
++ au_hn_imtx_unlock(hdir);
+ dput(h_parent);
+ ii_write_unlock(a->dir);
+
+ args->wh_dentry = dget(wh_dentry);
+ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb);
+ if (unlikely(wkq_err)) {
-+ AuWarn("rmdir error %.*s (%d), ignored\n",
-+ AuDLNPair(wh_dentry), wkq_err);
++ pr_warning("rmdir error %.*s (%d), ignored\n",
++ AuDLNPair(wh_dentry), wkq_err);
+ au_whtmp_rmdir_free(args);
+ }
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.h linux-2.6.31/fs/aufs/whout.h
---- linux-2.6.31-vanilla/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/whout.h 2009-09-16 13:55:30.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/whout.h linux-2.6.33.1/fs/aufs/whout.h
+--- linux-2.6.33.1-vanilla/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/whout.h 2010-04-05 16:53:27.000000000 +0200
@@ -0,0 +1,87 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_WHOUT_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c
---- linux-2.6.31-vanilla/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/wkq.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,259 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/wkq.c linux-2.6.33.1/fs/aufs/wkq.c
+--- linux-2.6.33.1-vanilla/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/wkq.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,183 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#include "aufs.h"
+
+/* internal workqueue named AUFS_WKQ_NAME */
-+static struct au_wkq {
-+ struct workqueue_struct *q;
-+
-+ /* balancing */
-+ atomic_t busy;
-+} *au_wkq;
++static struct workqueue_struct *au_wkq;
+
+struct au_wkinfo {
+ struct work_struct wk;
+ au_wkq_func_t func;
+ void *args;
+
-+ atomic_t *busyp;
+ struct completion *comp;
+};
+
+/* ---------------------------------------------------------------------- */
+
-+static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo)
-+{
-+ wkinfo->busyp = &wkq->busy;
-+ if (au_ftest_wkq(wkinfo->flags, WAIT))
-+ return !queue_work(wkq->q, &wkinfo->wk);
-+ else
-+ return !schedule_work(&wkinfo->wk);
-+}
-+
-+static void do_wkq(struct au_wkinfo *wkinfo)
-+{
-+ unsigned int idle, n;
-+ int i, idle_idx;
-+
-+ while (1) {
-+ if (au_ftest_wkq(wkinfo->flags, WAIT)) {
-+ idle_idx = 0;
-+ idle = UINT_MAX;
-+ for (i = 0; i < aufs_nwkq; i++) {
-+ n = atomic_inc_return(&au_wkq[i].busy);
-+ if (n == 1 && !enqueue(au_wkq + i, wkinfo))
-+ return; /* success */
-+
-+ if (n < idle) {
-+ idle_idx = i;
-+ idle = n;
-+ }
-+ atomic_dec(&au_wkq[i].busy);
-+ }
-+ } else
-+ idle_idx = aufs_nwkq;
-+
-+ atomic_inc(&au_wkq[idle_idx].busy);
-+ if (!enqueue(au_wkq + idle_idx, wkinfo))
-+ return; /* success */
-+
-+ /* impossible? */
-+ AuWarn1("failed to queue_work()\n");
-+ yield();
-+ }
-+}
-+
+static void wkq_func(struct work_struct *wk)
+{
+ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk);
+
+ wkinfo->func(wkinfo->args);
-+ atomic_dec_return(wkinfo->busyp);
+ if (au_ftest_wkq(wkinfo->flags, WAIT))
+ complete(wkinfo->comp);
+ else {
+}
+#endif /* 4KSTACKS */
+
-+static void au_wkq_run(struct au_wkinfo *wkinfo)
++static void au_wkq_run(struct au_wkinfo *wkinfo, int do_wait)
+{
+ au_dbg_verify_kthread();
-+ INIT_WORK(&wkinfo->wk, wkq_func);
-+ do_wkq(wkinfo);
++ if (do_wait) {
++ INIT_WORK_ON_STACK(&wkinfo->wk, wkq_func);
++ queue_work(au_wkq, &wkinfo->wk);
++ } else {
++ INIT_WORK(&wkinfo->wk, wkq_func);
++ schedule_work(&wkinfo->wk);
++ }
+}
+
+int au_wkq_wait(au_wkq_func_t func, void *args)
+
+ err = au_wkq_comp_alloc(&wkinfo, &comp);
+ if (!err) {
-+ au_wkq_run(&wkinfo);
++ au_wkq_run(&wkinfo, AuWkq_WAIT);
+ /* no timeout, no interrupt */
+ wait_for_completion(wkinfo.comp);
+ au_wkq_comp_free(comp);
++ destroy_work_on_stack(&wkinfo.wk);
+ }
+
+ return err;
+ kobject_get(&au_sbi(sb)->si_kobj);
+ __module_get(THIS_MODULE);
+
-+ au_wkq_run(wkinfo);
++ au_wkq_run(wkinfo, !AuWkq_WAIT);
+ } else {
+ err = -ENOMEM;
+ atomic_dec(&au_sbi(sb)->si_nowait.nw_len);
+void au_nwt_init(struct au_nowait_tasks *nwt)
+{
+ atomic_set(&nwt->nw_len, 0);
-+ /* smp_mb();*/ /* atomic_set */
++ /* smp_mb(); */ /* atomic_set */
+ init_waitqueue_head(&nwt->nw_wq);
+}
+
+void au_wkq_fin(void)
+{
-+ int i;
-+
-+ for (i = 0; i < aufs_nwkq; i++)
-+ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q))
-+ destroy_workqueue(au_wkq[i].q);
-+ kfree(au_wkq);
++ destroy_workqueue(au_wkq);
+}
+
+int __init au_wkq_init(void)
+{
-+ int err, i;
-+ struct au_wkq *nowaitq;
-+
-+ /* '+1' is for accounting of nowait queue */
-+ err = -ENOMEM;
-+ au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_NOFS);
-+ if (unlikely(!au_wkq))
-+ goto out;
-+
-+ err = 0;
-+ for (i = 0; i < aufs_nwkq; i++) {
-+ au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME);
-+ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) {
-+ atomic_set(&au_wkq[i].busy, 0);
-+ continue;
-+ }
-+
-+ err = PTR_ERR(au_wkq[i].q);
-+ au_wkq_fin();
-+ goto out;
-+ }
-+
-+ /* nowait accounting */
-+ nowaitq = au_wkq + aufs_nwkq;
-+ atomic_set(&nowaitq->busy, 0);
-+ nowaitq->q = NULL;
-+ /* smp_mb(); */ /* atomic_set */
-+
-+ out:
-+ return err;
++ au_wkq = create_workqueue(AUFS_WKQ_NAME);
++ return 0;
+}
-diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.h linux-2.6.31/fs/aufs/wkq.h
---- linux-2.6.31-vanilla/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/wkq.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,82 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/wkq.h linux-2.6.33.1/fs/aufs/wkq.h
+--- linux-2.6.33.1-vanilla/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/wkq.h 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,84 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+static inline int au_test_wkq(struct task_struct *tsk)
+{
-+ return !tsk->mm && !strcmp(tsk->comm, AUFS_WKQ_NAME);
++ return !tsk->mm
++ && !strncmp(tsk->comm, AUFS_WKQ_NAME "/",
++ sizeof(AUFS_WKQ_NAME));
+}
+
+static inline void au_nwt_done(struct au_nowait_tasks *nwt)
+
+#endif /* __KERNEL__ */
+#endif /* __AUFS_WKQ_H__ */
-diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c
---- linux-2.6.31-vanilla/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/fs/aufs/xino.c 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,1203 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/aufs/xino.c linux-2.6.33.1/fs/aufs/xino.c
+--- linux-2.6.33.1-vanilla/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/fs/aufs/xino.c 2010-04-05 16:53:27.000000000 +0200
+@@ -0,0 +1,1202 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
-+ lockdep_off();
++ /* lockdep_off(); */
+ do {
+ /* todo: signal_pending? */
+ err = func(file, (const char __user *)buf, size, pos);
+ } while (err == -EAGAIN || err == -EINTR);
-+ lockdep_on();
++ /* lockdep_on(); */
+ set_fs(oldfs);
+
+#if 0 /* reserved for future use */
+struct file *au_xino_create2(struct file *base_file, struct file *copy_src)
+{
+ struct file *file;
-+ struct dentry *base, *dentry, *parent;
++ struct dentry *base, *parent;
+ struct inode *dir;
+ struct qstr *name;
-+ int err;
+ struct path path;
++ int err;
+
+ base = base_file->f_dentry;
+ parent = base->d_parent; /* dir inode is locked */
+
+ file = ERR_PTR(-EINVAL);
+ name = &base->d_name;
-+ dentry = vfsub_lookup_one_len(name->name, parent, name->len);
-+ if (IS_ERR(dentry)) {
-+ file = (void *)dentry;
-+ AuErr("%.*s lookup err %ld\n", AuLNPair(name), PTR_ERR(dentry));
++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len);
++ if (IS_ERR(path.dentry)) {
++ file = (void *)path.dentry;
++ pr_err("%.*s lookup err %ld\n",
++ AuLNPair(name), PTR_ERR(path.dentry));
+ goto out;
+ }
+
+ /* no need to mnt_want_write() since we call dentry_open() later */
-+ err = vfs_create(dir, dentry, S_IRUGO | S_IWUGO, NULL);
++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL);
+ if (unlikely(err)) {
+ file = ERR_PTR(err);
-+ AuErr("%.*s create err %d\n", AuLNPair(name), err);
++ pr_err("%.*s create err %d\n", AuLNPair(name), err);
+ goto out_dput;
+ }
+
-+ path.dentry = dentry;
+ path.mnt = base_file->f_vfsmnt;
-+ path_get(&path);
-+ file = vfsub_dentry_open(&path, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE,
-+ current_cred());
++ file = vfsub_dentry_open(&path,
++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE);
+ if (IS_ERR(file)) {
-+ AuErr("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file));
++ pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file));
+ goto out_dput;
+ }
+
+ err = vfsub_unlink(dir, &file->f_path, /*force*/0);
+ if (unlikely(err)) {
-+ AuErr("%.*s unlink err %d\n", AuLNPair(name), err);
++ pr_err("%.*s unlink err %d\n", AuLNPair(name), err);
+ goto out_fput;
+ }
+
+ err = au_copy_file(file, copy_src,
+ i_size_read(copy_src->f_dentry->d_inode));
+ if (unlikely(err)) {
-+ AuErr("%.*s copy err %d\n", AuLNPair(name), err);
++ pr_err("%.*s copy err %d\n", AuLNPair(name), err);
+ goto out_fput;
+ }
+ }
+ fput(file);
+ file = ERR_PTR(err);
+ out_dput:
-+ dput(dentry);
++ dput(path.dentry);
+ out:
+ return file;
+}
+ bindex = au_br_index(sb, brid);
+ if (bindex >= 0) {
+ ldir->hdir = au_hi(sb->s_root->d_inode, bindex);
-+ au_hin_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
++ au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
+ } else {
+ ldir->parent = dget_parent(xino->f_dentry);
+ ldir->mtx = &ldir->parent->d_inode->i_mutex;
+static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
+{
+ if (ldir->hdir)
-+ au_hin_imtx_unlock(ldir->hdir);
++ au_hn_imtx_unlock(ldir->hdir);
+ else {
+ mutex_unlock(ldir->mtx);
+ dput(ldir->parent);
+
+ ii_read_unlock(dir);
+ if (unlikely(err))
-+ AuWarn("err b%d, (%d)\n", bindex, err);
++ pr_warning("err b%d, (%d)\n", bindex, err);
+ atomic_dec(&br->br_xino_running);
+ atomic_dec(&br->br_count);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
+ if (!wkq_err)
+ return; /* success */
+
-+ AuErr("wkq %d\n", wkq_err);
++ pr_err("wkq %d\n", wkq_err);
+ atomic_dec_return(&br->br_count);
+
+ out_args:
+
+ /*
+ * at mount-time, and the xino file is the default path,
-+ * hinotify is disabled so we have no inotify events to ignore.
++ * hnotify is disabled so we have no notify events to ignore.
+ * when a user specified the xino, we cannot get au_hdir to be ignored.
+ */
+ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE,
+ S_IRUGO | S_IWUGO);
+ if (IS_ERR(file)) {
+ if (!silent)
-+ AuErr("open %s(%ld)\n", fname, PTR_ERR(file));
++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file));
+ return file;
+ }
+
+ dput(h_parent);
+ if (unlikely(err)) {
+ if (!silent)
-+ AuErr("unlink %s(%d)\n", fname, err);
++ pr_err("unlink %s(%d)\n", fname, err);
+ goto out;
+ }
+
+ d = file->f_dentry;
+ if (unlikely(sb == d->d_sb)) {
+ if (!silent)
-+ AuErr("%s must be outside\n", fname);
++ pr_err("%s must be outside\n", fname);
+ goto out;
+ }
+ if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
+ if (!silent)
-+ AuErr("xino doesn't support %s(%s)\n",
-+ fname, au_sbtype(d->d_sb));
++ pr_err("xino doesn't support %s(%s)\n",
++ fname, au_sbtype(d->d_sb));
+ goto out;
+ }
+ return file; /* success */
+
+ if (bwr >= 0) {
+ file = ERR_PTR(-ENOMEM);
-+ page = __getname();
++ page = __getname_gfp(GFP_NOFS);
+ if (unlikely(!page))
+ goto out;
+ path.mnt = br->br_mnt;
+ goto out;
+ h_sb = file->f_dentry->d_sb;
+ if (unlikely(au_test_fs_bad_xino(h_sb))) {
-+ AuErr("xino doesn't support %s(%s)\n",
-+ AUFS_XINO_DEFPATH, au_sbtype(h_sb));
++ pr_err("xino doesn't support %s(%s)\n",
++ AUFS_XINO_DEFPATH, au_sbtype(h_sb));
+ fput(file);
+ file = ERR_PTR(-EINVAL);
+ }
+ out:
+ return err;
+}
-diff -Nur linux-2.6.31-vanilla/fs/Kconfig linux-2.6.31/fs/Kconfig
---- linux-2.6.31-vanilla/fs/Kconfig 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/Kconfig 2009-09-16 13:55:56.000000000 +0200
-@@ -187,6 +187,7 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/Kconfig linux-2.6.33.1/fs/Kconfig
+--- linux-2.6.33.1-vanilla/fs/Kconfig 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/Kconfig 2010-04-05 16:54:40.000000000 +0200
+@@ -188,6 +188,7 @@
+ source "fs/sysv/Kconfig"
source "fs/ufs/Kconfig"
source "fs/exofs/Kconfig"
- source "fs/nilfs2/Kconfig"
+source "fs/aufs/Kconfig"
endif # MISC_FILESYSTEMS
-diff -Nur linux-2.6.31-vanilla/fs/Makefile linux-2.6.31/fs/Makefile
---- linux-2.6.31-vanilla/fs/Makefile 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/Makefile 2009-09-16 13:55:56.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/Makefile linux-2.6.33.1/fs/Makefile
+--- linux-2.6.33.1-vanilla/fs/Makefile 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/Makefile 2010-04-05 16:54:40.000000000 +0200
@@ -124,3 +124,4 @@
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
+obj-$(CONFIG_AUFS_FS) += aufs/
-diff -Nur linux-2.6.31-vanilla/fs/namei.c linux-2.6.31/fs/namei.c
---- linux-2.6.31-vanilla/fs/namei.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/namei.c 2009-09-16 13:55:49.000000000 +0200
-@@ -337,6 +337,7 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/namei.c linux-2.6.33.1/fs/namei.c
+--- linux-2.6.33.1-vanilla/fs/namei.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/namei.c 2010-04-05 16:54:44.000000000 +0200
+@@ -349,6 +349,7 @@
return 0;
}
/**
* path_get - get a reference to a path
-@@ -1219,7 +1220,7 @@
+@@ -1207,7 +1208,7 @@
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
{
int err;
-@@ -1228,8 +1229,9 @@
+@@ -1216,8 +1217,9 @@
return ERR_PTR(err);
return __lookup_hash(&nd->last, nd->path.dentry, nd);
}
struct dentry *base, int len)
{
unsigned long hash;
-@@ -1250,6 +1252,7 @@
+@@ -1238,6 +1240,7 @@
this->hash = end_name_hash(hash);
return 0;
}
/**
* lookup_one_len - filesystem helper to lookup single pathname component
-diff -Nur linux-2.6.31-vanilla/fs/namespace.c linux-2.6.31/fs/namespace.c
---- linux-2.6.31-vanilla/fs/namespace.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/namespace.c 2009-09-16 13:55:49.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/fs/namespace.c linux-2.6.33.1/fs/namespace.c
+--- linux-2.6.33.1-vanilla/fs/namespace.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/namespace.c 2010-04-05 16:54:44.000000000 +0200
@@ -39,6 +39,7 @@
/* spinlock for vfsmount related operations, inplace of dcache_lock */
static int event;
static DEFINE_IDA(mnt_id_ida);
-diff -Nur linux-2.6.31-vanilla/fs/open.c linux-2.6.31/fs/open.c
---- linux-2.6.31-vanilla/fs/open.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/open.c 2009-09-16 13:55:49.000000000 +0200
-@@ -221,6 +221,7 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/notify/group.c linux-2.6.33.1/fs/notify/group.c
+--- linux-2.6.33.1-vanilla/fs/notify/group.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/notify/group.c 2010-04-05 16:54:44.000000000 +0200
+@@ -22,6 +22,7 @@
+ #include <linux/srcu.h>
+ #include <linux/rculist.h>
+ #include <linux/wait.h>
++#include <linux/module.h>
+
+ #include <linux/fsnotify_backend.h>
+ #include "fsnotify.h"
+@@ -169,6 +170,7 @@
+ fsnotify_recalc_global_mask();
+ fsnotify_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_put_group);
+
+ /*
+ * Simply run the fsnotify_groups list and find a group which matches
+@@ -252,3 +254,4 @@
+
+ return group;
+ }
++EXPORT_SYMBOL(fsnotify_obtain_group);
+diff -Nur linux-2.6.33.1-vanilla/fs/notify/inode_mark.c linux-2.6.33.1/fs/notify/inode_mark.c
+--- linux-2.6.33.1-vanilla/fs/notify/inode_mark.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/notify/inode_mark.c 2010-04-05 16:54:44.000000000 +0200
+@@ -106,6 +106,7 @@
+ if (atomic_dec_and_test(&entry->refcnt))
+ entry->free_mark(entry);
+ }
++EXPORT_SYMBOL(fsnotify_put_mark);
+
+ /*
+ * Recalculate the mask of events relevant to a given inode locked.
+@@ -216,6 +217,7 @@
+ if (unlikely(atomic_dec_and_test(&group->num_marks)))
+ fsnotify_final_destroy_group(group);
+ }
++EXPORT_SYMBOL(fsnotify_destroy_mark_by_entry);
+
+ /*
+ * Given a group, destroy all of the marks associated with that group.
+@@ -282,6 +284,7 @@
+ }
+ return NULL;
+ }
++EXPORT_SYMBOL(fsnotify_find_mark_entry);
+
+ /*
+ * Nothing fancy, just initialize lists and locks and counters.
+@@ -298,6 +301,7 @@
+ entry->inode = NULL;
+ entry->free_mark = free_mark;
+ }
++EXPORT_SYMBOL(fsnotify_init_mark);
+
+ /*
+ * Attach an initialized mark entry to a given group and inode.
+@@ -353,6 +357,7 @@
+
+ return ret;
+ }
++EXPORT_SYMBOL(fsnotify_add_mark);
+
+ /**
+ * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
+diff -Nur linux-2.6.33.1-vanilla/fs/open.c linux-2.6.33.1/fs/open.c
+--- linux-2.6.33.1-vanilla/fs/open.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/open.c 2010-04-05 16:54:44.000000000 +0200
+@@ -226,6 +226,7 @@
mutex_unlock(&dentry->d_inode->i_mutex);
- return err;
+ return ret;
}
+EXPORT_SYMBOL(do_truncate);
static long do_sys_truncate(const char __user *pathname, loff_t length)
{
-diff -Nur linux-2.6.31-vanilla/fs/splice.c linux-2.6.31/fs/splice.c
---- linux-2.6.31-vanilla/fs/splice.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/fs/splice.c 2009-09-16 13:55:49.000000000 +0200
-@@ -1057,8 +1057,8 @@
+diff -Nur linux-2.6.33.1-vanilla/fs/splice.c linux-2.6.33.1/fs/splice.c
+--- linux-2.6.33.1-vanilla/fs/splice.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/fs/splice.c 2010-04-05 16:54:44.000000000 +0200
+@@ -1053,8 +1053,8 @@
/*
* Attempt to initiate a splice from pipe to file.
*/
{
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
loff_t *, size_t, unsigned int);
-@@ -1080,13 +1080,14 @@
+@@ -1077,13 +1077,14 @@
return splice_write(pipe, out, ppos, len, flags);
}
{
ssize_t (*splice_read)(struct file *, loff_t *,
struct pipe_inode_info *, size_t, unsigned int);
-@@ -1105,6 +1106,7 @@
+@@ -1103,6 +1104,7 @@
return splice_read(in, ppos, pipe, len, flags);
}
/**
* splice_direct_to_actor - splices data directly between two non-pipes
-diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/linux/aufs_type.h
---- linux-2.6.31-vanilla/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/include/linux/aufs_type.h 2009-09-16 13:55:30.000000000 +0200
-@@ -0,0 +1,184 @@
+diff -Nur linux-2.6.33.1-vanilla/include/linux/aufs_type.h linux-2.6.33.1/include/linux/aufs_type.h
+--- linux-2.6.33.1-vanilla/include/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.33.1/include/linux/aufs_type.h 2010-04-05 16:53:31.000000000 +0200
+@@ -0,0 +1,198 @@
+/*
-+ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ * Copyright (C) 2005-2010 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
+#define __AUFS_TYPE_H__
+
+#include <linux/ioctl.h>
++/* for those who didn't "make headers_install" */
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#endif
++#include <linux/limits.h>
+#include <linux/types.h>
+
-+#define AUFS_VERSION "2-standalone.tree-20090914"
++#define AUFS_VERSION "2-standalone.tree-33-20100405"
+
+/* todo? move this to linux-2.6.19/include/magic.h */
+#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
+
+#define AUFS_WH_PFX ".wh."
+#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1)
++#define AUFS_WH_TMP_LEN 4
++/* a limit for rmdir/rename a dir */
++#define AUFS_MAX_NAMELEN (NAME_MAX \
++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\
++ - 1 /* dot */\
++ - AUFS_WH_TMP_LEN) /* hex */
+#define AUFS_XINO_FNAME "." AUFS_NAME ".xino"
+#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
+#define AUFS_XINO_TRUNC_INIT 64 /* blocks */
+#define AUFS_RDBLK_DEF 512 /* bytes */
+#define AUFS_RDHASH_DEF 32
+#define AUFS_WKQ_NAME AUFS_NAME "d"
-+#define AUFS_NWKQ_DEF 4
+#define AUFS_MFS_SECOND_DEF 30 /* seconds */
+#define AUFS_PLINK_WARN 100 /* number of plinks */
+
+
+ /* readdir in userspace */
+ AuCtl_RDU,
-+ AuCtl_RDU_INO
++ AuCtl_RDU_INO,
++
++ /* pathconf wrapper */
++ AuCtl_WBR_FD
+};
+
+/* borrowed from linux/include/linux/kernel.h */
+#define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN)
+#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
+#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
++#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD)
+
+#endif /* __AUFS_TYPE_H__ */
-diff -Nur linux-2.6.31-vanilla/include/linux/Kbuild linux-2.6.31/include/linux/Kbuild
---- linux-2.6.31-vanilla/include/linux/Kbuild 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/include/linux/Kbuild 2009-09-16 13:55:56.000000000 +0200
+diff -Nur linux-2.6.33.1-vanilla/include/linux/Kbuild linux-2.6.33.1/include/linux/Kbuild
+--- linux-2.6.33.1-vanilla/include/linux/Kbuild 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/include/linux/Kbuild 2010-04-05 16:54:40.000000000 +0200
@@ -34,6 +34,7 @@
header-y += atmsap.h
header-y += atmsvc.h
header-y += auto_fs4.h
header-y += ax25.h
header-y += b1lli.h
-diff -Nur linux-2.6.31-vanilla/include/linux/namei.h linux-2.6.31/include/linux/namei.h
---- linux-2.6.31-vanilla/include/linux/namei.h 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/include/linux/namei.h 2009-09-16 13:55:46.000000000 +0200
-@@ -75,6 +75,9 @@
- extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
- extern void release_open_intent(struct nameidata *);
+diff -Nur linux-2.6.33.1-vanilla/include/linux/namei.h linux-2.6.33.1/include/linux/namei.h
+--- linux-2.6.33.1-vanilla/include/linux/namei.h 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/include/linux/namei.h 2010-04-05 16:54:34.000000000 +0200
+@@ -73,6 +73,9 @@
+ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+ int (*open)(struct inode *, struct file *));
+extern struct dentry *lookup_hash(struct nameidata *nd);
+extern int __lookup_one_len(const char *name, struct qstr *this,
+ struct dentry *base, int len);
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
- extern struct dentry *lookup_one_noperm(const char *, struct dentry *);
-diff -Nur linux-2.6.31-vanilla/include/linux/splice.h linux-2.6.31/include/linux/splice.h
---- linux-2.6.31-vanilla/include/linux/splice.h 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/include/linux/splice.h 2009-09-16 13:55:46.000000000 +0200
+ extern int follow_down(struct path *);
+diff -Nur linux-2.6.33.1-vanilla/include/linux/splice.h linux-2.6.33.1/include/linux/splice.h
+--- linux-2.6.33.1-vanilla/include/linux/splice.h 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/include/linux/splice.h 2010-04-05 16:54:34.000000000 +0200
@@ -82,4 +82,10 @@
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
splice_direct_actor *);
+ unsigned int flags);
+
#endif
-diff -Nur linux-2.6.31-vanilla/security/device_cgroup.c linux-2.6.31/security/device_cgroup.c
---- linux-2.6.31-vanilla/security/device_cgroup.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/security/device_cgroup.c 2009-09-16 13:55:49.000000000 +0200
-@@ -513,6 +513,7 @@
+diff -Nur linux-2.6.33.1-vanilla/security/commoncap.c linux-2.6.33.1/security/commoncap.c
+--- linux-2.6.33.1-vanilla/security/commoncap.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/security/commoncap.c 2010-04-05 16:54:44.000000000 +0200
+@@ -946,3 +946,4 @@
+ }
+ return ret;
+ }
++EXPORT_SYMBOL(cap_file_mmap);
+diff -Nur linux-2.6.33.1-vanilla/security/device_cgroup.c linux-2.6.33.1/security/device_cgroup.c
+--- linux-2.6.33.1-vanilla/security/device_cgroup.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/security/device_cgroup.c 2010-04-05 16:54:44.000000000 +0200
+@@ -514,6 +514,7 @@
return -EPERM;
}
int devcgroup_inode_mknod(int mode, dev_t dev)
{
-diff -Nur linux-2.6.31-vanilla/security/integrity/ima/ima_main.c linux-2.6.31/security/integrity/ima/ima_main.c
---- linux-2.6.31-vanilla/security/integrity/ima/ima_main.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/security/integrity/ima/ima_main.c 2009-09-16 13:55:49.000000000 +0200
-@@ -324,6 +324,7 @@
- MAY_EXEC, FILE_MMAP);
- return 0;
- }
-+EXPORT_SYMBOL(ima_file_mmap);
-
- /**
- * ima_bprm_check - based on policy, collect/store measurement.
-diff -Nur linux-2.6.31-vanilla/security/integrity/ima/ima_main.c.orig linux-2.6.31/security/integrity/ima/ima_main.c.orig
---- linux-2.6.31-vanilla/security/integrity/ima/ima_main.c.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.31/security/integrity/ima/ima_main.c.orig 2009-09-10 00:13:59.000000000 +0200
-@@ -0,0 +1,368 @@
-+/*
-+ * Copyright (C) 2005,2006,2007,2008 IBM Corporation
-+ *
-+ * Authors:
-+ * Reiner Sailer <sailer@watson.ibm.com>
-+ * Serge Hallyn <serue@us.ibm.com>
-+ * Kylene Hall <kylene@us.ibm.com>
-+ * Mimi Zohar <zohar@us.ibm.com>
-+ *
-+ * 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, version 2 of the
-+ * License.
-+ *
-+ * File: ima_main.c
-+ * implements the IMA hooks: ima_bprm_check, ima_file_mmap,
-+ * and ima_path_check.
-+ */
-+#include <linux/module.h>
-+#include <linux/file.h>
-+#include <linux/binfmts.h>
-+#include <linux/mount.h>
-+#include <linux/mman.h>
-+
-+#include "ima.h"
-+
-+int ima_initialized;
-+
-+char *ima_hash = "sha1";
-+static int __init hash_setup(char *str)
-+{
-+ if (strncmp(str, "md5", 3) == 0)
-+ ima_hash = "md5";
-+ return 1;
-+}
-+__setup("ima_hash=", hash_setup);
-+
-+/**
-+ * ima_file_free - called on __fput()
-+ * @file: pointer to file structure being freed
-+ *
-+ * Flag files that changed, based on i_version;
-+ * and decrement the iint readcount/writecount.
-+ */
-+void ima_file_free(struct file *file)
-+{
-+ struct inode *inode = file->f_dentry->d_inode;
-+ struct ima_iint_cache *iint;
-+
-+ if (!ima_initialized || !S_ISREG(inode->i_mode))
-+ return;
-+ iint = ima_iint_find_get(inode);
-+ if (!iint)
-+ return;
-+
-+ mutex_lock(&iint->mutex);
-+ if (iint->opencount <= 0) {
-+ printk(KERN_INFO
-+ "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n",
-+ __FUNCTION__, file->f_dentry->d_name.name,
-+ iint->readcount, iint->writecount,
-+ iint->opencount, atomic_long_read(&file->f_count));
-+ if (!(iint->flags & IMA_IINT_DUMP_STACK)) {
-+ dump_stack();
-+ iint->flags |= IMA_IINT_DUMP_STACK;
-+ }
-+ }
-+ iint->opencount--;
-+
-+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
-+ iint->readcount--;
-+
-+ if (file->f_mode & FMODE_WRITE) {
-+ iint->writecount--;
-+ if (iint->writecount == 0) {
-+ if (iint->version != inode->i_version)
-+ iint->flags &= ~IMA_MEASURED;
-+ }
-+ }
-+ mutex_unlock(&iint->mutex);
-+ kref_put(&iint->refcount, iint_free);
-+}
-+
-+/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
-+ *
-+ * When opening a file for read, if the file is already open for write,
-+ * the file could change, resulting in a file measurement error.
-+ *
-+ * Opening a file for write, if the file is already open for read, results
-+ * in a time of measure, time of use (ToMToU) error.
-+ *
-+ * In either case invalidate the PCR.
-+ */
-+enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
-+static void ima_read_write_check(enum iint_pcr_error error,
-+ struct ima_iint_cache *iint,
-+ struct inode *inode,
-+ const unsigned char *filename)
-+{
-+ switch (error) {
-+ case TOMTOU:
-+ if (iint->readcount > 0)
-+ ima_add_violation(inode, filename, "invalid_pcr",
-+ "ToMToU");
-+ break;
-+ case OPEN_WRITERS:
-+ if (iint->writecount > 0)
-+ ima_add_violation(inode, filename, "invalid_pcr",
-+ "open_writers");
-+ break;
-+ }
-+}
-+
-+static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
-+ const unsigned char *filename)
-+{
-+ int rc = 0;
-+
-+ iint->opencount++;
-+ iint->readcount++;
-+
-+ rc = ima_collect_measurement(iint, file);
-+ if (!rc)
-+ ima_store_measurement(iint, file, filename);
-+ return rc;
-+}
-+
-+static void ima_update_counts(struct ima_iint_cache *iint, int mask)
-+{
-+ iint->opencount++;
-+ if ((mask & MAY_WRITE) || (mask == 0))
-+ iint->writecount++;
-+ else if (mask & (MAY_READ | MAY_EXEC))
-+ iint->readcount++;
-+}
-+
-+/**
-+ * ima_path_check - based on policy, collect/store measurement.
-+ * @path: contains a pointer to the path to be measured
-+ * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
-+ *
-+ * Measure the file being open for readonly, based on the
-+ * ima_must_measure() policy decision.
-+ *
-+ * Keep read/write counters for all files, but only
-+ * invalidate the PCR for measured files:
-+ * - Opening a file for write when already open for read,
-+ * results in a time of measure, time of use (ToMToU) error.
-+ * - Opening a file for read when already open for write,
-+ * could result in a file measurement error.
-+ *
-+ * Always return 0 and audit dentry_open failures.
-+ * (Return code will be based upon measurement appraisal.)
-+ */
-+int ima_path_check(struct path *path, int mask, int update_counts)
-+{
-+ struct inode *inode = path->dentry->d_inode;
-+ struct ima_iint_cache *iint;
-+ struct file *file = NULL;
-+ int rc;
-+
-+ if (!ima_initialized || !S_ISREG(inode->i_mode))
-+ return 0;
-+ iint = ima_iint_find_insert_get(inode);
-+ if (!iint)
-+ return 0;
-+
-+ mutex_lock(&iint->mutex);
-+ if (update_counts)
-+ ima_update_counts(iint, mask);
-+
-+ rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
-+ if (rc < 0)
-+ goto out;
-+
-+ if ((mask & MAY_WRITE) || (mask == 0))
-+ ima_read_write_check(TOMTOU, iint, inode,
-+ path->dentry->d_name.name);
-+
-+ if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ)
-+ goto out;
-+
-+ ima_read_write_check(OPEN_WRITERS, iint, inode,
-+ path->dentry->d_name.name);
-+ if (!(iint->flags & IMA_MEASURED)) {
-+ struct dentry *dentry = dget(path->dentry);
-+ struct vfsmount *mnt = mntget(path->mnt);
-+
-+ file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE,
-+ current_cred());
-+ if (IS_ERR(file)) {
-+ int audit_info = 0;
-+
-+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
-+ dentry->d_name.name,
-+ "add_measurement",
-+ "dentry_open failed",
-+ 1, audit_info);
-+ file = NULL;
-+ goto out;
-+ }
-+ rc = get_path_measurement(iint, file, dentry->d_name.name);
-+ }
-+out:
-+ mutex_unlock(&iint->mutex);
-+ if (file)
-+ fput(file);
-+ kref_put(&iint->refcount, iint_free);
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(ima_path_check);
-+
-+static int process_measurement(struct file *file, const unsigned char *filename,
-+ int mask, int function)
-+{
-+ struct inode *inode = file->f_dentry->d_inode;
-+ struct ima_iint_cache *iint;
-+ int rc;
-+
-+ if (!ima_initialized || !S_ISREG(inode->i_mode))
-+ return 0;
-+ iint = ima_iint_find_insert_get(inode);
-+ if (!iint)
-+ return -ENOMEM;
-+
-+ mutex_lock(&iint->mutex);
-+ rc = ima_must_measure(iint, inode, mask, function);
-+ if (rc != 0)
-+ goto out;
-+
-+ rc = ima_collect_measurement(iint, file);
-+ if (!rc)
-+ ima_store_measurement(iint, file, filename);
-+out:
-+ mutex_unlock(&iint->mutex);
-+ kref_put(&iint->refcount, iint_free);
-+ return rc;
-+}
-+
-+/*
-+ * ima_counts_put - decrement file counts
-+ *
-+ * File counts are incremented in ima_path_check. On file open
-+ * error, such as ETXTBSY, decrement the counts to prevent
-+ * unnecessary imbalance messages.
-+ */
-+void ima_counts_put(struct path *path, int mask)
-+{
-+ struct inode *inode = path->dentry->d_inode;
-+ struct ima_iint_cache *iint;
-+
-+ /* The inode may already have been freed, freeing the iint
-+ * with it. Verify the inode is not NULL before dereferencing
-+ * it.
-+ */
-+ if (!ima_initialized || !inode || !S_ISREG(inode->i_mode))
-+ return;
-+ iint = ima_iint_find_insert_get(inode);
-+ if (!iint)
-+ return;
-+
-+ mutex_lock(&iint->mutex);
-+ iint->opencount--;
-+ if ((mask & MAY_WRITE) || (mask == 0))
-+ iint->writecount--;
-+ else if (mask & (MAY_READ | MAY_EXEC))
-+ iint->readcount--;
-+ mutex_unlock(&iint->mutex);
-+
-+ kref_put(&iint->refcount, iint_free);
-+}
-+
-+/*
-+ * ima_counts_get - increment file counts
-+ *
-+ * - for IPC shm and shmat file.
-+ * - for nfsd exported files.
-+ *
-+ * Increment the counts for these files to prevent unnecessary
-+ * imbalance messages.
-+ */
-+void ima_counts_get(struct file *file)
-+{
-+ struct inode *inode = file->f_dentry->d_inode;
-+ struct ima_iint_cache *iint;
-+
-+ if (!ima_initialized || !S_ISREG(inode->i_mode))
-+ return;
-+ iint = ima_iint_find_insert_get(inode);
-+ if (!iint)
-+ return;
-+ mutex_lock(&iint->mutex);
-+ iint->opencount++;
-+ if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
-+ iint->readcount++;
-+
-+ if (file->f_mode & FMODE_WRITE)
-+ iint->writecount++;
-+ mutex_unlock(&iint->mutex);
-+
-+ kref_put(&iint->refcount, iint_free);
-+}
-+EXPORT_SYMBOL_GPL(ima_counts_get);
-+
-+/**
-+ * ima_file_mmap - based on policy, collect/store measurement.
-+ * @file: pointer to the file to be measured (May be NULL)
-+ * @prot: contains the protection that will be applied by the kernel.
-+ *
-+ * Measure files being mmapped executable based on the ima_must_measure()
-+ * policy decision.
-+ *
-+ * Return 0 on success, an error code on failure.
-+ * (Based on the results of appraise_measurement().)
-+ */
-+int ima_file_mmap(struct file *file, unsigned long prot)
-+{
-+ int rc;
-+
-+ if (!file)
-+ return 0;
-+ if (prot & PROT_EXEC)
-+ rc = process_measurement(file, file->f_dentry->d_name.name,
-+ MAY_EXEC, FILE_MMAP);
-+ return 0;
-+}
-+
-+/**
-+ * ima_bprm_check - based on policy, collect/store measurement.
-+ * @bprm: contains the linux_binprm structure
-+ *
-+ * The OS protects against an executable file, already open for write,
-+ * from being executed in deny_write_access() and an executable file,
-+ * already open for execute, from being modified in get_write_access().
-+ * So we can be certain that what we verify and measure here is actually
-+ * what is being executed.
-+ *
-+ * Return 0 on success, an error code on failure.
-+ * (Based on the results of appraise_measurement().)
-+ */
-+int ima_bprm_check(struct linux_binprm *bprm)
-+{
-+ int rc;
-+
-+ rc = process_measurement(bprm->file, bprm->filename,
-+ MAY_EXEC, BPRM_CHECK);
-+ return 0;
-+}
-+
-+static int __init init_ima(void)
-+{
-+ int error;
-+
-+ ima_iintcache_init();
-+ error = ima_init();
-+ ima_initialized = 1;
-+ return error;
-+}
-+
-+static void __exit cleanup_ima(void)
-+{
-+ ima_cleanup();
-+}
-+
-+late_initcall(init_ima); /* Start IMA after the TPM is available */
-+
-+MODULE_DESCRIPTION("Integrity Measurement Architecture");
-+MODULE_LICENSE("GPL");
-diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/security.c
---- linux-2.6.31-vanilla/security/security.c 2009-09-10 00:13:59.000000000 +0200
-+++ linux-2.6.31/security/security.c 2009-09-16 13:55:49.000000000 +0200
-@@ -386,6 +386,7 @@
+diff -Nur linux-2.6.33.1-vanilla/security/security.c linux-2.6.33.1/security/security.c
+--- linux-2.6.33.1-vanilla/security/security.c 2010-03-15 17:09:39.000000000 +0100
++++ linux-2.6.33.1/security/security.c 2010-04-05 16:54:44.000000000 +0200
+@@ -404,6 +404,7 @@
return 0;
return security_ops->path_mkdir(path, dentry, mode);
}
int security_path_rmdir(struct path *path, struct dentry *dentry)
{
-@@ -393,6 +394,7 @@
+@@ -411,6 +412,7 @@
return 0;
return security_ops->path_rmdir(path, dentry);
}
int security_path_unlink(struct path *path, struct dentry *dentry)
{
-@@ -400,6 +402,7 @@
+@@ -418,6 +420,7 @@
return 0;
return security_ops->path_unlink(path, dentry);
}
int security_path_symlink(struct path *path, struct dentry *dentry,
const char *old_name)
-@@ -408,6 +411,7 @@
+@@ -426,6 +429,7 @@
return 0;
return security_ops->path_symlink(path, dentry, old_name);
}
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
struct dentry *new_dentry)
-@@ -416,6 +420,7 @@
+@@ -434,6 +438,7 @@
return 0;
return security_ops->path_link(old_dentry, new_dir, new_dentry);
}
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry)
-@@ -426,6 +431,7 @@
+@@ -444,6 +449,7 @@
return security_ops->path_rename(old_dir, old_dentry, new_dir,
new_dentry);
}
int security_path_truncate(struct path *path, loff_t length,
unsigned int time_attrs)
-@@ -434,6 +440,7 @@
+@@ -452,6 +458,7 @@
return 0;
return security_ops->path_truncate(path, length, time_attrs);
}
+EXPORT_SYMBOL(security_path_truncate);
- #endif
- int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
-@@ -505,6 +512,7 @@
+ int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+@@ -460,6 +467,7 @@
+ return 0;
+ return security_ops->path_chmod(dentry, mnt, mode);
+ }
++EXPORT_SYMBOL(security_path_chmod);
+
+ int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+ {
+@@ -467,6 +475,7 @@
+ return 0;
+ return security_ops->path_chown(path, uid, gid);
+ }
++EXPORT_SYMBOL(security_path_chown);
+
+ int security_path_chroot(struct path *path)
+ {
+@@ -543,6 +552,7 @@
return 0;
return security_ops->inode_readlink(dentry);
}
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
{
-@@ -519,6 +527,7 @@
+@@ -557,6 +567,7 @@
return 0;
return security_ops->inode_permission(inode, mask);
}
int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
{
-@@ -619,6 +628,7 @@
+@@ -657,6 +668,7 @@
{
return security_ops->file_permission(file, mask);
}
int security_file_alloc(struct file *file)
{
+@@ -684,6 +696,7 @@
+ return ret;
+ return ima_file_mmap(file, prot);
+ }
++EXPORT_SYMBOL(security_file_mmap);
+
+ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot)