Commit ab70d2ad authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: dentry op, opt-out ->d_revalidate()



Optimize out ->d_revalidate() if possible.
If the refreshing failed, then ->d_revalidate() remains. In this case,
aufs has two types of dentries. One has ->d_revalidate, the other
doesn't. I am afraid it will confuse me someday.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 5531888f
......@@ -655,6 +655,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, nbr;
......@@ -1064,3 +1086,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
};
......@@ -49,7 +49,7 @@ struct au_do_lookup_args {
/* ---------------------------------------------------------------------- */
/* 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,
......@@ -60,6 +60,7 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop,
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);
......
......@@ -1062,10 +1062,10 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
{
int err;
aufs_bindex_t bindex, bbot;
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;
......@@ -1084,6 +1084,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);
bbot = au_sbbot(sb);
for (bindex = 0; !err && bindex <= bbot; bindex++) {
skip = 0;
......@@ -1123,6 +1125,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 (skip)
continue;
......@@ -1141,6 +1152,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);
return err;
}
......@@ -1238,6 +1254,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;
......@@ -1263,10 +1280,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_DOP);
if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
rerr = au_xib_trunc(sb);
if (unlikely(rerr && !err))
......@@ -1275,7 +1296,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_DOP)
))
au_fset_opts(opts->flags, REFRESH);
AuDbg("status 0x%x\n", opts->flags);
......
......@@ -135,6 +135,7 @@ struct au_opt {
#define AuOpts_REFRESH (1 << 1)
#define AuOpts_TRUNC_XIB (1 << 2)
#define AuOpts_REFRESH_DYAOP (1 << 3)
#define AuOpts_REFRESH_DOP (1 << 4)
#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
#define au_fset_opts(flags, name) \
do { (flags) |= AuOpts_##name; } while (0)
......
......@@ -460,7 +460,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_dop)
{
int err;
struct dentry *parent;
......@@ -483,11 +483,17 @@ static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
}
dput(parent);
if (!err) {
if (do_dop)
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_dop)
{
int err, i, j, ndentry, e;
unsigned int sigen;
......@@ -498,6 +504,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_dop)
au_refresh_dop(root, /*force_reval*/0);
err = au_dpages_init(&dpages, GFP_NOFS);
if (unlikely(err))
goto out;
......@@ -513,7 +522,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_dop);
if (unlikely(e && !err))
err = e;
/* go on even err */
......@@ -563,7 +573,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_dop)
{
int err, e;
unsigned int udba;
......@@ -571,9 +581,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);
......@@ -592,8 +604,19 @@ static void au_remount_refresh(struct super_block *sb)
}
au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
if (do_dop) {
if (au_ftest_si(sbi, NO_DREVAL)) {
AuDebugOn(sb->s_d_op == &aufs_dop_noreval);
sb->s_d_op = &aufs_dop_noreval;
} else {
AuDebugOn(sb->s_d_op == &aufs_dop);
sb->s_d_op = &aufs_dop;
}
pr_info("reset to %ps\n", sb->s_d_op);
}
di_write_unlock(root);
err = au_refresh_d(sb);
err = au_refresh_d(sb, do_dop);
e = au_refresh_i(sb);
if (unlikely(e && !err))
err = e;
......@@ -670,7 +693,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_DOP));
if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
mntflags = au_mntflags(sb);
......@@ -747,6 +770,7 @@ static int aufs_fill_super(struct super_block *sb, void *raw_data,
struct au_opts opts = {
.opt = NULL
};
struct au_sbinfo *sbinfo;
struct dentry *root;
struct inode *inode;
char *arg = raw_data;
......@@ -767,6 +791,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 |= SB_NOATIME | SB_NODIRATIME;
......@@ -801,6 +826,11 @@ 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("%ps\n", sb->s_d_op);
au_refresh_dop(root, /*force_reval*/0);
}
aufs_write_unlock(root);
inode_unlock(inode);
if (!err)
......@@ -810,7 +840,7 @@ out_root:
dput(root);
sb->s_root = NULL;
out_info:
kobject_put(&au_sbi(sb)->si_kobj);
kobject_put(&sbinfo->si_kobj);
sb->s_fs_info = NULL;
out_opts:
free_page((unsigned long)opts.opt);
......@@ -853,7 +883,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);
......
......@@ -156,6 +156,8 @@ struct au_sbinfo {
* if it is false, refreshing dirs at access time is unnecessary
*/
#define AuSi_FAILED_REFRESH_DIR 1
/* add later */
#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */
static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
unsigned int flag)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment