diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c index f7fa74fbf0c6..c7d1e2fb815f 100644 --- a/fs/aufs/branch.c +++ b/fs/aufs/branch.c @@ -526,11 +526,10 @@ int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) * test if the branch is deletable or not. */ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, - unsigned int sigen) + unsigned int sigen, const unsigned int verbose) { int err, i, j, ndentry; aufs_bindex_t bstart, bend; - unsigned char verbose; struct au_dcsub_pages dpages; struct au_dpage *dpage; struct dentry *d; @@ -543,7 +542,6 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, if (unlikely(err)) goto out_dpages; - verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE); for (i = 0; !err && i < dpages.ndpage; i++) { dpage = dpages.dpages + i; ndentry = dpage->ndentry; @@ -584,15 +582,13 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, } static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, - unsigned int sigen) + unsigned int sigen, const unsigned int verbose) { int err; struct inode *i; aufs_bindex_t bstart, bend; - unsigned char verbose; err = 0; - verbose = !!au_opt_test(au_mntflags(sb), VERBOSE); list_for_each_entry(i, &sb->s_inodes, i_sb_list) { AuDebugOn(!atomic_read(&i->i_count)); if (!list_empty(&i->i_dentry)) @@ -628,7 +624,8 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, return err; } -static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) +static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, + const unsigned int verbose) { int err; unsigned int sigen; @@ -637,9 +634,9 @@ static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) DiMustNoWaiters(root); IiMustNoWaiters(root->d_inode); di_write_unlock(root); - err = test_dentry_busy(root, bindex, sigen); + err = test_dentry_busy(root, bindex, sigen, verbose); if (!err) - err = test_inode_busy(root->d_sb, bindex, sigen); + err = test_inode_busy(root->d_sb, bindex, sigen, verbose); di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ return err; @@ -776,7 +773,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) } } - err = test_children_busy(sb->s_root, bindex); + err = test_children_busy(sb->s_root, bindex, verbose); if (unlikely(err)) { if (do_wh) goto out_wh; diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h index b4a8c2eaba3c..9e7747600217 100644 --- a/fs/aufs/branch.h +++ b/fs/aufs/branch.h @@ -157,8 +157,7 @@ ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, struct file *au_xino_create2(struct file *base_file, struct file *copy_src); struct file *au_xino_create(struct super_block *sb, char *fname, int silent); ino_t au_xino_new_ino(struct super_block *sb); -int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, - ino_t ino); +void au_xino_delete_inode(struct inode *inode, const int unlinked); int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ino_t ino); int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, diff --git a/fs/aufs/export.c b/fs/aufs/export.c index ac177a1978b5..fe6c227053ab 100644 --- a/fs/aufs/export.c +++ b/fs/aufs/export.c @@ -90,41 +90,28 @@ static int au_test_anon(struct dentry *dentry) /* ---------------------------------------------------------------------- */ /* inode generation external table */ -int au_xigen_inc(struct inode *inode) +void au_xigen_inc(struct inode *inode) { - int err; loff_t pos; ssize_t sz; __u32 igen; struct super_block *sb; struct au_sbinfo *sbinfo; - err = 0; sb = inode->i_sb; - sbinfo = au_sbi(sb); - /* - * temporary workaround for escaping from SiMustAnyLock() in - * au_mntflags(), since this function is called from au_iinfo_fin(). - */ - if (unlikely(!au_opt_test(sbinfo->si_mntflags, XINO))) - goto out; + AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); + sbinfo = au_sbi(sb); pos = inode->i_ino; pos *= sizeof(igen); igen = inode->i_generation + 1; sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, sizeof(igen), &pos); if (sz == sizeof(igen)) - goto out; /* success */ + return; /* success */ - err = sz; - if (unlikely(sz >= 0)) { - err = -EIO; + if (unlikely(sz >= 0)) AuIOErr("xigen error (%zd)\n", sz); - } - - out: - return err; } int au_xigen_new(struct inode *inode) diff --git a/fs/aufs/file.c b/fs/aufs/file.c index 8e7b5f061fbf..45bdca7bae6f 100644 --- a/fs/aufs/file.c +++ b/fs/aufs/file.c @@ -318,12 +318,12 @@ int au_do_flush(struct file *file, fl_owner_t id, inode = dentry->d_inode; si_noflush_read_lock(sb); fi_read_lock(file); - di_read_lock_child(dentry, AuLock_IW); + ii_read_lock_child(inode); err = flush(file, id); au_cpup_attr_timesizes(inode); - di_read_unlock(dentry, AuLock_IW); + ii_read_unlock(inode); fi_read_unlock(file); si_read_unlock(sb); return err; diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c index eaab5571fd7c..1c8f6630e44b 100644 --- a/fs/aufs/iinfo.c +++ b/fs/aufs/iinfo.c @@ -211,67 +211,38 @@ int au_ii_realloc(struct au_iinfo *iinfo, int nbr) return err; } -static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode, - ino_t ino) -{ - int err; - aufs_bindex_t bindex; - unsigned char locked; - - err = 0; - locked = !!si_noflush_read_trylock(sb); - bindex = au_br_index(sb, hinode->hi_id); - if (bindex >= 0) - err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino); - /* error action? */ - if (locked) - si_read_unlock(sb); - return err; -} - void au_iinfo_fin(struct inode *inode) { - ino_t ino; - aufs_bindex_t bend; - unsigned char unlinked = !inode->i_nlink; struct au_iinfo *iinfo; struct au_hinode *hi; struct super_block *sb; - - if (unlinked) { - int err = au_xigen_inc(inode); - if (unlikely(err)) - AuWarn1("failed resetting i_generation, %d\n", err); - } + aufs_bindex_t bindex, bend; + unsigned char locked; iinfo = au_ii(inode); /* bad_inode case */ if (!iinfo) return; + sb = inode->i_sb; + locked = !!si_noflush_read_trylock(sb); + au_xino_delete_inode(inode, !inode->i_nlink); + if (locked) + si_read_unlock(sb); + if (iinfo->ii_vdir) au_vdir_free(iinfo->ii_vdir); - if (iinfo->ii_bstart >= 0) { - sb = inode->i_sb; - ino = 0; - if (unlinked) - ino = inode->i_ino; - hi = iinfo->ii_hinode + iinfo->ii_bstart; + bindex = iinfo->ii_bstart; + if (bindex >= 0) { + hi = iinfo->ii_hinode + bindex; bend = iinfo->ii_bend; - while (iinfo->ii_bstart++ <= bend) { - if (hi->hi_inode) { - if (unlinked || !hi->hi_inode->i_nlink) { - au_iinfo_write0(sb, hi, ino); - /* ignore this error */ - ino = 0; - } + while (bindex++ <= bend) { + if (hi->hi_inode) au_hiput(hi); - } hi++; } } - kfree(iinfo->ii_hinode); AuRwDestroy(&iinfo->ii_rwsem); } diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c index 5fceec75814b..646cd39714c4 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -47,9 +47,14 @@ int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, /* true if a kernel thread named 'loop[0-9].*' accesses a file */ int au_test_loopback_kthread(void) { - const char c = current->comm[4]; + int ret; - return current->mm == NULL - && '0' <= c && c <= '9' - && strncmp(current->comm, "loop", 4) == 0; + ret = 0; + if (current->flags & PF_KTHREAD) { + const char c = current->comm[4]; + ret = ('0' <= c && c <= '9' + && !strncmp(current->comm, "loop", 4)); + } + + return ret; } diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c index a5a9becdadf1..c988bcdfd223 100644 --- a/fs/aufs/plink.c +++ b/fs/aufs/plink.c @@ -421,7 +421,6 @@ long au_plink_ioctl(struct file *file, unsigned int cmd) { long err; struct super_block *sb; - struct au_sbinfo *sbinfo; err = -EACCES; if (!capable(CAP_SYS_ADMIN)) @@ -429,7 +428,6 @@ long au_plink_ioctl(struct file *file, unsigned int cmd) err = 0; sb = file->f_dentry->d_sb; - sbinfo = au_sbi(sb); switch (cmd) { case AUFS_CTL_PLINK_MAINT: /* @@ -440,7 +438,7 @@ long au_plink_ioctl(struct file *file, unsigned int cmd) break; case AUFS_CTL_PLINK_CLEAN: aufs_write_lock(sb->s_root); - if (au_opt_test(sbinfo->si_mntflags, PLINK)) + if (au_opt_test(au_mntflags(sb), PLINK)) au_plink_put(sb); aufs_write_unlock(sb->s_root); break; diff --git a/fs/aufs/super.c b/fs/aufs/super.c index 6a6899b32ac9..5c1c823b54d5 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c @@ -686,6 +686,7 @@ static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) static const struct super_operations aufs_sop = { .alloc_inode = aufs_alloc_inode, .destroy_inode = aufs_destroy_inode, + /* always deleting, no clearing */ .drop_inode = generic_delete_inode, .show_options = aufs_show_options, .statfs = aufs_statfs, diff --git a/fs/aufs/super.h b/fs/aufs/super.h index cd6fdc4bc15c..9415a106e79c 100644 --- a/fs/aufs/super.h +++ b/fs/aufs/super.h @@ -231,10 +231,11 @@ void au_export_init(struct super_block *sb); static inline int au_test_nfsd(struct task_struct *tsk) { - return !tsk->mm && !strcmp(tsk->comm, "nfsd"); + return (current->flags & PF_KTHREAD) + && !strcmp(tsk->comm, "nfsd"); } -int au_xigen_inc(struct inode *inode); +void au_xigen_inc(struct inode *inode); int au_xigen_new(struct inode *inode); int au_xigen_set(struct super_block *sb, struct file *base); void au_xigen_clr(struct super_block *sb); @@ -248,7 +249,7 @@ static inline int au_busy_or_stale(void) #else AuStubVoid(au_export_init, struct super_block *sb) AuStubInt0(au_test_nfsd, struct task_struct *tsk) -AuStubInt0(au_xigen_inc, struct inode *inode) +AuStubVoid(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) diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h index 3fe36b31d148..143d4c3ad393 100644 --- a/fs/aufs/wkq.h +++ b/fs/aufs/wkq.h @@ -63,7 +63,7 @@ void au_wkq_fin(void); static inline int au_test_wkq(struct task_struct *tsk) { - return !tsk->mm + return (current->flags & PF_KTHREAD) && !strncmp(tsk->comm, AUFS_WKQ_NAME "/", sizeof(AUFS_WKQ_NAME)); } diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c index 51f17c7f9ae9..509dea613fad 100644 --- a/fs/aufs/xino.c +++ b/fs/aufs/xino.c @@ -487,33 +487,83 @@ static int xib_pindex(struct super_block *sb, unsigned long pindex) /* ---------------------------------------------------------------------- */ -int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, - ino_t ino) +static void au_xib_clear_bit(struct inode *inode) { int err, bit; unsigned long pindex; + struct super_block *sb; struct au_sbinfo *sbinfo; - if (!au_opt_test(au_mntflags(sb), XINO)) - return 0; + AuDebugOn(inode->i_nlink); - err = 0; - if (ino) { - sbinfo = au_sbi(sb); - xib_calc_bit(ino, &pindex, &bit); - AuDebugOn(page_bits <= bit); - mutex_lock(&sbinfo->si_xib_mtx); - err = xib_pindex(sb, pindex); - if (!err) { - clear_bit(bit, sbinfo->si_xib_buf); - sbinfo->si_xib_next_bit = bit; - } - mutex_unlock(&sbinfo->si_xib_mtx); + sb = inode->i_sb; + xib_calc_bit(inode->i_ino, &pindex, &bit); + AuDebugOn(page_bits <= bit); + sbinfo = au_sbi(sb); + mutex_lock(&sbinfo->si_xib_mtx); + err = xib_pindex(sb, pindex); + if (!err) { + clear_bit(bit, sbinfo->si_xib_buf); + sbinfo->si_xib_next_bit = bit; } + mutex_unlock(&sbinfo->si_xib_mtx); +} - if (!err) - err = au_xino_write(sb, bindex, h_ino, 0); - return err; +/* for s_op->delete_inode() */ +void au_xino_delete_inode(struct inode *inode, const int unlinked) +{ + int err; + unsigned int mnt_flags; + aufs_bindex_t bindex, bend, bi; + unsigned char try_trunc; + struct au_iinfo *iinfo; + struct super_block *sb; + struct au_hinode *hi; + struct inode *h_inode; + struct au_branch *br; + au_writef_t xwrite; + + sb = inode->i_sb; + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO) + || inode->i_ino == AUFS_ROOT_INO) + return; + + if (unlinked) { + au_xigen_inc(inode); + au_xib_clear_bit(inode); + } + + iinfo = au_ii(inode); + if (!iinfo) + return; + + bindex = iinfo->ii_bstart; + if (bindex < 0) + return; + + xwrite = au_sbi(sb)->si_xwrite; + try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); + hi = iinfo->ii_hinode + bindex; + bend = iinfo->ii_bend; + for (; bindex <= bend; bindex++, hi++) { + h_inode = hi->hi_inode; + if (!h_inode + || (!unlinked && h_inode->i_nlink)) + continue; + + /* inode may not be revalidated */ + bi = au_br_index(sb, hi->hi_id); + if (bi < 0) + continue; + + br = au_sbr(sb, bi); + err = au_xino_do_write(xwrite, br->br_xino.xi_file, + h_inode->i_ino, /*ino*/0); + if (!err && try_trunc + && au_test_fs_trunc_xino(br->br_mnt->mnt_sb)) + xino_try_trunc(sb, br); + } } /* get an unused inode number from bitmap */