From: Michael Tremer Date: Mon, 5 Apr 2010 15:21:33 +0000 (+0200) Subject: kernel: Readded aufs, again. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4f653c2bf5ffc981ce6e45ed1132a90051e6ecd;p=ipfire-3.x.git kernel: Readded aufs, again. --- diff --git a/pkgs/core/kernel/config b/pkgs/core/kernel/config index 27a349e4e..7c4f9e5d5 100644 --- a/pkgs/core/kernel/config +++ b/pkgs/core/kernel/config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.33.1 -# Sun Mar 21 20:09:46 2010 +# Mon Apr 5 15:20:41 2010 # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -3268,8 +3268,6 @@ CONFIG_JBD=m CONFIG_JBD2=m # CONFIG_JBD2_DEBUG is not set CONFIG_FS_MBCACHE=m -CONFIG_REISER4_FS=m -# CONFIG_REISER4_DEBUG is not set CONFIG_REISERFS_FS=m # CONFIG_REISERFS_CHECK is not set CONFIG_REISERFS_PROC_INFO=y @@ -3366,6 +3364,20 @@ CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_EXOFS_FS is not set +CONFIG_AUFS_FS=m +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +# CONFIG_AUFS_HNOTIFY is not set +# CONFIG_AUFS_EXPORT is not set +# CONFIG_AUFS_RDU is not set +CONFIG_AUFS_SP_IATTR=y +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y diff --git a/pkgs/core/kernel/patches/aufs2-2.6.31.1-1.patch.off b/pkgs/core/kernel/patches/aufs2-2.6.33.1-1.patch similarity index 87% rename from pkgs/core/kernel/patches/aufs2-2.6.31.1-1.patch.off rename to pkgs/core/kernel/patches/aufs2-2.6.33.1-1.patch index 1f6f6126e..ef625f495 100644 --- a/pkgs/core/kernel/patches/aufs2-2.6.31.1-1.patch.off +++ b/pkgs/core/kernel/patches/aufs2-2.6.33.1-1.patch @@ -1,6 +1,6 @@ -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_/ +Date: March 2009 @@ -42,9 +42,9 @@ diff -Nur linux-2.6.31-vanilla/Documentation/ABI/testing/debugfs-aufs linux-2.6. + 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_/ +Date: March 2009 @@ -71,12 +71,12 @@ diff -Nur linux-2.6.31-vanilla/Documentation/ABI/testing/sysfs-aufs linux-2.6.31 + 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 @@ -102,6 +102,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/aufs.h linux-2.6.31/fs/aufs/aufs.h + +#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" @@ -126,12 +134,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/aufs.h linux-2.6.31/fs/aufs/aufs.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 @@ -153,6 +161,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + */ + +#include ++#include +#include "aufs.h" + +/* @@ -178,9 +187,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + } + + /* some filesystems acquire extra lock */ -+ lockdep_off(); ++ /* lockdep_off(); */ + mntput(br->br_mnt); -+ lockdep_on(); ++ /* lockdep_on(); */ + + kfree(wbr); + kfree(br); @@ -242,7 +251,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c +{ + 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)) @@ -257,18 +268,20 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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); +} + +/* @@ -278,13 +291,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c +{ + 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; +} + @@ -308,7 +322,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + err = 1; + if (!remount) { + err = -EINVAL; -+ AuErr("%s duplicated\n", add->pathname); ++ pr_err("%s duplicated\n", add->pathname); + } + goto out; + } @@ -316,32 +330,32 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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; + } + @@ -356,7 +370,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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; + } + @@ -366,12 +380,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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: @@ -398,7 +412,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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); @@ -411,7 +425,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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; @@ -428,7 +442,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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); @@ -436,8 +452,23 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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; +} + @@ -520,7 +551,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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; @@ -535,7 +566,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + + 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); @@ -594,7 +625,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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. + */ @@ -616,9 +647,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + */ + +/* 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) + +/* @@ -761,6 +792,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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, @@ -779,6 +811,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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, @@ -792,12 +825,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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, @@ -812,7 +846,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + + 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; + @@ -840,7 +874,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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); @@ -904,8 +938,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + /* 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; +} @@ -919,7 +953,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c +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 +} + @@ -1025,13 +1060,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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); @@ -1099,12 +1134,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.c linux-2.6.31/fs/aufs/branch.c + 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 @@ -1155,7 +1190,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.h linux-2.6.31/fs/aufs/branch.h +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 */ @@ -1222,9 +1257,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.h linux-2.6.31/fs/aufs/branch.h + ? -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; @@ -1322,12 +1357,49 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/branch.h linux-2.6.31/fs/aufs/branch.h + +#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 @@ -1370,7 +1442,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + + 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) @@ -1469,7 +1541,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + + 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); +} + +/* ---------------------------------------------------------------------- */ @@ -1744,7 +1816,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + goto out; + + err = -ENOMEM; -+ sym = __getname(); ++ sym = __getname_gfp(GFP_NOFS); + if (unlikely(!sym)) + goto out; + @@ -2175,7 +2247,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + + 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); @@ -2224,10 +2299,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + 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 */ @@ -2240,6 +2313,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + 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)) @@ -2259,9 +2333,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + + 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); @@ -2374,12 +2447,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.c linux-2.6.31/fs/aufs/cpup.c + 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 @@ -2459,12 +2532,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/cpup.h linux-2.6.31/fs/aufs/cpup.h + +#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 @@ -2794,12 +2867,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dbgaufs.c linux-2.6.31/fs/aufs/dbgaufs.c + 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 @@ -2839,50 +2912,23 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dbgaufs.h linux-2.6.31/fs/aufs/dbgaufs.h +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 @@ -3104,12 +3150,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dcsub.c linux-2.6.31/fs/aufs/dcsub.c + 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 @@ -3162,12 +3208,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dcsub.h linux-2.6.31/fs/aufs/dcsub.h + +#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 @@ -3197,9 +3243,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c +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) + +/* ---------------------------------------------------------------------- */ @@ -3356,7 +3402,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c + && 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); @@ -3567,8 +3614,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c +#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; @@ -3588,7 +3635,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c + AuDebugOn(destr.len < NAME_MAX); + +#ifdef CONFIG_4KSTACKS -+ AuWarn("CONFIG_4KSTACKS is defined.\n"); ++ pr_warning("CONFIG_4KSTACKS is defined.\n"); +#endif + +#ifdef AuForceNoBrs @@ -3597,12 +3644,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.c linux-2.6.31/fs/aufs/debug.c + + 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 @@ -3658,51 +3705,42 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.h linux-2.6.31/fs/aufs/debug.h +} +#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) + @@ -3796,37 +3834,15 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.h linux-2.6.31/fs/aufs/debug.h + 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) @@ -3850,26 +3866,23 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/debug.h linux-2.6.31/fs/aufs/debug.h + 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 @@ -3940,6 +3953,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + path_put(&h_nd.path); + } + ++ AuTraceErrPtr(h_dentry); + return h_dentry; +} + @@ -3971,13 +3985,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c +{ + 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); @@ -3996,7 +4008,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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; + @@ -4066,7 +4078,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + struct dentry *parent; + struct inode *inode; + -+ parent = dget_parent(dentry); + err = au_test_shwh(dentry->d_sb, name); + if (unlikely(err)) + goto out; @@ -4081,6 +4092,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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; @@ -4107,7 +4119,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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) @@ -4140,10 +4152,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + /* both of real entry and whiteout found */ + err = -EIO; + -+ out_wh: ++ out_parent: ++ dput(parent); + kfree(whname.name); + out: -+ dput(parent); + return err; +} + @@ -4179,12 +4191,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c +{ + 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)) @@ -4197,12 +4207,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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); @@ -4300,7 +4310,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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; @@ -4488,14 +4498,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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); @@ -4512,7 +4521,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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); + } @@ -4740,19 +4748,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.c linux-2.6.31/fs/aufs/dentry.c + 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 @@ -4799,7 +4807,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.h linux-2.6.31/fs/aufs/dentry.h +/* ---------------------------------------------------------------------- */ + +/* 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); @@ -4851,7 +4859,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.h linux-2.6.31/fs/aufs/dentry.h +/* 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, @@ -4963,31 +4971,28 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dentry.h linux-2.6.31/fs/aufs/dentry.h + +/* ---------------------------------------------------------------------- */ + -+#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 @@ -5353,12 +5358,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dinfo.c linux-2.6.31/fs/aufs/dinfo.c + 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 @@ -5471,9 +5476,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c + 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) @@ -5509,7 +5512,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c + 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); @@ -5552,24 +5554,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c +{ + 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; +} + @@ -5720,9 +5711,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c + + 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); + @@ -5950,12 +5941,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.c linux-2.6.31/fs/aufs/dir.c + .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 @@ -6081,12 +6072,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/dir.h linux-2.6.31/fs/aufs/dir.h + +#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 @@ -6434,14 +6425,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/export.c linux-2.6.31/fs/aufs/export.c + 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; @@ -6831,12 +6821,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/export.c linux-2.6.31/fs/aufs/export.c + 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 @@ -6880,8 +6870,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -6909,8 +6899,18 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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; + @@ -6934,7 +6934,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c +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; + @@ -6946,10 +6945,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -6963,12 +6959,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c +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) { @@ -6982,10 +6978,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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? */ @@ -7039,9 +7033,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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) @@ -7050,8 +7044,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + /* 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; @@ -7067,11 +7062,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -7101,7 +7098,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -7114,6 +7115,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -7311,15 +7313,18 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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); @@ -7330,12 +7335,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + + 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); @@ -7388,27 +7393,50 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.c linux-2.6.31/fs/aufs/file.c + 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 @@ -7458,12 +7486,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h + 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; + }; + }; +}; @@ -7471,7 +7500,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h +/* ---------------------------------------------------------------------- */ + +/* 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); @@ -7487,9 +7516,40 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h +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); @@ -7497,11 +7557,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h + 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) @@ -7575,18 +7640,18 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/file.h linux-2.6.31/fs/aufs/file.h + +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 @@ -7612,7 +7677,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/finfo.c linux-2.6.31/fs/aufs/finfo.c + +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; @@ -7629,6 +7695,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/finfo.c linux-2.6.31/fs/aufs/finfo.c + 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); + } @@ -7642,26 +7709,42 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/finfo.c linux-2.6.31/fs/aufs/finfo.c + +/* ---------------------------------------------------------------------- */ + ++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); +} @@ -7713,12 +7796,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/finfo.c linux-2.6.31/fs/aufs/finfo.c + + 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 @@ -7741,7 +7824,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + +#include +#include -+#include +#include +#include +#include @@ -7782,7 +7864,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + +/* ---------------------------------------------------------------------- */ + -+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; @@ -7797,11 +7879,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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); @@ -7819,18 +7898,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c +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; +} + @@ -7907,6 +7984,34 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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) +{ @@ -7926,15 +8031,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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, @@ -7943,9 +8040,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + /* 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; @@ -7955,7 +8052,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + unsigned long nv, loff_t pos) +{ + ssize_t err; -+ aufs_bindex_t bstart; + struct au_pin pin; + struct dentry *dentry; + struct inode *inode; @@ -7979,19 +8075,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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 @@ -8116,13 +8203,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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); @@ -8146,11 +8233,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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; @@ -8168,11 +8255,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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); +} + @@ -8183,33 +8270,57 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + +/* ---------------------------------------------------------------------- */ + -+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); @@ -8217,7 +8328,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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)) { @@ -8235,7 +8347,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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; @@ -8261,49 +8373,116 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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; @@ -8321,22 +8500,23 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + 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; +} + @@ -8525,6 +8705,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c +#ifdef CONFIG_AUFS_POLL + .poll = aufs_poll, +#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, + .mmap = aufs_mmap, + .open = aufs_open_nondir, + .flush = aufs_flush, @@ -8540,12 +8721,306 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/f_op.c linux-2.6.31/fs/aufs/f_op.c + .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 ++#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 @@ -8571,7 +9046,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.h + +#ifdef __KERNEL__ + -+#include +#include +#include +#include @@ -8857,7 +9331,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.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. + */ @@ -8928,11 +9411,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.h +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 */ + ; +} @@ -8957,7 +9442,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.h +#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); +} + +/* @@ -9029,12 +9516,246 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/fstype.h linux-2.6.31/fs/aufs/fstype.h + +#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 @@ -9052,7 +9773,69 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + */ + +/* -+ * 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 ++#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" @@ -9060,70 +9843,58 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. +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) { @@ -9137,7 +9908,219 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9165,7 +10148,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + +/* ---------------------------------------------------------------------- */ + -+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; @@ -9173,7 +10156,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + + 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; + } + @@ -9186,12 +10169,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; + @@ -9212,7 +10194,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9259,8 +10241,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. +/* + * 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; @@ -9268,7 +10250,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + + 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; + } @@ -9300,7 +10282,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + + 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); + } + @@ -9309,7 +10291,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9318,7 +10300,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; + } + @@ -9331,7 +10313,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + } 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); @@ -9340,18 +10322,32 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + +/* ---------------------------------------------------------------------- */ + -+/* 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; @@ -9359,36 +10355,36 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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); @@ -9399,44 +10395,17 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + } + + /* 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) +{ @@ -9488,7 +10457,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9500,25 +10469,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; + @@ -9526,8 +10486,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9561,22 +10521,22 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9584,7 +10544,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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); @@ -9596,7 +10556,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + } + + 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; @@ -9604,7 +10564,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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: @@ -9619,49 +10579,29 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + +/* ---------------------------------------------------------------------- */ + -+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; @@ -9671,37 +10611,31 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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: @@ -9711,24 +10645,25 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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; @@ -9736,64 +10671,59 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/hinotify.c linux-2.6.31/fs/aufs/hinotify. + 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 @@ -9843,7 +10773,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c + +void au_hiput(struct au_hinode *hinode) +{ -+ au_hin_free(hinode); ++ au_hn_free(hinode); + dput(hinode->hi_whdentry); + iput(hinode->hi_inode); +} @@ -9856,8 +10786,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c + 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; +} + @@ -9873,7 +10803,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c + 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); @@ -9894,11 +10823,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c + 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); + } + } +} @@ -10075,12 +11004,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/iinfo.c linux-2.6.31/fs/aufs/iinfo.c + 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 @@ -10125,7 +11054,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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; @@ -10140,7 +11068,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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++) { @@ -10152,7 +11079,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + continue; + + if (new_bindex < 0) { -+ update++; ++ update = 1; + au_hiput(p); + p->hi_inode = NULL; + continue; @@ -10182,11 +11109,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + +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; + @@ -10197,7 +11123,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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); @@ -10233,6 +11158,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + au_refresh_hinode_attr(inode, update && isdir); + + out: ++ AuTraceErr(err); + return err; +} + @@ -10277,7 +11203,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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); @@ -10285,13 +11211,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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; @@ -10417,13 +11343,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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) @@ -10446,6 +11373,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + + out_iput: + iput(inode); ++ out_err: + inode = ERR_PTR(err); + out: + return inode; @@ -10492,12 +11420,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.c linux-2.6.31/fs/aufs/inode.c + 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 @@ -10524,24 +11452,28 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h +#ifdef __KERNEL__ + +#include -+#include ++#include +#include +#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 */ @@ -10680,14 +11612,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h + +/* 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, @@ -10701,14 +11633,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h +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); @@ -10723,7 +11653,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h +/* 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, @@ -10796,6 +11726,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h + && 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, @@ -10899,106 +11836,92 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/inode.h linux-2.6.31/fs/aufs/inode.h + +/* ---------------------------------------------------------------------- */ + -+#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 @@ -11018,10 +11941,67 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/ioctl.c linux-2.6.31/fs/aufs/ioctl.c +/* + * ioctl + * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. + */ + ++#include +#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; @@ -11037,19 +12017,44 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/ioctl.c linux-2.6.31/fs/aufs/ioctl.c + 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 @@ -11143,6 +12148,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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) { @@ -11166,13 +12175,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + } + } + -+ 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; +} + @@ -11193,6 +12202,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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); @@ -11209,13 +12220,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + + 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) { @@ -11275,6 +12287,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + .flags = AuWrDir_ADD_ENTRY + }; + ++ AuDbg("%.*s\n", AuDLNPair(dentry)); + IMustLock(dir); + + parent = dentry->d_parent; /* dir inode is locked */ @@ -11382,6 +12395,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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); @@ -11396,9 +12410,15 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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: @@ -11413,6 +12433,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + struct inode *h_inode, *inode; + struct dentry *h_src_dentry; + struct super_block *sb; ++ struct file *h_file; + + plink = 0; + h_inode = NULL; @@ -11426,9 +12447,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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 { @@ -11697,12 +12725,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_add.c linux-2.6.31/fs/aufs/i_op_add. + 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 @@ -11755,7 +12783,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + && 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); @@ -11764,10 +12793,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + + 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) { @@ -11790,8 +12819,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c +{ + 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; @@ -11812,7 +12841,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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--) @@ -11862,6 +12893,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + + 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)) @@ -12034,7 +13068,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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); @@ -12091,7 +13125,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + } + + 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; @@ -12118,7 +13152,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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; @@ -12173,6 +13207,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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 @@ -12206,13 +13241,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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); @@ -12220,6 +13251,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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); @@ -12236,12 +13268,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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) @@ -12251,6 +13290,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + + 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); @@ -12258,7 +13298,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + } + + au_unpin(&a->pin); -+ ++ out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } + out_dentry: + di_write_unlock(dentry); + out: @@ -12303,6 +13347,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + } + + 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; + @@ -12354,17 +13411,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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; +} + @@ -12415,14 +13471,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + 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; @@ -12479,10 +13528,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + + 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); @@ -12518,7 +13564,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + mm_segment_t old_fs; + + err = -ENOMEM; -+ buf = __getname(); ++ buf = __getname_gfp(GFP_NOFS); + if (unlikely(!buf)) + goto out; + @@ -12592,12 +13638,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op.c linux-2.6.31/fs/aufs/i_op.c + .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 @@ -12793,9 +13839,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del. + 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); @@ -12827,7 +13875,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del. + 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; @@ -12847,6 +13895,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del. + } + + out: ++ AuTraceErr(err); + return err; +} + @@ -13021,7 +14070,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del. + } + } 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); @@ -13062,14 +14111,15 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_del.c linux-2.6.31/fs/aufs/i_op_del. + 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 @@ -13165,9 +14215,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + * 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) + @@ -13175,14 +14225,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. +{ + 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; @@ -13217,7 +14266,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry)); +} + -+ +static void au_ren_rev_whtmp(int err, struct au_ren_args *a) +{ + int rerr; @@ -13238,10 +14286,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + 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)); +} + @@ -13301,18 +14348,29 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + 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; @@ -13331,8 +14389,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + || 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; @@ -13353,9 +14411,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + + 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); @@ -13417,11 +14475,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + /* 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; + } @@ -13645,6 +14711,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + out: + if (unlikely(err == -ENOENT || err == -EEXIST)) + err = -EIO; ++ AuTraceErr(err); + return err; +} + @@ -13893,6 +14960,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + /* reduce stack space */ + struct au_ren_args *a; + ++ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry)); + IMustLock(_src_dir); + IMustLock(_dst_dir); + @@ -13977,11 +15045,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + 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); @@ -14023,12 +15092,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/i_op_ren.c linux-2.6.31/fs/aufs/i_op_ren. + 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 @@ -14075,16 +15145,28 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig + 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) @@ -14093,6 +15175,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig + 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 @@ -14101,6 +15193,17 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig + 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 @@ -14132,19 +15235,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig + 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 @@ -14154,27 +15257,26 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Kconfig linux-2.6.31/fs/aufs/Kconfig + 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 @@ -14228,12 +15330,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/loop.c linux-2.6.31/fs/aufs/loop.c + && '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 @@ -14268,25 +15370,17 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/loop.h linux-2.6.31/fs/aufs/loop.h + 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 @@ -14306,10 +15400,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/magic.mk linux-2.6.31/fs/aufs/magic.mk +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 @@ -14339,14 +15429,29 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/magic.mk linux-2.6.31/fs/aufs/magic.mk +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 \ @@ -14361,18 +15466,22 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/Makefile linux-2.6.31/fs/aufs/Makefile +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 @@ -14434,6 +15543,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c +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]); @@ -14455,11 +15566,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c + " -- 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 /fs/aufs/si_*/brN"); @@ -14492,18 +15598,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c + + 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(); @@ -14515,7 +15616,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c + 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: @@ -14523,7 +15625,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c + out_sysrq: + au_sysrq_fin(); + out_hin: -+ au_hinotify_fin(); ++ au_hnotify_fin(); + out_wkq: + au_wkq_fin(); + out_sysaufs: @@ -14537,19 +15639,19 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.c linux-2.6.31/fs/aufs/module.c + 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 @@ -14581,7 +15683,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.h linux-2.6.31/fs/aufs/module.h +struct seq_file; + +/* module parameters */ -+extern short aufs_nwkq; +extern int sysaufs_brs; + +/* ---------------------------------------------------------------------- */ @@ -14600,38 +15701,39 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/module.h linux-2.6.31/fs/aufs/module.h + 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 @@ -14815,7 +15917,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + {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]; @@ -14834,17 +15936,34 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c +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) @@ -14877,7 +15996,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + * 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; @@ -14903,7 +16023,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -14919,14 +16039,15 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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]; @@ -14978,7 +16099,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + {-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]; + @@ -15227,7 +16348,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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: @@ -15243,7 +16364,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + + 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; +} @@ -15259,7 +16380,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15273,7 +16394,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c +} +#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; @@ -15283,14 +16405,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15314,7 +16436,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15344,7 +16466,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15356,10 +16478,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; @@ -15368,7 +16490,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + + 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; + } + @@ -15386,7 +16508,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15444,7 +16566,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; @@ -15474,7 +16596,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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); @@ -15491,7 +16613,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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); @@ -15515,13 +16637,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } @@ -15547,12 +16669,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; @@ -15564,7 +16686,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + || 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; @@ -15605,7 +16727,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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: @@ -15616,7 +16738,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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); @@ -15624,18 +16746,18 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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; + } + @@ -15958,14 +17080,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + + 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; @@ -16026,13 +17148,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + 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); @@ -16081,7 +17203,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + bend = au_sbend(sb); + if (unlikely(bend < 0)) { + err = -EINVAL; -+ AuErr("no branches\n"); ++ pr_err("no branches\n"); + goto out; + } + @@ -16113,10 +17235,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c + /* 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: @@ -16176,12 +17297,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.c linux-2.6.31/fs/aufs/opts.c +{ + 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 @@ -16221,7 +17342,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.h linux-2.6.31/fs/aufs/opts.h +#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 */ @@ -16232,9 +17353,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.h linux-2.6.31/fs/aufs/opts.h +#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 @@ -16248,7 +17369,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.h linux-2.6.31/fs/aufs/opts.h + | 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 { \ @@ -16376,12 +17497,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/opts.h linux-2.6.31/fs/aufs/opts.h + +#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 @@ -16408,14 +17529,53 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/plink.c linux-2.6.31/fs/aufs/plink.c + * 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; +} + +/* ---------------------------------------------------------------------- */ @@ -16654,14 +17814,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/plink.c linux-2.6.31/fs/aufs/plink.c + 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); + } @@ -16756,13 +17916,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/plink.c linux-2.6.31/fs/aufs/plink.c + * 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); @@ -16771,17 +17925,18 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/plink.c linux-2.6.31/fs/aufs/plink.c + 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 @@ -16836,12 +17991,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/poll.c linux-2.6.31/fs/aufs/poll.c + 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 @@ -16862,6 +18017,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c + * readdir in userspace. + */ + ++#include +#include +#include +#include @@ -16901,6 +18057,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c + 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))) @@ -17071,14 +18229,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c + 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); @@ -17164,6 +18317,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c + break; + + default: ++ /* err = -ENOTTY; */ + err = -EINVAL; + } + @@ -17171,12 +18325,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rdu.c linux-2.6.31/fs/aufs/rdu.c + 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 @@ -17203,6 +18357,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rwsem.h linux-2.6.31/fs/aufs/rwsem.h +#ifdef __KERNEL__ + +#include ++#include "debug.h" + +struct au_rwsem { + struct rw_semaphore rwsem; @@ -17361,12 +18516,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/rwsem.h linux-2.6.31/fs/aufs/rwsem.h + +#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 @@ -17399,6 +18554,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c + + 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); @@ -17418,7 +18574,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c + struct au_sbinfo *sbinfo; + + err = -ENOMEM; -+ sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS); ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); + if (unlikely(!sbinfo)) + goto out; + @@ -17427,30 +18583,22 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c + 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 */ + @@ -17461,6 +18609,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c + + 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; @@ -17573,12 +18722,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sbinfo.c linux-2.6.31/fs/aufs/sbinfo.c + 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 @@ -17634,12 +18783,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/spl.h linux-2.6.31/fs/aufs/spl.h + +#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 @@ -17906,9 +19055,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + si_read_unlock(sb); + return 0; + -+#undef Deleted +#undef AuBool +#undef AuStr ++#undef AuUInt +} + +/* ---------------------------------------------------------------------- */ @@ -17991,7 +19140,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + + 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; */ @@ -18001,34 +19150,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + +/* ---------------------------------------------------------------------- */ + -+/* 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. @@ -18042,7 +19163,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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) @@ -18085,10 +19205,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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); @@ -18250,20 +19371,21 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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() */ @@ -18299,8 +19421,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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; + } @@ -18323,7 +19443,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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); @@ -18344,7 +19463,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + 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, @@ -18408,7 +19527,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + + if (unlikely(!arg || !*arg)) { + err = -EINVAL; -+ AuErr("no arg\n"); ++ pr_err("no arg\n"); + goto out; + } + @@ -18452,20 +19571,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + + /* 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; @@ -18512,12 +19625,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.c linux-2.6.31/fs/aufs/super.c + /* 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 @@ -18647,6 +19760,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h + /* 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. @@ -18673,7 +19788,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h + * 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) +{ @@ -18693,10 +19807,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h +/* ---------------------------------------------------------------------- */ + +/* 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 */ @@ -18763,36 +19877,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h + 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; @@ -18900,12 +19990,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/super.h linux-2.6.31/fs/aufs/super.h + +#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 @@ -18992,7 +20082,10 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.c linux-2.6.31/fs/aufs/sysaufs.c + 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; @@ -19008,12 +20101,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.c linux-2.6.31/fs/aufs/sysaufs.c + 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 @@ -19095,11 +20188,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.h linux-2.6.31/fs/aufs/sysaufs.h +#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, @@ -19108,20 +20197,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.h linux-2.6.31/fs/aufs/sysaufs.h + 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) +{ @@ -19132,12 +20210,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysaufs.h linux-2.6.31/fs/aufs/sysaufs.h + +#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 @@ -19164,7 +20242,30 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c +#include +#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 */ +}; + @@ -19237,7 +20338,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c + +/* 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; @@ -19250,12 +20351,25 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c + + 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; @@ -19290,8 +20404,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c + err = -EFBIG; + } + kfree(seq); -+ out: ++ out_unlock: + si_read_unlock(sb); ++ out: + return err; +} + @@ -19343,15 +20458,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysfs.c linux-2.6.31/fs/aufs/sysfs.c + "%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 @@ -19391,24 +20507,28 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysrq.c linux-2.6.31/fs/aufs/sysrq.c + 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); @@ -19454,7 +20574,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysrq.c linux-2.6.31/fs/aufs/sysrq.c + 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; +} + @@ -19463,14 +20583,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/sysrq.c linux-2.6.31/fs/aufs/sysrq.c + 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 @@ -19496,7 +20616,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + +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)); +} + @@ -19538,7 +20657,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + n = sz; + if (sz < AUFS_RDHASH_DEF) + n = AUFS_RDHASH_DEF; -+ /* AuInfo("n %u\n", n); */ ++ /* pr_info("n %u\n", n); */ + return n; +} + @@ -19572,7 +20691,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + n = 0; + hlist_for_each(pos, head) + n++; -+ AuInfo("%lu\n", n); ++ pr_info("%lu\n", n); +#endif +} + @@ -19594,7 +20713,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + + hlist_for_each_entry_safe(tpos, pos, node, head, hash) { + /* hlist_del(pos); */ -+ au_cache_free_dehstr(tpos); ++ au_cache_free_vdir_dehstr(tpos); + } +} + @@ -19804,7 +20923,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + } + + err = -ENOMEM; -+ dehstr = au_cache_alloc_dehstr(); ++ dehstr = au_cache_alloc_vdir_dehstr(); + if (unlikely(!dehstr)) + goto out; + @@ -19860,7 +20979,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + 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; @@ -19946,9 +21065,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + + 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; @@ -19958,10 +21080,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + 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: @@ -19987,7 +21112,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); + + err = -ENOMEM; -+ o = p = __getname(); ++ o = p = __getname_gfp(GFP_NOFS); + if (unlikely(!p)) + goto out; + @@ -20348,12 +21473,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vdir.c linux-2.6.31/fs/aufs/vdir.c + /* 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 @@ -20374,6 +21499,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + * sub-routines for VFS + */ + ++#include +#include +#include +#include @@ -20403,20 +21529,49 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + +/* ---------------------------------------------------------------------- */ + ++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; +} + @@ -20424,9 +21579,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +{ + 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*/ @@ -20464,6 +21619,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ + + out: ++ AuTraceErrPtr(path.dentry); + return path.dentry; +} + @@ -20476,9 +21632,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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; +} + @@ -20492,9 +21652,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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; +} @@ -20502,9 +21662,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +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(); @@ -20649,9 +21809,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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; @@ -20691,9 +21851,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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; + @@ -20757,9 +21917,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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, @@ -20805,9 +21965,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +{ + 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; @@ -20829,9 +21989,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +{ + 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; @@ -20843,9 +22003,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +{ + 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; @@ -20856,9 +22016,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c +{ + 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; @@ -20891,9 +22051,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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: @@ -20994,9 +22154,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + + *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*/ + } @@ -21063,9 +22223,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + 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, @@ -21107,12 +22267,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.c linux-2.6.31/fs/aufs/vfsub.c + + 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 @@ -21139,7 +22299,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h +#ifdef __KERNEL__ + +#include -+#include + +/* ---------------------------------------------------------------------- */ + @@ -21162,18 +22321,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.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); @@ -21198,12 +22348,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h +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, @@ -21216,13 +22360,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h + 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) +{ @@ -21241,15 +22388,23 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h + 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; +} + @@ -21281,14 +22436,22 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/vfsub.h linux-2.6.31/fs/aufs/vfsub.h + 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 @@ -21398,8 +22561,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wbr_policy.c linux-2.6.31/fs/aufs/wbr_pol + 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; @@ -21424,7 +22586,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wbr_policy.c linux-2.6.31/fs/aufs/wbr_pol + 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); @@ -21432,8 +22593,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wbr_policy.c linux-2.6.31/fs/aufs/wbr_pol + 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)) { @@ -21928,12 +23087,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wbr_policy.c linux-2.6.31/fs/aufs/wbr_pol + .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 @@ -22006,9 +23165,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c +{ + 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 @@ -22055,19 +23212,20 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c +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); @@ -22081,17 +23239,17 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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(); @@ -22100,8 +23258,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + if (name != defname) + kfree(name); + out: ++ AuTraceErrPtr(dentry); + return dentry; -+#undef HEX_LEN +} + +/* @@ -22131,6 +23289,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + dput(h_path.dentry); + + out: ++ AuTraceErr(err); + return err; +} + @@ -22208,8 +23367,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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) @@ -22219,8 +23378,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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; +} + @@ -22243,7 +23402,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + } 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; +} @@ -22342,8 +23501,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + } 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; + @@ -22413,7 +23572,6 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + if (wbr) + WbrWhMustWriteLock(wbr); + -+ h_dir = h_root->d_inode; + for (i = 0; i < AuBrWh_Last; i++) { + /* doubly whiteouted */ + struct dentry *d; @@ -22436,12 +23594,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + } + + 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; + @@ -22467,8 +23625,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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); @@ -22513,7 +23671,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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); @@ -22526,7 +23684,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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); @@ -22534,7 +23693,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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: @@ -22768,7 +23927,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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; @@ -22914,8 +24073,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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; +} + @@ -22943,7 +24102,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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); @@ -22953,7 +24112,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + mnt_drop_write(br->br_mnt); + } + } -+ au_hin_imtx_unlock(hdir); ++ au_hn_imtx_unlock(hdir); + dput(h_parent); + ii_write_unlock(a->dir); + @@ -22979,17 +24138,17 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.c linux-2.6.31/fs/aufs/whout.c + 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 @@ -23075,12 +24234,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/whout.h linux-2.6.31/fs/aufs/whout.h + +#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 @@ -23106,12 +24265,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c +#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; @@ -23122,60 +24276,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c + 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 { @@ -23226,11 +24336,16 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c +} +#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) @@ -23245,10 +24360,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c + + 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; @@ -23277,7 +24393,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c + 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); @@ -23291,59 +24407,26 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.c linux-2.6.31/fs/aufs/wkq.c +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 @@ -23407,7 +24490,9 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.h linux-2.6.31/fs/aufs/wkq.h + +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) @@ -23424,12 +24509,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/wkq.h linux-2.6.31/fs/aufs/wkq.h + +#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 @@ -23487,12 +24572,12 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + + 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 */ @@ -23557,11 +24642,11 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c +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 */ @@ -23570,34 +24655,33 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + + 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; + } + @@ -23606,7 +24690,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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; + } + } @@ -23616,7 +24700,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + fput(file); + file = ERR_PTR(err); + out_dput: -+ dput(dentry); ++ dput(path.dentry); + out: + return file; +} @@ -23639,7 +24723,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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; @@ -23650,7 +24734,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c +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); @@ -23737,7 +24821,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + + 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); @@ -23771,7 +24855,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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: @@ -24052,14 +25136,14 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + + /* + * 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; + } + @@ -24073,7 +25157,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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; + } + @@ -24081,13 +25165,13 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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 */ @@ -24577,7 +25661,7 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + + if (bwr >= 0) { + file = ERR_PTR(-ENOMEM); -+ page = __getname(); ++ page = __getname_gfp(GFP_NOFS); + if (unlikely(!page)) + goto out; + path.mnt = br->br_mnt; @@ -24598,8 +25682,8 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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); + } @@ -24631,29 +25715,29 @@ diff -Nur linux-2.6.31-vanilla/fs/aufs/xino.c linux-2.6.31/fs/aufs/xino.c + 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; } @@ -24661,7 +25745,7 @@ diff -Nur linux-2.6.31-vanilla/fs/namei.c linux-2.6.31/fs/namei.c /** * 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. */ @@ -24670,7 +25754,7 @@ diff -Nur linux-2.6.31-vanilla/fs/namei.c linux-2.6.31/fs/namei.c { int err; -@@ -1228,8 +1229,9 @@ +@@ -1216,8 +1217,9 @@ return ERR_PTR(err); return __lookup_hash(&nd->last, nd->path.dentry, nd); } @@ -24681,7 +25765,7 @@ diff -Nur linux-2.6.31-vanilla/fs/namei.c linux-2.6.31/fs/namei.c struct dentry *base, int len) { unsigned long hash; -@@ -1250,6 +1252,7 @@ +@@ -1238,6 +1240,7 @@ this->hash = end_name_hash(hash); return 0; } @@ -24689,9 +25773,9 @@ diff -Nur linux-2.6.31-vanilla/fs/namei.c linux-2.6.31/fs/namei.c /** * 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 */ @@ -24700,21 +25784,88 @@ diff -Nur linux-2.6.31-vanilla/fs/namespace.c linux-2.6.31/fs/namespace.c 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 + #include + #include ++#include + + #include + #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. */ @@ -24725,7 +25876,7 @@ diff -Nur linux-2.6.31-vanilla/fs/splice.c linux-2.6.31/fs/splice.c { 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); } @@ -24743,7 +25894,7 @@ diff -Nur linux-2.6.31-vanilla/fs/splice.c linux-2.6.31/fs/splice.c { 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); } @@ -24751,12 +25902,12 @@ diff -Nur linux-2.6.31-vanilla/fs/splice.c linux-2.6.31/fs/splice.c /** * 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 @@ -24777,9 +25928,14 @@ diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/li +#define __AUFS_TYPE_H__ + +#include ++/* for those who didn't "make headers_install" */ ++#ifdef __KERNEL__ ++#include ++#endif ++#include +#include + -+#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') @@ -24816,6 +25972,12 @@ diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/li + +#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 */ @@ -24825,7 +25987,6 @@ diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/li +#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 */ + @@ -24860,7 +26021,10 @@ diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/li + + /* readdir in userspace */ + AuCtl_RDU, -+ AuCtl_RDU_INO ++ AuCtl_RDU_INO, ++ ++ /* pathconf wrapper */ ++ AuCtl_WBR_FD +}; + +/* borrowed from linux/include/linux/kernel.h */ @@ -24937,11 +26101,12 @@ diff -Nur linux-2.6.31-vanilla/include/linux/aufs_type.h linux-2.6.31/include/li +#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 @@ -24950,22 +26115,22 @@ diff -Nur linux-2.6.31-vanilla/include/linux/Kbuild linux-2.6.31/include/linux/K 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 *); @@ -24977,10 +26142,18 @@ diff -Nur linux-2.6.31-vanilla/include/linux/splice.h linux-2.6.31/include/linux + 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; } @@ -24988,393 +26161,10 @@ diff -Nur linux-2.6.31-vanilla/security/device_cgroup.c linux-2.6.31/security/de 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 -+ * Serge Hallyn -+ * Kylene Hall -+ * Mimi Zohar -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+#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); } @@ -25382,7 +26172,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25390,7 +26180,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25398,7 +26188,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25406,7 +26196,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25414,7 +26204,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25422,15 +26212,31 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25438,7 +26244,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25446,7 +26252,7 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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); } @@ -25454,3 +26260,11 @@ diff -Nur linux-2.6.31-vanilla/security/security.c linux-2.6.31/security/securit 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)