diff options
Diffstat (limited to 'fs/aufs/super.c')
-rw-r--r-- | fs/aufs/super.c | 95 |
1 files changed, 69 insertions, 26 deletions
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); |