mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
mnt: Clarify and correct the disconnect logic in umount_tree
commitf2d0a123bcupstream. rmdir mntpoint will result in an infinite loop when there is a mount locked on the mountpoint in another mount namespace. This is because the logic to test to see if a mount should be disconnected in umount_tree is buggy. Move the logic to decide if a mount should remain connected to it's mountpoint into it's own function disconnect_mount so that clarity of expression instead of terseness of expression becomes a virtue. When the conditions where it is invalid to leave a mount connected are first ruled out, the logic for deciding if a mount should be disconnected becomes much clearer and simpler. Fixes:e0c9c0afd2mnt: Update detach_mounts to leave mounts connected Fixes:ce07d891a0mnt: Honor MNT_LOCKED when detaching mounts Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
59366187ef
commit
4647b34f1a
@@ -1350,6 +1350,36 @@ enum umount_tree_flags {
|
|||||||
UMOUNT_PROPAGATE = 2,
|
UMOUNT_PROPAGATE = 2,
|
||||||
UMOUNT_CONNECTED = 4,
|
UMOUNT_CONNECTED = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how)
|
||||||
|
{
|
||||||
|
/* Leaving mounts connected is only valid for lazy umounts */
|
||||||
|
if (how & UMOUNT_SYNC)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* A mount without a parent has nothing to be connected to */
|
||||||
|
if (!mnt_has_parent(mnt))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Because the reference counting rules change when mounts are
|
||||||
|
* unmounted and connected, umounted mounts may not be
|
||||||
|
* connected to mounted mounts.
|
||||||
|
*/
|
||||||
|
if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Has it been requested that the mount remain connected? */
|
||||||
|
if (how & UMOUNT_CONNECTED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Is the mount locked such that it needs to remain connected? */
|
||||||
|
if (IS_MNT_LOCKED(mnt))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* By default disconnect the mount */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mount_lock must be held
|
* mount_lock must be held
|
||||||
* namespace_sem must be held for write
|
* namespace_sem must be held for write
|
||||||
@@ -1387,10 +1417,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
|
|||||||
if (how & UMOUNT_SYNC)
|
if (how & UMOUNT_SYNC)
|
||||||
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
|
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
|
||||||
|
|
||||||
disconnect = !(((how & UMOUNT_CONNECTED) &&
|
disconnect = disconnect_mount(p, how);
|
||||||
mnt_has_parent(p) &&
|
|
||||||
(p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) ||
|
|
||||||
IS_MNT_LOCKED_AND_LAZY(p));
|
|
||||||
|
|
||||||
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
|
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
|
||||||
disconnect ? &unmounted : NULL);
|
disconnect ? &unmounted : NULL);
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
|
#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
|
||||||
#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
|
#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
|
||||||
#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
|
#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
|
||||||
#define IS_MNT_LOCKED_AND_LAZY(m) \
|
|
||||||
(((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED)
|
|
||||||
|
|
||||||
#define CL_EXPIRE 0x01
|
#define CL_EXPIRE 0x01
|
||||||
#define CL_SLAVE 0x02
|
#define CL_SLAVE 0x02
|
||||||
|
|||||||
Reference in New Issue
Block a user