VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   55 Tags
author: Al Viro <viro@zeniv.linux.org.uk> 2018-08-09 17:21:17 -0400 committer: Al Viro <viro@zeniv.linux.org.uk> 2018-08-09 17:21:17 -0400 commit: 9ea0a46ca2c318fcc449c1e6b62a7230a17888f1 parent: 90bad5e05bcdb0308cfa3d3a60f5c0b9c8e2efb3
Commit Summary:
fix mntput/mntput race
Diffstat:
1 file changed, 12 insertions, 2 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 8ddd14806799..d46a951bd541 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1195,12 +1195,22 @@ static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
 static void mntput_no_expire(struct mount *mnt)
 {
 	rcu_read_lock();
-	mnt_add_count(mnt, -1);
-	if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */
+	if (likely(READ_ONCE(mnt->mnt_ns))) {
+		/*
+		 * Since we don't do lock_mount_hash() here,
+		 * ->mnt_ns can change under us.  However, if it's
+		 * non-NULL, then there's a reference that won't
+		 * be dropped until after an RCU delay done after
+		 * turning ->mnt_ns NULL.  So if we observe it
+		 * non-NULL under rcu_read_lock(), the reference
+		 * we are dropping is not the final one.
+		 */
+		mnt_add_count(mnt, -1);
 		rcu_read_unlock();
 		return;
 	}
 	lock_mount_hash();
+	mnt_add_count(mnt, -1);
 	if (mnt_get_count(mnt)) {
 		rcu_read_unlock();
 		unlock_mount_hash();