diff options
-rw-r--r-- | fs/namespace.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index fcf636e37c8e..1e4a979e8aa5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -969,12 +969,22 @@ static void mntput_no_expire(struct mount *mnt) { put_again: rcu_read_lock(); - mnt_add_count(mnt, -1); - if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ + if (likely(ACCESS_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(); |