From 0200894d11551a8abcff7872c2260d0801951f67 Mon Sep 17 00:00:00 2001 From: Al Viro <viro@zeniv.linux.org.uk> Date: Wed, 11 Oct 2017 13:48:55 -0400 Subject: new helper: destroy_unused_super() Used for disposal of super_block instances that had never been reachable via any shared data structures. No need for RCU delay in there, everything can be called directly. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/super.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'fs/super.c') diff --git a/fs/super.c b/fs/super.c index 166c4ee0d0ed..01b7e3fd09e8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -171,6 +171,21 @@ static void destroy_super(struct super_block *s) call_rcu(&s->rcu, destroy_super_rcu); } +/* Free a superblock that has never been seen by anyone */ +static void destroy_unused_super(struct super_block *s) +{ + if (!s) + return; + up_write(&s->s_umount); + list_lru_destroy(&s->s_dentry_lru); + list_lru_destroy(&s->s_inode_lru); + security_sb_free(s); + put_user_ns(s->s_user_ns); + kfree(s->s_subtype); + /* no delays needed */ + destroy_super_work(&s->destroy_work); +} + /** * alloc_super - create new superblock * @type: filesystem type superblock should belong to @@ -256,7 +271,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, return s; fail: - destroy_super(s); + destroy_unused_super(s); return NULL; } @@ -484,19 +499,12 @@ retry: continue; if (user_ns != old->s_user_ns) { spin_unlock(&sb_lock); - if (s) { - up_write(&s->s_umount); - destroy_super(s); - } + destroy_unused_super(s); return ERR_PTR(-EBUSY); } if (!grab_super(old)) goto retry; - if (s) { - up_write(&s->s_umount); - destroy_super(s); - s = NULL; - } + destroy_unused_super(s); return old; } } @@ -511,8 +519,7 @@ retry: err = set(s, data); if (err) { spin_unlock(&sb_lock); - up_write(&s->s_umount); - destroy_super(s); + destroy_unused_super(s); return ERR_PTR(err); } s->s_type = type; -- cgit v1.2.3 From c645b9309839be3f1543255db2abfe120f9d4f26 Mon Sep 17 00:00:00 2001 From: Al Viro <viro@zeniv.linux.org.uk> Date: Wed, 11 Oct 2017 13:48:55 -0400 Subject: fold destroy_super() into __put_super() There's only one caller of destroy_super() left now. Fold it there, and replace those list_lru_destroy() calls with checks that they had already been done (as they should have, when we were dropping the last active reference). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/super.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'fs/super.c') diff --git a/fs/super.c b/fs/super.c index 01b7e3fd09e8..8ca15415351a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -154,23 +154,6 @@ static void destroy_super_rcu(struct rcu_head *head) schedule_work(&s->destroy_work); } -/** - * destroy_super - frees a superblock - * @s: superblock to free - * - * Frees a superblock. - */ -static void destroy_super(struct super_block *s) -{ - list_lru_destroy(&s->s_dentry_lru); - list_lru_destroy(&s->s_inode_lru); - security_sb_free(s); - WARN_ON(!list_empty(&s->s_mounts)); - put_user_ns(s->s_user_ns); - kfree(s->s_subtype); - call_rcu(&s->rcu, destroy_super_rcu); -} - /* Free a superblock that has never been seen by anyone */ static void destroy_unused_super(struct super_block *s) { @@ -280,11 +263,17 @@ fail: /* * Drop a superblock's refcount. The caller must hold sb_lock. */ -static void __put_super(struct super_block *sb) +static void __put_super(struct super_block *s) { - if (!--sb->s_count) { - list_del_init(&sb->s_list); - destroy_super(sb); + if (!--s->s_count) { + list_del_init(&s->s_list); + WARN_ON(s->s_dentry_lru.node); + WARN_ON(s->s_inode_lru.node); + WARN_ON(!list_empty(&s->s_mounts)); + security_sb_free(s); + put_user_ns(s->s_user_ns); + kfree(s->s_subtype); + call_rcu(&s->rcu, destroy_super_rcu); } } -- cgit v1.2.3