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