|
@@ -1361,6 +1361,36 @@ enum umount_tree_flags {
|
|
|
UMOUNT_PROPAGATE = 2,
|
|
|
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
|
|
|
* namespace_sem must be held for write
|
|
@@ -1398,10 +1428,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
|
|
|
if (how & UMOUNT_SYNC)
|
|
|
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
|
|
|
|
|
|
- disconnect = !(((how & UMOUNT_CONNECTED) &&
|
|
|
- mnt_has_parent(p) &&
|
|
|
- (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) ||
|
|
|
- IS_MNT_LOCKED_AND_LAZY(p));
|
|
|
+ disconnect = disconnect_mount(p, how);
|
|
|
|
|
|
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
|
|
|
disconnect ? &unmounted : NULL);
|
|
@@ -1538,11 +1565,8 @@ void __detach_mounts(struct dentry *dentry)
|
|
|
while (!hlist_empty(&mp->m_list)) {
|
|
|
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
|
|
|
if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
|
|
|
- struct mount *p, *tmp;
|
|
|
- list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
|
|
|
- hlist_add_head(&p->mnt_umount.s_list, &unmounted);
|
|
|
- umount_mnt(p);
|
|
|
- }
|
|
|
+ hlist_add_head(&mnt->mnt_umount.s_list, &unmounted);
|
|
|
+ umount_mnt(mnt);
|
|
|
}
|
|
|
else umount_tree(mnt, UMOUNT_CONNECTED);
|
|
|
}
|