Skip to content

Commit c93ff74

Browse files
author
Al Viro
committed
do_umount(): simplify the "is it still mounted" checks
Calls of do_umount() are always preceded by can_umount(), where we'd done a racy check for mount belonging to our namespace; if it wasn't, can_unmount() would've failed with -EINVAL and we wouldn't have reached do_umount() at all. That check needs to be redone once we have acquired namespace_sem and in do_umount() we do that. However, that's done in a very odd way; we check that mount is still in rbtree of _some_ namespace or its mnt_list is not empty. It is equivalent to check_mnt(mnt) - we know that earlier mnt was mounted in our namespace; if it has stayed there, it's going to remain in rbtree of our namespace. OTOH, if it ever had been removed from out namespace, it would be removed from rbtree and it never would've re-added to a namespace afterwards. As for ->mnt_list, for something that had been mounted in a namespace we'll never observe non-empty ->mnt_list while holding namespace_sem - it does temporarily become non-empty during umount_tree(), but that doesn't outlast the call of umount_tree(), let alone dropping namespace_sem. Things get much easier to follow if we replace that with (equivalent) check_mnt(mnt) there. What's more, currently we treat a failure of that test as "quietly do nothing"; we might as well pretend that we'd lost the race and fail on that the same way can_umount() would have. Reviewed-by: Christian Brauner <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 49acacd commit c93ff74

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

fs/namespace.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,8 +1983,11 @@ static int do_umount(struct mount *mnt, int flags)
19831983
namespace_lock();
19841984
lock_mount_hash();
19851985

1986-
/* Recheck MNT_LOCKED with the locks held */
1986+
/* Repeat the earlier racy checks, now that we are holding the locks */
19871987
retval = -EINVAL;
1988+
if (!check_mnt(mnt))
1989+
goto out;
1990+
19881991
if (mnt->mnt.mnt_flags & MNT_LOCKED)
19891992
goto out;
19901993

@@ -1993,16 +1996,14 @@ static int do_umount(struct mount *mnt, int flags)
19931996

19941997
event++;
19951998
if (flags & MNT_DETACH) {
1996-
if (mnt_ns_attached(mnt) || !list_empty(&mnt->mnt_list))
1997-
umount_tree(mnt, UMOUNT_PROPAGATE);
1999+
umount_tree(mnt, UMOUNT_PROPAGATE);
19982000
retval = 0;
19992001
} else {
20002002
smp_mb(); // paired with __legitimize_mnt()
20012003
shrink_submounts(mnt);
20022004
retval = -EBUSY;
20032005
if (!propagate_mount_busy(mnt, 2)) {
2004-
if (mnt_ns_attached(mnt) || !list_empty(&mnt->mnt_list))
2005-
umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC);
2006+
umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC);
20062007
retval = 0;
20072008
}
20082009
}

0 commit comments

Comments
 (0)