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>
This commit is contained in:
Al Viro 2017-10-11 13:48:55 -04:00
parent 6aa211e8ce
commit 0200894d11

View File

@ -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;