|
@@ -659,12 +659,21 @@ int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
|
|
|
return 0;
|
|
|
mnt = real_mount(bastard);
|
|
|
mnt_add_count(mnt, 1);
|
|
|
+ smp_mb(); // see mntput_no_expire()
|
|
|
if (likely(!read_seqretry(&mount_lock, seq)))
|
|
|
return 0;
|
|
|
if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
|
|
|
mnt_add_count(mnt, -1);
|
|
|
return 1;
|
|
|
}
|
|
|
+ lock_mount_hash();
|
|
|
+ if (unlikely(bastard->mnt_flags & MNT_DOOMED)) {
|
|
|
+ mnt_add_count(mnt, -1);
|
|
|
+ unlock_mount_hash();
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ unlock_mount_hash();
|
|
|
+ /* caller will mntput() */
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -1195,12 +1204,27 @@ 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();
|
|
|
+ /*
|
|
|
+ * make sure that if __legitimize_mnt() has not seen us grab
|
|
|
+ * mount_lock, we'll see their refcount increment here.
|
|
|
+ */
|
|
|
+ smp_mb();
|
|
|
+ mnt_add_count(mnt, -1);
|
|
|
if (mnt_get_count(mnt)) {
|
|
|
rcu_read_unlock();
|
|
|
unlock_mount_hash();
|