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

aufs: hnotify 3/3, callers



In order to prevent firing the notify event from aufs itself, hnotify
feature is suspend/resume-able. They are combined with mutex lock/unlock
for the parent dir.

See also previous commits.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 6b81a214
......@@ -19,6 +19,7 @@ static void au_br_do_free(struct au_branch *br)
struct au_wbr *wbr;
struct au_dykey **key;
au_hnotify_fin_br(br);
au_xino_put(br);
AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0));
......@@ -120,13 +121,16 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
add_branch->br_xino = au_xino_alloc(/*nfile*/1);
if (unlikely(!add_branch->br_xino))
goto out_br;
err = au_hnotify_init_br(add_branch, perm);
if (unlikely(err))
goto out_xino;
if (au_br_writable(perm)) {
/* may be freed separately at changing the branch permission */
add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr),
GFP_NOFS);
if (unlikely(!add_branch->br_wbr))
goto out_xino;
goto out_hnotify;
}
root = sb->s_root;
......@@ -143,6 +147,8 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
au_kfree_rcu(add_branch->br_wbr);
out_hnotify:
au_hnotify_fin_br(add_branch);
out_xino:
au_xino_put(add_branch);
out_br:
......@@ -275,7 +281,7 @@ static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
bindex = au_br_index(sb, br->br_id);
if (0 <= bindex) {
hdir = au_hi(d_inode(sb->s_root), bindex);
inode_lock_nested(hdir->hi_inode, AuLsc_I_PARENT);
au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT);
} else {
h_dentry = au_br_dentry(br);
h_inode = d_inode(h_dentry);
......@@ -289,7 +295,7 @@ static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
wbr_wh_write_unlock(wbr);
}
if (hdir)
inode_unlock(hdir->hi_inode);
au_hn_inode_unlock(hdir);
else
inode_unlock(h_inode);
vfsub_mnt_drop_write(au_br_mnt(br));
......
......@@ -55,7 +55,7 @@ char *au_plevel = KERN_DEBUG;
/* ---------------------------------------------------------------------- */
static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn,
struct dentry *wh)
{
char *n = NULL;
......@@ -75,12 +75,12 @@ static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
}
dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
" ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
" hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
bindex, inode,
inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
i_size_read(inode), (unsigned long long)inode->i_blocks,
(long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff,
hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff,
inode->i_mapping ? inode->i_mapping->nrpages : 0,
inode->i_state, inode->i_flags, inode_peek_iversion(inode),
inode->i_generation,
......@@ -91,10 +91,11 @@ static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
void au_dpri_inode(struct inode *inode)
{
struct au_iinfo *iinfo;
struct au_hinode *hi;
aufs_bindex_t bindex;
int err;
int err, hn;
err = do_pri_inode(-1, inode, NULL);
err = do_pri_inode(-1, inode, -1, NULL);
if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode))
return;
......@@ -103,9 +104,12 @@ void au_dpri_inode(struct inode *inode)
iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode));
if (iinfo->ii_btop < 0)
return;
for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++)
do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode,
iinfo->ii_hinode[0 + bindex].hi_whdentry);
hn = 0;
for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) {
hi = au_hinode(iinfo, bindex);
hn = !!au_hn(hi);
do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry);
}
}
void au_dpri_dalias(struct inode *inode)
......@@ -121,6 +125,7 @@ void au_dpri_dalias(struct inode *inode)
static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
{
struct dentry *wh = NULL;
int hn;
struct inode *inode;
struct au_iinfo *iinfo;
struct au_hinode *hi;
......@@ -136,6 +141,7 @@ static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
au_dcount(dentry), dentry->d_flags,
d_unhashed(dentry) ? "un" : "");
hn = -1;
inode = NULL;
if (d_is_positive(dentry))
inode = d_inode(dentry);
......@@ -145,9 +151,10 @@ static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
&& !au_is_bad_inode(inode)) {
iinfo = au_ii(inode);
hi = au_hinode(iinfo, bindex);
hn = !!au_hn(hi);
wh = hi->hi_whdentry;
}
do_pri_inode(bindex, inode, wh);
do_pri_inode(bindex, inode, hn, wh);
return 0;
}
......
......@@ -85,14 +85,14 @@ static void au_do_dir_ts(void *arg)
if (err)
goto out_unlock;
hdir = au_hi(dir, btop);
inode_lock_nested(hdir->hi_inode, AuLsc_I_PARENT);
au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT);
h_dir = au_h_iptr(dir, btop);
if (h_dir->i_nlink
&& timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) {
dt.dt_h_path = h_path;
au_dtime_revert(&dt);
}
inode_unlock(hdir->hi_inode);
au_hn_inode_unlock(hdir);
vfsub_mnt_drop_write(h_path.mnt);
au_cpup_attr_timesizes(dir);
......
......@@ -12,7 +12,7 @@
void au_pin_hdir_unlock(struct au_pin *p)
{
if (p->hdir)
inode_unlock(p->hdir->hi_inode);
au_hn_inode_unlock(p->hdir);
}
int au_pin_hdir_lock(struct au_pin *p)
......@@ -24,7 +24,7 @@ int au_pin_hdir_lock(struct au_pin *p)
goto out;
/* even if an error happens later, keep this lock */
inode_lock_nested(p->hdir->hi_inode, p->lsc_hi);
au_hn_inode_lock_nested(p->hdir, p->lsc_hi);
err = -EBUSY;
if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent)))
......
......@@ -25,6 +25,7 @@ struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex)
/* todo: hard/soft set? */
void au_hiput(struct au_hinode *hinode)
{
au_hn_free(hinode);
dput(hinode->hi_whdentry);
iput(hinode->hi_inode);
}
......@@ -37,6 +38,8 @@ unsigned int au_hi_flags(struct inode *inode, int isdir)
flags = 0;
if (au_opt_test(mnt_flags, XINO))
au_fset_hi(flags, XINO);
if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY))
au_fset_hi(flags, HNOTIFY);
return flags;
}
......@@ -74,6 +77,13 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
if (unlikely(err))
AuIOErr1("failed au_xino_write() %d\n", err);
}
if (au_ftest_hi(flags, HNOTIFY)
&& au_br_hnotifyable(br->br_perm)) {
err = au_hn_alloc(hinode, inode);
if (unlikely(err))
AuIOErr1("au_hn_alloc() %d\n", err);
}
}
}
......@@ -159,6 +169,7 @@ void au_hinode_init(struct au_hinode *hinode)
{
hinode->hi_inode = NULL;
hinode->hi_id = -1;
au_hn_init(hinode);
hinode->hi_whdentry = NULL;
}
......
......@@ -81,7 +81,10 @@ static void au_cache_fin(void)
* destroy cache.
*/
rcu_barrier();
for (i = 0; i < AuCache_Last; i++) {
/* excluding AuCache_HNOTIFY */
BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last);
for (i = 0; i < AuCache_HNOTIFY; i++) {
kmem_cache_destroy(au_cache[i]);
au_cache[i] = NULL;
}
......@@ -161,7 +164,7 @@ static int __init aufs_init(void)
au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
memset(au_cache, 0, sizeof(au_cache));
memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */
au_sbilist_init();
sysaufs_brs_init();
......@@ -175,14 +178,19 @@ static int __init aufs_init(void)
err = au_wkq_init();
if (unlikely(err))
goto out_procfs;
err = au_cache_init();
err = au_hnotify_init();
if (unlikely(err))
goto out_wkq;
err = au_cache_init();
if (unlikely(err))
goto out_hin;
/* since we define pr_fmt, call printk directly */
printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
goto out; /* success */
out_hin:
au_hnotify_fin();
out_wkq:
au_wkq_fin();
out_procfs:
......
......@@ -22,6 +22,7 @@ enum {
Opt_trunc_xino_path, Opt_itrunc_xino,
Opt_trunc_xib, Opt_notrunc_xib,
Opt_plink, Opt_noplink, Opt_list_plink,
Opt_udba,
Opt_dio, Opt_nodio,
Opt_wbr_copyup, Opt_wbr_create,
Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
......@@ -54,6 +55,8 @@ static match_table_t options = {
{Opt_list_plink, "list_plink"},
#endif
{Opt_udba, "udba=%s"},
{Opt_dio, "dio"},
{Opt_nodio, "nodio"},
......@@ -259,10 +262,15 @@ void au_optstr_br_perm(au_br_perm_str_t *str, int perm)
static match_table_t udbalevel = {
{AuOpt_UDBA_REVAL, "reval"},
{AuOpt_UDBA_NONE, "none"},
#ifdef CONFIG_AUFS_HNOTIFY
{AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
#ifdef CONFIG_AUFS_HFSNOTIFY
{AuOpt_UDBA_HNOTIFY, "fsnotify"},
#endif
#endif
{-1, NULL}
};
/* re-commit later */ __maybe_unused
static int noinline_for_stack udba_val(char *str)
{
substring_t args[MAX_OPT_ARGS];
......@@ -461,6 +469,10 @@ static void dump_opts(struct au_opts *opts)
case Opt_list_plink:
AuLabel(list_plink);
break;
case Opt_udba:
AuDbg("udba %d, %s\n",
opt->udba, au_optstr_udba(opt->udba));
break;
case Opt_dio:
AuLabel(dio);
break;
......@@ -730,6 +742,15 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
opt->type = token;
break;
case Opt_udba:
opt->udba = udba_val(a->args[0].from);
if (opt->udba >= 0) {
err = 0;
opt->type = token;
} else
pr_err("wrong value, %s\n", opt_str);
break;
case Opt_wbr_create:
u.create = &opt->wbr_create;
u.create->wbr_create
......@@ -839,6 +860,12 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
err = 1; /* handled */
sbinfo = au_sbi(sb);
switch (opt->type) {
case Opt_udba:
sbinfo->si_mntflags &= ~AuOptMask_UDBA;
sbinfo->si_mntflags |= opt->udba;
opts->given_udba |= opt->udba;
break;
case Opt_plink:
au_opt_set(sbinfo->si_mntflags, PLINK);
break;
......@@ -964,6 +991,7 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
SiMustAnyLock(sb);
sbinfo = au_sbi(sb);
AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
if (!(sb_flags & SB_RDONLY)) {
if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
......@@ -1017,13 +1045,13 @@ int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
continue;
hdir = au_hi(dir, bindex);
inode_lock_nested(hdir->hi_inode, AuLsc_I_PARENT);
au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT);
if (wbr)
wbr_wh_write_lock(wbr);
err = au_wh_init(br, sb);
if (wbr)
wbr_wh_write_unlock(wbr);
inode_unlock(hdir->hi_inode);
au_hn_inode_unlock(hdir);
if (!err && do_free) {
au_kfree_rcu(wbr);
......@@ -1038,10 +1066,12 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
{
int err;
unsigned int tmp;
aufs_bindex_t bbot;
aufs_bindex_t bindex, bbot;
struct au_opt *opt;
struct au_opt_xino *opt_xino, xino;
struct au_sbinfo *sbinfo;
struct au_branch *br;
struct inode *dir;
SiMustWriteLock(sb);
......@@ -1055,10 +1085,11 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
else if (unlikely(err < 0))
goto out;
/* disable xino temporary */
/* disable xino and udba temporary */
sbinfo = au_sbi(sb);
tmp = sbinfo->si_mntflags;
au_opt_clr(sbinfo->si_mntflags, XINO);
au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
opt = opts->opt;
while (err >= 0 && opt->type != Opt_tail)
......@@ -1100,7 +1131,23 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
goto out;
}
/* restore udba */
tmp &= AuOptMask_UDBA;
sbinfo->si_mntflags &= ~AuOptMask_UDBA;
sbinfo->si_mntflags |= tmp;
bbot = au_sbbot(sb);
for (bindex = 0; bindex <= bbot; bindex++) {
br = au_sbr(sb, bindex);
err = au_hnotify_reset_br(tmp, br, br->br_perm);
if (unlikely(err))
AuIOErr("hnotify failed on br %d, %d, ignored\n",
bindex, err);
/* go on even if err */
}
if (au_opt_test(tmp, UDBA_HNOTIFY)) {
dir = d_inode(sb->s_root);
au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
}
out:
return err;
......
......@@ -120,6 +120,7 @@ struct au_opt {
struct au_opt_xino xino;
struct au_opt_xino_itrunc xino_itrunc;
struct au_opt_add add;
int udba;
struct au_opt_wbr_create wbr_create;
int wbr_copyup;
/* add more later */
......@@ -139,6 +140,7 @@ struct au_opts {
struct au_opt *opt;
int max_opt;
unsigned int given_udba;
unsigned int flags;
unsigned long sb_flags;
};
......
......@@ -496,7 +496,7 @@ static void reinit_br_wh(void *arg)
h_root = au_h_dptr(a->sb->s_root, bindex);
AuDebugOn(h_root != au_br_dentry(a->br));
inode_lock_nested(hdir->hi_inode, AuLsc_I_PARENT);
au_hn_inode_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);
......@@ -520,7 +520,7 @@ static void reinit_br_wh(void *arg)
if (!err)
err = au_wh_init(a->br, a->sb);
wbr_wh_write_unlock(wbr);
inode_unlock(hdir->hi_inode);
au_hn_inode_unlock(hdir);
di_read_unlock(a->sb->s_root, AuLock_IR);
out:
......
......@@ -258,7 +258,15 @@ static void au_wkq_comp_free(struct completion *comp __maybe_unused)
static void au_wkq_run(struct au_wkinfo *wkinfo)
{
au_dbg_verify_kthread();
if (au_ftest_wkq(wkinfo->flags, NEST)) {
if (au_wkq_test()) {
AuWarn1("wkq from wkq, unless silly-rename on NFS,"
" due to a dead dir by UDBA,"
" or async xino write?\n");
AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT));
}
} else
au_dbg_verify_kthread();
if (au_ftest_wkq(wkinfo->flags, WAIT)) {
INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func);
......
......@@ -124,7 +124,7 @@ static void au_xino_lock_dir(struct super_block *sb, struct path *xipath,
if (bindex >= 0) {
/* rw branch root */
ldir->hdir = au_hi(d_inode(sb->s_root), bindex);
inode_lock_nested(ldir->hdir->hi_inode, AuLsc_I_PARENT);
au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT);
} else {
/* other */
ldir->parent = au_dget_parent_lock(xipath->dentry,
......@@ -136,7 +136,7 @@ static void au_xino_lock_dir(struct super_block *sb, struct path *xipath,
static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
{
if (ldir->hdir)
inode_unlock(ldir->hdir->hi_inode);
au_hn_inode_unlock(ldir->hdir);
else {
inode_unlock(ldir->dir);
dput(ldir->parent);
......
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