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