diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index c7cb8a526c05..2b8aa15fd6df 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1361,6 +1361,36 @@ enum umount_tree_flags { | |||
1361 | UMOUNT_PROPAGATE = 2, | 1361 | UMOUNT_PROPAGATE = 2, |
1362 | UMOUNT_CONNECTED = 4, | 1362 | UMOUNT_CONNECTED = 4, |
1363 | }; | 1363 | }; |
1364 | |||
1365 | static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how) | ||
1366 | { | ||
1367 | /* Leaving mounts connected is only valid for lazy umounts */ | ||
1368 | if (how & UMOUNT_SYNC) | ||
1369 | return true; | ||
1370 | |||
1371 | /* A mount without a parent has nothing to be connected to */ | ||
1372 | if (!mnt_has_parent(mnt)) | ||
1373 | return true; | ||
1374 | |||
1375 | /* Because the reference counting rules change when mounts are | ||
1376 | * unmounted and connected, umounted mounts may not be | ||
1377 | * connected to mounted mounts. | ||
1378 | */ | ||
1379 | if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) | ||
1380 | return true; | ||
1381 | |||
1382 | /* Has it been requested that the mount remain connected? */ | ||
1383 | if (how & UMOUNT_CONNECTED) | ||
1384 | return false; | ||
1385 | |||
1386 | /* Is the mount locked such that it needs to remain connected? */ | ||
1387 | if (IS_MNT_LOCKED(mnt)) | ||
1388 | return false; | ||
1389 | |||
1390 | /* By default disconnect the mount */ | ||
1391 | return true; | ||
1392 | } | ||
1393 | |||
1364 | /* | 1394 | /* |
1365 | * mount_lock must be held | 1395 | * mount_lock must be held |
1366 | * namespace_sem must be held for write | 1396 | * namespace_sem must be held for write |
@@ -1398,10 +1428,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) | |||
1398 | if (how & UMOUNT_SYNC) | 1428 | if (how & UMOUNT_SYNC) |
1399 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1429 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
1400 | 1430 | ||
1401 | disconnect = !(((how & UMOUNT_CONNECTED) && | 1431 | disconnect = disconnect_mount(p, how); |
1402 | mnt_has_parent(p) && | ||
1403 | (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) || | ||
1404 | IS_MNT_LOCKED_AND_LAZY(p)); | ||
1405 | 1432 | ||
1406 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, | 1433 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, |
1407 | disconnect ? &unmounted : NULL); | 1434 | disconnect ? &unmounted : NULL); |
@@ -1538,11 +1565,8 @@ void __detach_mounts(struct dentry *dentry) | |||
1538 | while (!hlist_empty(&mp->m_list)) { | 1565 | while (!hlist_empty(&mp->m_list)) { |
1539 | mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); | 1566 | mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); |
1540 | if (mnt->mnt.mnt_flags & MNT_UMOUNT) { | 1567 | if (mnt->mnt.mnt_flags & MNT_UMOUNT) { |
1541 | struct mount *p, *tmp; | 1568 | hlist_add_head(&mnt->mnt_umount.s_list, &unmounted); |
1542 | list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) { | 1569 | umount_mnt(mnt); |
1543 | hlist_add_head(&p->mnt_umount.s_list, &unmounted); | ||
1544 | umount_mnt(p); | ||
1545 | } | ||
1546 | } | 1570 | } |
1547 | else umount_tree(mnt, UMOUNT_CONNECTED); | 1571 | else umount_tree(mnt, UMOUNT_CONNECTED); |
1548 | } | 1572 | } |