diff options
Diffstat (limited to 'fs/aufs')
-rw-r--r-- | fs/aufs/branch.c | 11 | ||||
-rw-r--r-- | fs/aufs/cpup.c | 4 | ||||
-rw-r--r-- | fs/aufs/dentry.c | 35 | ||||
-rw-r--r-- | fs/aufs/dentry.h | 3 | ||||
-rw-r--r-- | fs/aufs/dir.c | 4 | ||||
-rw-r--r-- | fs/aufs/file.c | 5 | ||||
-rw-r--r-- | fs/aufs/fstype.h | 2 | ||||
-rw-r--r-- | fs/aufs/i_op.c | 108 | ||||
-rw-r--r-- | fs/aufs/i_op_ren.c | 8 | ||||
-rw-r--r-- | fs/aufs/inode.c | 36 | ||||
-rw-r--r-- | fs/aufs/inode.h | 10 | ||||
-rw-r--r-- | fs/aufs/loop.c | 5 | ||||
-rw-r--r-- | fs/aufs/module.c | 13 | ||||
-rw-r--r-- | fs/aufs/mvdown.c | 21 | ||||
-rw-r--r-- | fs/aufs/opts.c | 32 | ||||
-rw-r--r-- | fs/aufs/opts.h | 1 | ||||
-rw-r--r-- | fs/aufs/sbinfo.c | 10 | ||||
-rw-r--r-- | fs/aufs/super.c | 95 | ||||
-rw-r--r-- | fs/aufs/super.h | 14 | ||||
-rw-r--r-- | fs/aufs/sysfs.c | 10 | ||||
-rw-r--r-- | fs/aufs/sysrq.c | 4 | ||||
-rw-r--r-- | fs/aufs/vfsub.h | 1 |
22 files changed, 296 insertions, 136 deletions
diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c index d34e789ca..72a8ee665 100644 --- a/fs/aufs/branch.c +++ b/fs/aufs/branch.c @@ -541,7 +541,7 @@ out: /* ---------------------------------------------------------------------- */ -static unsigned long long au_farray_cb(void *a, +static unsigned long long au_farray_cb(struct super_block *sb, void *a, unsigned long long max __maybe_unused, void *arg) { @@ -549,7 +549,6 @@ static unsigned long long au_farray_cb(void *a, struct file **p, *f; struct au_sphlhead *files; struct au_finfo *finfo; - struct super_block *sb = arg; n = 0; p = a; @@ -574,7 +573,7 @@ static struct file **au_farray_alloc(struct super_block *sb, unsigned long long *max) { *max = atomic_long_read(&au_sbi(sb)->si_nfiles); - return au_array_alloc(max, au_farray_cb, sb); + return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); } static void au_farray_free(struct file **a, unsigned long long max) @@ -972,8 +971,8 @@ static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, au_br_do_free(br); } -static unsigned long long empty_cb(void *array, unsigned long long max, - void *arg) +static unsigned long long empty_cb(struct super_block *sb, void *array, + unsigned long long max, void *arg) { return max; } @@ -1018,7 +1017,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) br_id = br->br_id; opened = atomic_read(&br->br_count); if (unlikely(opened)) { - to_free = au_array_alloc(&opened, empty_cb, NULL); + to_free = au_array_alloc(&opened, empty_cb, sb, NULL); err = PTR_ERR(to_free); if (IS_ERR(to_free)) goto out; diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c index f6f6818ba..cd322746c 100644 --- a/fs/aufs/cpup.c +++ b/fs/aufs/cpup.c @@ -710,9 +710,9 @@ static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) goto out_parent; if (unlikely(d_is_negative(h_src))) { err = -EIO; - AuIOErr("i%lu exists on a upper branch " + AuIOErr("i%lu exists on b%d " "but not pseudo-linked\n", - inode->i_ino); + inode->i_ino, cpg->bdst); dput(h_src); goto out_parent; } diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c index d03087c84..c33fb8318 100644 --- a/fs/aufs/dentry.c +++ b/fs/aufs/dentry.c @@ -685,6 +685,28 @@ out: return err; } +void au_refresh_dop(struct dentry *dentry, int force_reval) +{ + const struct dentry_operations *dop + = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; + static const unsigned int mask + = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; + + BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); + + if (dentry->d_op == dop) + return; + + AuDbg("%pd\n", dentry); + spin_lock(&dentry->d_lock); + if (dop == &aufs_dop) + dentry->d_flags |= mask; + else + dentry->d_flags &= ~mask; + dentry->d_op = dop; + spin_unlock(&dentry->d_lock); +} + int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) { int err, ebrange; @@ -1040,8 +1062,10 @@ static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) && inode && !(inode->i_state && I_LINKABLE) - && (IS_DEADDIR(inode) || !inode->i_nlink)) + && (IS_DEADDIR(inode) || !inode->i_nlink)) { + AuTraceErr(err); goto out_inval; + } do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); if (do_udba && inode) { @@ -1050,8 +1074,10 @@ static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) if (bstart >= 0) { h_inode = au_h_iptr(inode, bstart); - if (h_inode && au_test_higen(inode, h_inode)) + if (h_inode && au_test_higen(inode, h_inode)) { + AuTraceErr(err); goto out_inval; + } } } @@ -1090,3 +1116,8 @@ const struct dentry_operations aufs_dop = { .d_weak_revalidate = aufs_d_revalidate, .d_release = aufs_d_release }; + +/* aufs_dop without d_revalidate */ +const struct dentry_operations aufs_dop_noreval = { + .d_release = aufs_d_release +}; diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h index 65161462b..522522179 100644 --- a/fs/aufs/dentry.h +++ b/fs/aufs/dentry.h @@ -31,7 +31,7 @@ struct au_dinfo { /* ---------------------------------------------------------------------- */ /* dentry.c */ -extern const struct dentry_operations aufs_dop; +extern const struct dentry_operations aufs_dop, aufs_dop_noreval; struct au_branch; struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, @@ -41,6 +41,7 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); int au_reval_dpath(struct dentry *dentry, unsigned int sigen); +void au_refresh_dop(struct dentry *dentry, int force_reval); /* dinfo.c */ void au_di_init_once(void *_di); diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c index 630819083..ccdcebeb3 100644 --- a/fs/aufs/dir.c +++ b/fs/aufs/dir.c @@ -102,9 +102,9 @@ static void au_do_dir_ts(void *arg) sb = a->dentry->d_sb; if (d_really_is_negative(a->dentry)) goto out; - aufs_read_lock(a->dentry, AuLock_DW | AuLock_DIR); /* noflush */ - /* no dir->i_mutex lock */ + aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ + dir = d_inode(a->dentry); bstart = au_ibstart(dir); bindex = au_br_index(sb, a->brid); diff --git a/fs/aufs/file.c b/fs/aufs/file.c index 8b17fbac1..72316b122 100644 --- a/fs/aufs/file.c +++ b/fs/aufs/file.c @@ -782,9 +782,11 @@ static void aufs_invalidatepage(struct page *page, unsigned int offset, { AuUnsupport(); } static int aufs_releasepage(struct page *page, gfp_t gfp) { AuUnsupport(); return 0; } +#if 0 /* called by memory compaction regardless file */ static int aufs_migratepage(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode) { AuUnsupport(); return 0; } +#endif static int aufs_launder_page(struct page *page) { AuUnsupport(); return 0; } static int aufs_is_partially_uptodate(struct page *page, @@ -817,7 +819,8 @@ const struct address_space_operations aufs_aop = { /* no bmap, no block device */ .invalidatepage = aufs_invalidatepage, .releasepage = aufs_releasepage, - .migratepage = aufs_migratepage, + /* is fallback_migrate_page ok? */ + /* .migratepage = aufs_migratepage, */ .launder_page = aufs_launder_page, .is_partially_uptodate = aufs_is_partially_uptodate, .is_dirty_writeback = aufs_is_dirty_writeback, diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h index 6c3e1debf..6196c606b 100644 --- a/fs/aufs/fstype.h +++ b/fs/aufs/fstype.h @@ -13,8 +13,8 @@ #include <linux/fs.h> #include <linux/magic.h> -#include <linux/romfs_fs.h> #include <linux/nfs_fs.h> +#include <linux/romfs_fs.h> static inline int au_test_aufs(struct super_block *sb) { diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c index 9c60a9eed..daad67aa1 100644 --- a/fs/aufs/i_op.c +++ b/fs/aufs/i_op.c @@ -1392,78 +1392,80 @@ static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) /* ---------------------------------------------------------------------- */ -struct inode_operations aufs_symlink_iop = { - .permission = aufs_permission, +/* no getattr version will be set by module.c:aufs_init() */ +struct inode_operations aufs_iop_nogetattr[AuIop_Last], + aufs_iop[] = { + [AuIop_SYMLINK] = { + .permission = aufs_permission, #ifdef CONFIG_FS_POSIX_ACL - .get_acl = aufs_get_acl, - .set_acl = aufs_set_acl, /* unsupport for symlink? */ + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, /* unsupport for symlink? */ #endif - .setattr = aufs_setattr, - .getattr = aufs_getattr, + .setattr = aufs_setattr, + .getattr = aufs_getattr, #ifdef CONFIG_AUFS_XATTR - .setxattr = aufs_setxattr, - .getxattr = aufs_getxattr, - .listxattr = aufs_listxattr, - .removexattr = aufs_removexattr, + .setxattr = aufs_setxattr, + .getxattr = aufs_getxattr, + .listxattr = aufs_listxattr, + .removexattr = aufs_removexattr, #endif - .readlink = generic_readlink, - .follow_link = aufs_follow_link, - .put_link = aufs_put_link, - - /* .update_time = aufs_update_time */ -}; - -struct inode_operations aufs_dir_iop = { - .create = aufs_create, - .lookup = aufs_lookup, - .link = aufs_link, - .unlink = aufs_unlink, - .symlink = aufs_symlink, - .mkdir = aufs_mkdir, - .rmdir = aufs_rmdir, - .mknod = aufs_mknod, - .rename = aufs_rename, - - .permission = aufs_permission, + .readlink = generic_readlink, + .follow_link = aufs_follow_link, + .put_link = aufs_put_link, + + /* .update_time = aufs_update_time */ + }, + [AuIop_DIR] = { + .create = aufs_create, + .lookup = aufs_lookup, + .link = aufs_link, + .unlink = aufs_unlink, + .symlink = aufs_symlink, + .mkdir = aufs_mkdir, + .rmdir = aufs_rmdir, + .mknod = aufs_mknod, + .rename = aufs_rename, + + .permission = aufs_permission, #ifdef CONFIG_FS_POSIX_ACL - .get_acl = aufs_get_acl, - .set_acl = aufs_set_acl, + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, #endif - .setattr = aufs_setattr, - .getattr = aufs_getattr, + .setattr = aufs_setattr, + .getattr = aufs_getattr, #ifdef CONFIG_AUFS_XATTR - .setxattr = aufs_setxattr, - .getxattr = aufs_getxattr, - .listxattr = aufs_listxattr, - .removexattr = aufs_removexattr, + .setxattr = aufs_setxattr, + .getxattr = aufs_getxattr, + .listxattr = aufs_listxattr, + .removexattr = aufs_removexattr, #endif - .update_time = aufs_update_time, - .atomic_open = aufs_atomic_open, - .tmpfile = aufs_tmpfile -}; - -struct inode_operations aufs_iop = { - .permission = aufs_permission, + .update_time = aufs_update_time, + .atomic_open = aufs_atomic_open, + .tmpfile = aufs_tmpfile + }, + [AuIop_OTHER] = { + .permission = aufs_permission, #ifdef CONFIG_FS_POSIX_ACL - .get_acl = aufs_get_acl, - .set_acl = aufs_set_acl, + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, #endif - .setattr = aufs_setattr, - .getattr = aufs_getattr, + .setattr = aufs_setattr, + .getattr = aufs_getattr, #ifdef CONFIG_AUFS_XATTR - .setxattr = aufs_setxattr, - .getxattr = aufs_getxattr, - .listxattr = aufs_listxattr, - .removexattr = aufs_removexattr, + .setxattr = aufs_setxattr, + .getxattr = aufs_getxattr, + .listxattr = aufs_listxattr, + .removexattr = aufs_removexattr, #endif - .update_time = aufs_update_time + .update_time = aufs_update_time + } }; diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c index 652e973ce..fd815fdbc 100644 --- a/fs/aufs/i_op_ren.c +++ b/fs/aufs/i_op_ren.c @@ -829,11 +829,9 @@ int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, if (unlikely(d_really_is_positive(a->dst_dentry) && !d_is_dir(a->dst_dentry))) goto out_free; - err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, - AuLock_DIR | flags); - } else - err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, - flags); + flags |= AuLock_DIRS; + } + err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, flags); if (unlikely(err)) goto out_free; diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c index 559da3358..6db3d6f62 100644 --- a/fs/aufs/inode.c +++ b/fs/aufs/inode.c @@ -87,6 +87,32 @@ out: return err; } +void au_refresh_iop(struct inode *inode, int force_getattr) +{ + int type; + struct au_sbinfo *sbi = au_sbi(inode->i_sb); + const struct inode_operations *iop + = force_getattr ? aufs_iop : sbi->si_iop_array; + + if (inode->i_op == iop) + return; + + switch (inode->i_mode & S_IFMT) { + case S_IFDIR: + type = AuIop_DIR; + break; + case S_IFLNK: + type = AuIop_SYMLINK; + break; + default: + type = AuIop_OTHER; + break; + } + + inode->i_op = iop + type; + /* unnecessary smp_wmb() */ +} + int au_refresh_hinode_self(struct inode *inode) { int err, update; @@ -168,11 +194,13 @@ static int set_inode(struct inode *inode, struct dentry *dentry) struct dentry *h_dentry; struct inode *h_inode; struct au_iinfo *iinfo; + struct inode_operations *iop; IiMustWriteLock(inode); err = 0; isdir = 0; + iop = au_sbi(inode->i_sb)->si_iop_array; bstart = au_dbstart(dentry); h_dentry = au_h_dptr(dentry, bstart); h_inode = d_inode(h_dentry); @@ -180,7 +208,7 @@ static int set_inode(struct inode *inode, struct dentry *dentry) switch (mode & S_IFMT) { case S_IFREG: btail = au_dbtail(dentry); - inode->i_op = &aufs_iop; + inode->i_op = iop + AuIop_OTHER; inode->i_fop = &aufs_file_fop; err = au_dy_iaop(inode, bstart, h_inode); if (unlikely(err)) @@ -189,19 +217,19 @@ static int set_inode(struct inode *inode, struct dentry *dentry) case S_IFDIR: isdir = 1; btail = au_dbtaildir(dentry); - inode->i_op = &aufs_dir_iop; + inode->i_op = iop + AuIop_DIR; inode->i_fop = &aufs_dir_fop; break; case S_IFLNK: btail = au_dbtail(dentry); - inode->i_op = &aufs_symlink_iop; + inode->i_op = iop + AuIop_SYMLINK; break; case S_IFBLK: case S_IFCHR: case S_IFIFO: case S_IFSOCK: btail = au_dbtail(dentry); - inode->i_op = &aufs_iop; + inode->i_op = iop + AuIop_OTHER; init_special_inode(inode, mode, h_inode->i_rdev); break; default: diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h index 003534a44..a3a187616 100644 --- a/fs/aufs/inode.h +++ b/fs/aufs/inode.h @@ -117,6 +117,7 @@ static inline struct au_iinfo *au_ii(struct inode *inode) /* inode.c */ struct inode *au_igrab(struct inode *inode); +void au_refresh_iop(struct inode *inode, int force_getattr); int au_refresh_hinode_self(struct inode *inode); int au_refresh_hinode(struct inode *inode, struct dentry *dentry); int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, @@ -138,7 +139,14 @@ static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, } /* i_op.c */ -extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; +enum { + AuIop_SYMLINK, + AuIop_DIR, + AuIop_OTHER, + AuIop_Last +}; +extern struct inode_operations aufs_iop[AuIop_Last], + aufs_iop_nogetattr[AuIop_Last]; /* au_wr_dir flags */ #define AuWrDir_ADD_ENTRY 1 diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c index 69f7e9647..f324758e9 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -114,7 +114,7 @@ int au_loopback_init(void) int err; struct super_block *sb __maybe_unused; - AuDebugOn(sizeof(sb->s_magic) != sizeof(unsigned long)); + BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(unsigned long)); err = 0; au_warn_loopback_array = kcalloc(au_warn_loopback_step, @@ -127,6 +127,7 @@ int au_loopback_init(void) void au_loopback_fin(void) { - symbol_put(loop_backing_file); + if (backing_file_func) + symbol_put(loop_backing_file); kfree(au_warn_loopback_array); } diff --git a/fs/aufs/module.c b/fs/aufs/module.c index a7a4b3647..3268e62e4 100644 --- a/fs/aufs/module.c +++ b/fs/aufs/module.c @@ -59,11 +59,10 @@ static void au_cache_fin(void) /* excluding AuCache_HNOTIFY */ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); - for (i = 0; i < AuCache_HNOTIFY; i++) - if (au_cachep[i]) { - kmem_cache_destroy(au_cachep[i]); - au_cachep[i] = NULL; - } + for (i = 0; i < AuCache_HNOTIFY; i++) { + kmem_cache_destroy(au_cachep[i]); + au_cachep[i] = NULL; + } } /* ---------------------------------------------------------------------- */ @@ -133,6 +132,10 @@ static int __init aufs_init(void) au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); + memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); + for (i = 0; i < AuIop_Last; i++) + aufs_iop_nogetattr[i].getattr = NULL; + au_sbilist_init(); sysaufs_brs_init(); au_debug_init(); diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c index bec20d360..53e0f6af9 100644 --- a/fs/aufs/mvdown.c +++ b/fs/aufs/mvdown.c @@ -353,6 +353,12 @@ static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) au_set_dbstart(a->dentry, a->mvd_bdst); au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); au_set_ibstart(a->inode, a->mvd_bdst); + } else { + /* hide the lower */ + au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); + au_set_dbend(a->dentry, a->mvd_bsrc); + au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); + au_set_ibend(a->inode, a->mvd_bsrc); } if (au_dbend(a->dentry) < a->mvd_bdst) au_set_dbend(a->dentry, a->mvd_bdst); @@ -608,7 +614,9 @@ int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) int err, e; unsigned char dmsg; struct au_mvd_args *args; + struct inode *inode; + inode = d_inode(dentry); err = -EPERM; if (unlikely(!capable(CAP_SYS_ADMIN))) goto out; @@ -630,7 +638,7 @@ int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); args->mvdown.au_errno = 0; args->dentry = dentry; - args->inode = d_inode(dentry); + args->inode = inode; args->sb = dentry->d_sb; err = -ENOENT; @@ -644,8 +652,8 @@ int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) goto out_dir; } - mutex_lock_nested(&args->inode->i_mutex, I_MUTEX_CHILD); - err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); if (unlikely(err)) goto out_inode; @@ -659,15 +667,16 @@ int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) goto out_parent; au_cpup_attr_timesizes(args->dir); - au_cpup_attr_timesizes(args->inode); - au_cpup_igen(args->inode, au_h_iptr(args->inode, args->mvd_bdst)); + au_cpup_attr_timesizes(inode); + if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) + au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); /* au_digen_dec(dentry); */ out_parent: di_write_unlock(args->parent); aufs_read_unlock(dentry, AuLock_DW); out_inode: - mutex_unlock(&args->inode->i_mutex); + mutex_unlock(&inode->i_mutex); out_dir: mutex_unlock(&args->dir->i_mutex); out_free: diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c index 90098fe7f..f79d15e32 100644 --- a/fs/aufs/opts.c +++ b/fs/aufs/opts.c @@ -1555,10 +1555,10 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags, { int err, fhsm; aufs_bindex_t bindex, bend; - unsigned char do_plink, skip, do_free; + unsigned char do_plink, skip, do_free, can_no_dreval; struct au_branch *br; struct au_wbr *wbr; - struct dentry *root; + struct dentry *root, *dentry; struct inode *dir, *h_dir; struct au_sbinfo *sbinfo; struct au_hinode *hdir; @@ -1588,6 +1588,8 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags, root = sb->s_root; dir = d_inode(root); do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); + can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), + UDBA_NONE); bend = au_sbend(sb); for (bindex = 0; !err && bindex <= bend; bindex++) { skip = 0; @@ -1636,6 +1638,15 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags, if (wbr) wbr_wh_read_unlock(wbr); + if (can_no_dreval) { + dentry = br->br_path.dentry; + spin_lock(&dentry->d_lock); + if (dentry->d_flags & + (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) + can_no_dreval = 0; + spin_unlock(&dentry->d_lock); + } + if (au_br_fhsm(br->br_perm)) { fhsm++; AuDebugOn(!br->br_fhsm); @@ -1659,6 +1670,11 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags, } } + if (can_no_dreval) + au_fset_si(sbinfo, NO_DREVAL); + else + au_fclr_si(sbinfo, NO_DREVAL); + if (fhsm >= 2) { au_fset_si(sbinfo, FHSM); for (bindex = bend; bindex >= 0; bindex--) { @@ -1770,6 +1786,7 @@ out: int au_opts_remount(struct super_block *sb, struct au_opts *opts) { int err, rerr; + unsigned char no_dreval; struct inode *dir; struct au_opt_xino *opt_xino; struct au_opt *opt; @@ -1777,9 +1794,9 @@ int au_opts_remount(struct super_block *sb, struct au_opts *opts) SiMustWriteLock(sb); + err = 0; dir = d_inode(sb->s_root); sbinfo = au_sbi(sb); - err = 0; opt_xino = NULL; opt = opts->opt; while (err >= 0 && opt->type != Opt_tail) { @@ -1795,10 +1812,14 @@ int au_opts_remount(struct super_block *sb, struct au_opts *opts) AuTraceErr(err); /* go on even err */ + no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); if (unlikely(rerr && !err)) err = rerr; + if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) + au_fset_opts(opts->flags, REFRESH_IDOP); + if (au_ftest_opts(opts->flags, TRUNC_XIB)) { rerr = au_xib_trunc(sb); if (unlikely(rerr && !err)) @@ -1807,7 +1828,10 @@ int au_opts_remount(struct super_block *sb, struct au_opts *opts) /* will be handled by the caller */ if (!au_ftest_opts(opts->flags, REFRESH) - && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO))) + && (opts->given_udba + || au_opt_test(sbinfo->si_mntflags, XINO) + || au_ftest_opts(opts->flags, REFRESH_IDOP) + )) au_fset_opts(opts->flags, REFRESH); AuDbg("status 0x%x\n", opts->flags); diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h index da552ff50..3899e9240 100644 --- a/fs/aufs/opts.h +++ b/fs/aufs/opts.h @@ -161,6 +161,7 @@ struct au_opt { #define AuOpts_REFRESH (1 << 1) #define AuOpts_TRUNC_XIB (1 << 2) #define AuOpts_REFRESH_DYAOP (1 << 3) +#define AuOpts_REFRESH_IDOP (1 << 4) #define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) #define au_fset_opts(flags, name) \ do { (flags) |= AuOpts_##name; } while (0) diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c index cb7ac83a1..8f2ec5573 100644 --- a/fs/aufs/sbinfo.c +++ b/fs/aufs/sbinfo.c @@ -113,6 +113,9 @@ int au_si_alloc(struct super_block *sb) au_sphl_init(&sbinfo->si_files); + /* with getattr by default */ + sbinfo->si_iop_array = aufs_iop; + /* leave other members for sysaufs and si_mnt. */ sbinfo->si_sb = sb; sb->s_fs_info = sbinfo; @@ -237,7 +240,10 @@ int aufs_read_lock(struct dentry *dentry, int flags) if (au_ftest_lock(flags, GEN)) { err = au_digen_test(dentry, au_sigen(sb)); - AuDebugOn(!err && au_dbrange_test(dentry)); + if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) + AuDebugOn(!err && au_dbrange_test(dentry)); + else if (!err) + err = au_dbrange_test(dentry); if (unlikely(err)) aufs_read_unlock(dentry, flags); } @@ -278,7 +284,7 @@ int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) if (unlikely(err)) goto out; - di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); + di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); if (au_ftest_lock(flags, GEN)) { sigen = au_sigen(sb); diff --git a/fs/aufs/super.c b/fs/aufs/super.c index 7ae6ea12e..3fe10d35d 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c @@ -93,13 +93,13 @@ static int au_show_brs(struct seq_file *seq, struct super_block *sb) err = au_seq_path(seq, &path); if (!err) { au_optstr_br_perm(&perm, br->br_perm); - err = seq_printf(seq, "=%s", perm.a); - if (err == -1) - err = -E2BIG; + seq_printf(seq, "=%s", perm.a); + if (bindex != bend) + seq_putc(seq, ':'); } - if (!err && bindex != bend) - err = seq_putc(seq, ':'); } + if (unlikely(err || seq_has_overflowed(seq))) + err = -E2BIG; return err; } @@ -466,7 +466,8 @@ void au_array_free(void *array) } } -void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, + struct super_block *sb, void *arg) { void *array; unsigned long long n, sz; @@ -491,7 +492,7 @@ void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) goto out; } - n = cb(array, *hint, arg); + n = cb(sb, array, *hint, arg); AuDebugOn(n > *hint); out: @@ -499,7 +500,7 @@ out: return array; } -static unsigned long long au_iarray_cb(void *a, +static unsigned long long au_iarray_cb(struct super_block *sb, void *a, unsigned long long max __maybe_unused, void *arg) { @@ -510,7 +511,7 @@ static unsigned long long au_iarray_cb(void *a, n = 0; p = a; head = arg; - spin_lock(&inode_sb_list_lock); + spin_lock(&sb->s_inode_list_lock); list_for_each_entry(inode, head, i_sb_list) { if (!is_bad_inode(inode) && au_ii(inode)->ii_bstart >= 0) { @@ -524,7 +525,7 @@ static unsigned long long au_iarray_cb(void *a, spin_unlock(&inode->i_lock); } } - spin_unlock(&inode_sb_list_lock); + spin_unlock(&sb->s_inode_list_lock); return n; } @@ -532,7 +533,7 @@ static unsigned long long au_iarray_cb(void *a, struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) { *max = atomic_long_read(&au_sbi(sb)->si_ninodes); - return au_array_alloc(max, au_iarray_cb, &sb->s_inodes); + return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); } void au_iarray_free(struct inode **a, unsigned long long max) @@ -568,7 +569,7 @@ static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, struct au_sbinfo *sbinfo, - const unsigned int dir_flags) + const unsigned int dir_flags, unsigned int do_idop) { int err; struct dentry *parent; @@ -591,11 +592,17 @@ static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, } dput(parent); + if (!err) { + if (do_idop) + au_refresh_dop(dentry, /*force_reval*/0); + } else + au_refresh_dop(dentry, /*force_reval*/1); + AuTraceErr(err); return err; } -static int au_refresh_d(struct super_block *sb) +static int au_refresh_d(struct super_block *sb, unsigned int do_idop) { int err, i, j, ndentry, e; unsigned int sigen; @@ -606,6 +613,9 @@ static int au_refresh_d(struct super_block *sb) struct dentry *root = sb->s_root; const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); + if (do_idop) + au_refresh_dop(root, /*force_reval*/0); + err = au_dpages_init(&dpages, GFP_NOFS); if (unlikely(err)) goto out; @@ -621,7 +631,8 @@ static int au_refresh_d(struct super_block *sb) ndentry = dpage->ndentry; for (j = 0; j < ndentry; j++) { d = dentries[j]; - e = au_do_refresh_d(d, sigen, sbinfo, dir_flags); + e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, + do_idop); if (unlikely(e && !err)) err = e; /* go on even err */ @@ -634,7 +645,7 @@ out: return err; } -static int au_refresh_i(struct super_block *sb) +static int au_refresh_i(struct super_block *sb, unsigned int do_idop) { int err, e; unsigned int sigen; @@ -652,17 +663,22 @@ static int au_refresh_i(struct super_block *sb) inode = array[ull]; if (unlikely(!inode)) break; + + e = 0; + ii_write_lock_child(inode); if (au_iigen(inode, NULL) != sigen) { - ii_write_lock_child(inode); e = au_refresh_hinode_self(inode); - ii_write_unlock(inode); if (unlikely(e)) { + au_refresh_iop(inode, /*force_getattr*/1); pr_err("error %d, i%lu\n", e, inode->i_ino); if (!err) err = e; /* go on even if err */ } } + if (!e && do_idop) + au_refresh_iop(inode, /*force_getattr*/0); + ii_write_unlock(inode); } au_iarray_free(array, max); @@ -671,7 +687,7 @@ out: return err; } -static void au_remount_refresh(struct super_block *sb) +static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) { int err, e; unsigned int udba; @@ -679,9 +695,11 @@ static void au_remount_refresh(struct super_block *sb) struct dentry *root; struct inode *inode; struct au_branch *br; + struct au_sbinfo *sbi; au_sigen_inc(sb); - au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR); + sbi = au_sbi(sb); + au_fclr_si(sbi, FAILED_REFRESH_DIR); root = sb->s_root; DiMustNoWaiters(root); @@ -700,9 +718,25 @@ static void au_remount_refresh(struct super_block *sb) } au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); + if (do_idop) { + if (au_ftest_si(sbi, NO_DREVAL)) { + AuDebugOn(sb->s_d_op == &aufs_dop_noreval); + sb->s_d_op = &aufs_dop_noreval; + AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); + sbi->si_iop_array = aufs_iop_nogetattr; + } else { + AuDebugOn(sb->s_d_op == &aufs_dop); + sb->s_d_op = &aufs_dop; + AuDebugOn(sbi->si_iop_array == aufs_iop); + sbi->si_iop_array = aufs_iop; + } + pr_info("reset to %pf and %pf\n", + sb->s_d_op, sbi->si_iop_array); + } + di_write_unlock(root); - err = au_refresh_d(sb); - e = au_refresh_i(sb); + err = au_refresh_d(sb, do_idop); + e = au_refresh_i(sb, do_idop); if (unlikely(e && !err)) err = e; /* aufs_write_lock() calls ..._child() */ @@ -777,7 +811,7 @@ static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) au_opts_free(&opts); if (au_ftest_opts(opts.flags, REFRESH)) - au_remount_refresh(sb); + au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { mntflags = au_mntflags(sb); @@ -824,7 +858,7 @@ static int alloc_root(struct super_block *sb) if (IS_ERR(inode)) goto out; - inode->i_op = &aufs_dir_iop; + inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ inode->i_fop = &aufs_dir_fop; inode->i_mode = S_IFDIR; set_nlink(inode, 2); @@ -853,6 +887,7 @@ static int aufs_fill_super(struct super_block *sb, void *raw_data, { int err; struct au_opts opts; + struct au_sbinfo *sbinfo; struct dentry *root; struct inode *inode; char *arg = raw_data; @@ -874,6 +909,7 @@ static int aufs_fill_super(struct super_block *sb, void *raw_data, err = au_si_alloc(sb); if (unlikely(err)) goto out_opts; + sbinfo = au_sbi(sb); /* all timestamps always follow the ones on the branch */ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; @@ -909,6 +945,13 @@ static int aufs_fill_super(struct super_block *sb, void *raw_data, aufs_write_lock(root); err = au_opts_mount(sb, &opts); au_opts_free(&opts); + if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { + sb->s_d_op = &aufs_dop_noreval; + pr_info("%pf\n", sb->s_d_op); + au_refresh_dop(root, /*force_reval*/0); + sbinfo->si_iop_array = aufs_iop_nogetattr; + au_refresh_iop(inode, /*force_getattr*/0); + } aufs_write_unlock(root); mutex_unlock(&inode->i_mutex); if (!err) @@ -918,8 +961,8 @@ out_root: dput(root); sb->s_root = NULL; out_info: - dbgaufs_si_fin(au_sbi(sb)); - kobject_put(&au_sbi(sb)->si_kobj); + dbgaufs_si_fin(sbinfo); + kobject_put(&sbinfo->si_kobj); sb->s_fs_info = NULL; out_opts: free_page((unsigned long)opts.opt); @@ -968,7 +1011,7 @@ static void aufs_kill_sb(struct super_block *sb) sbinfo->si_wbr_create_ops->fin(sb); if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); - au_remount_refresh(sb); + au_remount_refresh(sb, /*do_idop*/0); } if (au_opt_test(sbinfo->si_mntflags, PLINK)) au_plink_put(sb, /*verbose*/1); diff --git a/fs/aufs/super.h b/fs/aufs/super.h index 8ec54fa6e..e0f588ef2 100644 --- a/fs/aufs/super.h +++ b/fs/aufs/super.h @@ -178,6 +178,9 @@ struct au_sbinfo { /* file list */ struct au_sphlhead si_files; + /* with/without getattr, brother of sb->s_d_op */ + struct inode_operations *si_iop_array; + /* * sysfs and lifetime management. * this is not a small structure and it may be a waste of memory in case @@ -209,8 +212,8 @@ struct au_sbinfo { * if it is false, refreshing dirs at access time is unnecesary */ #define AuSi_FAILED_REFRESH_DIR 1 - #define AuSi_FHSM (1 << 1) /* fhsm is active now */ +#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ #ifndef CONFIG_AUFS_FHSM #undef AuSi_FHSM @@ -246,7 +249,7 @@ static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, #define AuLock_IR (1 << 1) /* read-lock inode */ #define AuLock_IW (1 << 2) /* write-lock inode */ #define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ -#define AuLock_DIR (1 << 4) /* target is a dir */ +#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ #define AuLock_NOPLM (1 << 5) /* return err in plm mode */ #define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ #define AuLock_GEN (1 << 7) /* test digen/iigen */ @@ -261,10 +264,11 @@ static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, /* super.c */ extern struct file_system_type aufs_fs_type; struct inode *au_iget_locked(struct super_block *sb, ino_t ino); -typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max, - void *arg); +typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, + unsigned long long max, void *arg); void au_array_free(void *array); -void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg); +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, + struct super_block *sb, void *arg); struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); void au_iarray_free(struct inode **a, unsigned long long max); diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c index cc74d02b1..ec8df8f6c 100644 --- a/fs/aufs/sysfs.c +++ b/fs/aufs/sysfs.c @@ -64,15 +64,15 @@ static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, err = au_seq_path(seq, &path); if (!err) { au_optstr_br_perm(&perm, br->br_perm); - err = seq_printf(seq, "=%s\n", perm.a); + seq_printf(seq, "=%s\n", perm.a); } break; case AuBrSysfs_BRID: - err = seq_printf(seq, "%d\n", br->br_id); + seq_printf(seq, "%d\n", br->br_id); break; } di_read_unlock(root, !AuLock_IR); - if (err == -1) + if (unlikely(err || seq_has_overflowed(seq))) err = -E2BIG; return err; @@ -229,8 +229,8 @@ static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) err = au_seq_path(seq, &br->br_path); if (unlikely(err)) break; - err = seq_putc(seq, '\0'); - if (!err && seq->count <= sz) { + seq_putc(seq, '\0'); + if (!seq_has_overflowed(seq)) { err = copy_to_user(arg->path, seq->buf, seq->count); seq->count = 0; if (unlikely(err)) diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c index dcfa82462..3a0182b90 100644 --- a/fs/aufs/sysrq.c +++ b/fs/aufs/sysrq.c @@ -64,14 +64,14 @@ static void sysrq_sb(struct super_block *sb) struct inode *i; pr("isolated inode\n"); - spin_lock(&inode_sb_list_lock); + spin_lock(&sb->s_inode_list_lock); list_for_each_entry(i, &sb->s_inodes, i_sb_list) { spin_lock(&i->i_lock); if (1 || hlist_empty(&i->i_dentry)) au_dpri_inode(i); spin_unlock(&i->i_lock); } - spin_unlock(&inode_sb_list_lock); + spin_unlock(&sb->s_inode_list_lock); } #endif pr("files\n"); diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h index 541b7b160..4218da12e 100644 --- a/fs/aufs/vfsub.h +++ b/fs/aufs/vfsub.h @@ -19,7 +19,6 @@ /* copied from linux/fs/internal.h */ /* todo: BAD approach!! */ extern void __mnt_drop_write(struct vfsmount *); -extern spinlock_t inode_sb_list_lock; extern int open_check_o_direct(struct file *f); /* ---------------------------------------------------------------------- */ |