diff options
| -rw-r--r-- | fs/fs_pin.c | 4 | ||||
| -rw-r--r-- | fs/namespace.c | 142 | ||||
| -rw-r--r-- | fs/pnode.c | 60 | ||||
| -rw-r--r-- | fs/pnode.h | 7 | ||||
| -rw-r--r-- | include/linux/fs_pin.h | 2 | ||||
| -rw-r--r-- | include/linux/mount.h | 1 |
6 files changed, 159 insertions, 57 deletions
diff --git a/fs/fs_pin.c b/fs/fs_pin.c index b06c98796afb..611b5408f6ec 100644 --- a/fs/fs_pin.c +++ b/fs/fs_pin.c | |||
| @@ -9,8 +9,8 @@ static DEFINE_SPINLOCK(pin_lock); | |||
| 9 | void pin_remove(struct fs_pin *pin) | 9 | void pin_remove(struct fs_pin *pin) |
| 10 | { | 10 | { |
| 11 | spin_lock(&pin_lock); | 11 | spin_lock(&pin_lock); |
| 12 | hlist_del(&pin->m_list); | 12 | hlist_del_init(&pin->m_list); |
| 13 | hlist_del(&pin->s_list); | 13 | hlist_del_init(&pin->s_list); |
| 14 | spin_unlock(&pin_lock); | 14 | spin_unlock(&pin_lock); |
| 15 | spin_lock_irq(&pin->wait.lock); | 15 | spin_lock_irq(&pin->wait.lock); |
| 16 | pin->done = 1; | 16 | pin->done = 1; |
diff --git a/fs/namespace.c b/fs/namespace.c index 82ef1405260e..1f4f9dac6e5a 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -632,14 +632,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | |||
| 632 | */ | 632 | */ |
| 633 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) | 633 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) |
| 634 | { | 634 | { |
| 635 | struct mount *p, *res; | 635 | struct mount *p, *res = NULL; |
| 636 | res = p = __lookup_mnt(mnt, dentry); | 636 | p = __lookup_mnt(mnt, dentry); |
| 637 | if (!p) | 637 | if (!p) |
| 638 | goto out; | 638 | goto out; |
| 639 | if (!(p->mnt.mnt_flags & MNT_UMOUNT)) | ||
| 640 | res = p; | ||
| 639 | hlist_for_each_entry_continue(p, mnt_hash) { | 641 | hlist_for_each_entry_continue(p, mnt_hash) { |
| 640 | if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) | 642 | if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) |
| 641 | break; | 643 | break; |
| 642 | res = p; | 644 | if (!(p->mnt.mnt_flags & MNT_UMOUNT)) |
| 645 | res = p; | ||
| 643 | } | 646 | } |
| 644 | out: | 647 | out: |
| 645 | return res; | 648 | return res; |
| @@ -795,10 +798,8 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) | |||
| 795 | /* | 798 | /* |
| 796 | * vfsmount lock must be held for write | 799 | * vfsmount lock must be held for write |
| 797 | */ | 800 | */ |
| 798 | static void detach_mnt(struct mount *mnt, struct path *old_path) | 801 | static void unhash_mnt(struct mount *mnt) |
| 799 | { | 802 | { |
| 800 | old_path->dentry = mnt->mnt_mountpoint; | ||
| 801 | old_path->mnt = &mnt->mnt_parent->mnt; | ||
| 802 | mnt->mnt_parent = mnt; | 803 | mnt->mnt_parent = mnt; |
| 803 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; | 804 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
| 804 | list_del_init(&mnt->mnt_child); | 805 | list_del_init(&mnt->mnt_child); |
| @@ -811,6 +812,26 @@ static void detach_mnt(struct mount *mnt, struct path *old_path) | |||
| 811 | /* | 812 | /* |
| 812 | * vfsmount lock must be held for write | 813 | * vfsmount lock must be held for write |
| 813 | */ | 814 | */ |
| 815 | static void detach_mnt(struct mount *mnt, struct path *old_path) | ||
| 816 | { | ||
| 817 | old_path->dentry = mnt->mnt_mountpoint; | ||
| 818 | old_path->mnt = &mnt->mnt_parent->mnt; | ||
| 819 | unhash_mnt(mnt); | ||
| 820 | } | ||
| 821 | |||
| 822 | /* | ||
| 823 | * vfsmount lock must be held for write | ||
| 824 | */ | ||
| 825 | static void umount_mnt(struct mount *mnt) | ||
| 826 | { | ||
| 827 | /* old mountpoint will be dropped when we can do that */ | ||
| 828 | mnt->mnt_ex_mountpoint = mnt->mnt_mountpoint; | ||
| 829 | unhash_mnt(mnt); | ||
| 830 | } | ||
| 831 | |||
| 832 | /* | ||
| 833 | * vfsmount lock must be held for write | ||
| 834 | */ | ||
| 814 | void mnt_set_mountpoint(struct mount *mnt, | 835 | void mnt_set_mountpoint(struct mount *mnt, |
| 815 | struct mountpoint *mp, | 836 | struct mountpoint *mp, |
| 816 | struct mount *child_mnt) | 837 | struct mount *child_mnt) |
| @@ -1078,6 +1099,13 @@ static void mntput_no_expire(struct mount *mnt) | |||
| 1078 | rcu_read_unlock(); | 1099 | rcu_read_unlock(); |
| 1079 | 1100 | ||
| 1080 | list_del(&mnt->mnt_instance); | 1101 | list_del(&mnt->mnt_instance); |
| 1102 | |||
| 1103 | if (unlikely(!list_empty(&mnt->mnt_mounts))) { | ||
| 1104 | struct mount *p, *tmp; | ||
| 1105 | list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) { | ||
| 1106 | umount_mnt(p); | ||
| 1107 | } | ||
| 1108 | } | ||
| 1081 | unlock_mount_hash(); | 1109 | unlock_mount_hash(); |
| 1082 | 1110 | ||
| 1083 | if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) { | 1111 | if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) { |
| @@ -1298,17 +1326,15 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ | |||
| 1298 | 1326 | ||
| 1299 | static void namespace_unlock(void) | 1327 | static void namespace_unlock(void) |
| 1300 | { | 1328 | { |
| 1301 | struct hlist_head head = unmounted; | 1329 | struct hlist_head head; |
| 1302 | 1330 | ||
| 1303 | if (likely(hlist_empty(&head))) { | 1331 | hlist_move_list(&unmounted, &head); |
| 1304 | up_write(&namespace_sem); | ||
| 1305 | return; | ||
| 1306 | } | ||
| 1307 | 1332 | ||
| 1308 | head.first->pprev = &head.first; | ||
| 1309 | INIT_HLIST_HEAD(&unmounted); | ||
| 1310 | up_write(&namespace_sem); | 1333 | up_write(&namespace_sem); |
| 1311 | 1334 | ||
| 1335 | if (likely(hlist_empty(&head))) | ||
| 1336 | return; | ||
| 1337 | |||
| 1312 | synchronize_rcu(); | 1338 | synchronize_rcu(); |
| 1313 | 1339 | ||
| 1314 | group_pin_kill(&head); | 1340 | group_pin_kill(&head); |
| @@ -1319,49 +1345,63 @@ static inline void namespace_lock(void) | |||
| 1319 | down_write(&namespace_sem); | 1345 | down_write(&namespace_sem); |
| 1320 | } | 1346 | } |
| 1321 | 1347 | ||
| 1348 | enum umount_tree_flags { | ||
| 1349 | UMOUNT_SYNC = 1, | ||
| 1350 | UMOUNT_PROPAGATE = 2, | ||
| 1351 | UMOUNT_CONNECTED = 4, | ||
| 1352 | }; | ||
| 1322 | /* | 1353 | /* |
| 1323 | * mount_lock must be held | 1354 | * mount_lock must be held |
| 1324 | * namespace_sem must be held for write | 1355 | * namespace_sem must be held for write |
| 1325 | * how = 0 => just this tree, don't propagate | ||
| 1326 | * how = 1 => propagate; we know that nobody else has reference to any victims | ||
| 1327 | * how = 2 => lazy umount | ||
| 1328 | */ | 1356 | */ |
| 1329 | void umount_tree(struct mount *mnt, int how) | 1357 | static void umount_tree(struct mount *mnt, enum umount_tree_flags how) |
| 1330 | { | 1358 | { |
| 1331 | HLIST_HEAD(tmp_list); | 1359 | LIST_HEAD(tmp_list); |
| 1332 | struct mount *p; | 1360 | struct mount *p; |
| 1333 | 1361 | ||
| 1362 | if (how & UMOUNT_PROPAGATE) | ||
| 1363 | propagate_mount_unlock(mnt); | ||
| 1364 | |||
| 1365 | /* Gather the mounts to umount */ | ||
| 1334 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 1366 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
| 1335 | hlist_del_init_rcu(&p->mnt_hash); | 1367 | p->mnt.mnt_flags |= MNT_UMOUNT; |
| 1336 | hlist_add_head(&p->mnt_hash, &tmp_list); | 1368 | list_move(&p->mnt_list, &tmp_list); |
| 1337 | } | 1369 | } |
| 1338 | 1370 | ||
| 1339 | hlist_for_each_entry(p, &tmp_list, mnt_hash) | 1371 | /* Hide the mounts from mnt_mounts */ |
| 1372 | list_for_each_entry(p, &tmp_list, mnt_list) { | ||
| 1340 | list_del_init(&p->mnt_child); | 1373 | list_del_init(&p->mnt_child); |
| 1374 | } | ||
| 1341 | 1375 | ||
| 1342 | if (how) | 1376 | /* Add propogated mounts to the tmp_list */ |
| 1377 | if (how & UMOUNT_PROPAGATE) | ||
| 1343 | propagate_umount(&tmp_list); | 1378 | propagate_umount(&tmp_list); |
| 1344 | 1379 | ||
| 1345 | while (!hlist_empty(&tmp_list)) { | 1380 | while (!list_empty(&tmp_list)) { |
| 1346 | p = hlist_entry(tmp_list.first, struct mount, mnt_hash); | 1381 | bool disconnect; |
| 1347 | hlist_del_init_rcu(&p->mnt_hash); | 1382 | p = list_first_entry(&tmp_list, struct mount, mnt_list); |
| 1348 | list_del_init(&p->mnt_expire); | 1383 | list_del_init(&p->mnt_expire); |
| 1349 | list_del_init(&p->mnt_list); | 1384 | list_del_init(&p->mnt_list); |
| 1350 | __touch_mnt_namespace(p->mnt_ns); | 1385 | __touch_mnt_namespace(p->mnt_ns); |
| 1351 | p->mnt_ns = NULL; | 1386 | p->mnt_ns = NULL; |
| 1352 | if (how < 2) | 1387 | if (how & UMOUNT_SYNC) |
| 1353 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1388 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
| 1354 | 1389 | ||
| 1355 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted); | 1390 | disconnect = !(((how & UMOUNT_CONNECTED) && |
| 1391 | mnt_has_parent(p) && | ||
| 1392 | (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) || | ||
| 1393 | IS_MNT_LOCKED_AND_LAZY(p)); | ||
| 1394 | |||
| 1395 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, | ||
| 1396 | disconnect ? &unmounted : NULL); | ||
| 1356 | if (mnt_has_parent(p)) { | 1397 | if (mnt_has_parent(p)) { |
| 1357 | hlist_del_init(&p->mnt_mp_list); | ||
| 1358 | put_mountpoint(p->mnt_mp); | ||
| 1359 | mnt_add_count(p->mnt_parent, -1); | 1398 | mnt_add_count(p->mnt_parent, -1); |
| 1360 | /* old mountpoint will be dropped when we can do that */ | 1399 | if (!disconnect) { |
| 1361 | p->mnt_ex_mountpoint = p->mnt_mountpoint; | 1400 | /* Don't forget about p */ |
| 1362 | p->mnt_mountpoint = p->mnt.mnt_root; | 1401 | list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts); |
| 1363 | p->mnt_parent = p; | 1402 | } else { |
| 1364 | p->mnt_mp = NULL; | 1403 | umount_mnt(p); |
| 1404 | } | ||
| 1365 | } | 1405 | } |
| 1366 | change_mnt_propagation(p, MS_PRIVATE); | 1406 | change_mnt_propagation(p, MS_PRIVATE); |
| 1367 | } | 1407 | } |
| @@ -1447,14 +1487,14 @@ static int do_umount(struct mount *mnt, int flags) | |||
| 1447 | 1487 | ||
| 1448 | if (flags & MNT_DETACH) { | 1488 | if (flags & MNT_DETACH) { |
| 1449 | if (!list_empty(&mnt->mnt_list)) | 1489 | if (!list_empty(&mnt->mnt_list)) |
| 1450 | umount_tree(mnt, 2); | 1490 | umount_tree(mnt, UMOUNT_PROPAGATE); |
| 1451 | retval = 0; | 1491 | retval = 0; |
| 1452 | } else { | 1492 | } else { |
| 1453 | shrink_submounts(mnt); | 1493 | shrink_submounts(mnt); |
| 1454 | retval = -EBUSY; | 1494 | retval = -EBUSY; |
| 1455 | if (!propagate_mount_busy(mnt, 2)) { | 1495 | if (!propagate_mount_busy(mnt, 2)) { |
| 1456 | if (!list_empty(&mnt->mnt_list)) | 1496 | if (!list_empty(&mnt->mnt_list)) |
| 1457 | umount_tree(mnt, 1); | 1497 | umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC); |
| 1458 | retval = 0; | 1498 | retval = 0; |
| 1459 | } | 1499 | } |
| 1460 | } | 1500 | } |
| @@ -1480,13 +1520,20 @@ void __detach_mounts(struct dentry *dentry) | |||
| 1480 | 1520 | ||
| 1481 | namespace_lock(); | 1521 | namespace_lock(); |
| 1482 | mp = lookup_mountpoint(dentry); | 1522 | mp = lookup_mountpoint(dentry); |
| 1483 | if (!mp) | 1523 | if (IS_ERR_OR_NULL(mp)) |
| 1484 | goto out_unlock; | 1524 | goto out_unlock; |
| 1485 | 1525 | ||
| 1486 | lock_mount_hash(); | 1526 | lock_mount_hash(); |
| 1487 | while (!hlist_empty(&mp->m_list)) { | 1527 | while (!hlist_empty(&mp->m_list)) { |
| 1488 | mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); | 1528 | mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); |
| 1489 | umount_tree(mnt, 2); | 1529 | if (mnt->mnt.mnt_flags & MNT_UMOUNT) { |
| 1530 | struct mount *p, *tmp; | ||
| 1531 | list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) { | ||
| 1532 | hlist_add_head(&p->mnt_umount.s_list, &unmounted); | ||
| 1533 | umount_mnt(p); | ||
| 1534 | } | ||
| 1535 | } | ||
| 1536 | else umount_tree(mnt, UMOUNT_CONNECTED); | ||
| 1490 | } | 1537 | } |
| 1491 | unlock_mount_hash(); | 1538 | unlock_mount_hash(); |
| 1492 | put_mountpoint(mp); | 1539 | put_mountpoint(mp); |
| @@ -1648,7 +1695,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
| 1648 | out: | 1695 | out: |
| 1649 | if (res) { | 1696 | if (res) { |
| 1650 | lock_mount_hash(); | 1697 | lock_mount_hash(); |
| 1651 | umount_tree(res, 0); | 1698 | umount_tree(res, UMOUNT_SYNC); |
| 1652 | unlock_mount_hash(); | 1699 | unlock_mount_hash(); |
| 1653 | } | 1700 | } |
| 1654 | return q; | 1701 | return q; |
| @@ -1660,8 +1707,11 @@ struct vfsmount *collect_mounts(struct path *path) | |||
| 1660 | { | 1707 | { |
| 1661 | struct mount *tree; | 1708 | struct mount *tree; |
| 1662 | namespace_lock(); | 1709 | namespace_lock(); |
| 1663 | tree = copy_tree(real_mount(path->mnt), path->dentry, | 1710 | if (!check_mnt(real_mount(path->mnt))) |
| 1664 | CL_COPY_ALL | CL_PRIVATE); | 1711 | tree = ERR_PTR(-EINVAL); |
| 1712 | else | ||
| 1713 | tree = copy_tree(real_mount(path->mnt), path->dentry, | ||
| 1714 | CL_COPY_ALL | CL_PRIVATE); | ||
| 1665 | namespace_unlock(); | 1715 | namespace_unlock(); |
| 1666 | if (IS_ERR(tree)) | 1716 | if (IS_ERR(tree)) |
| 1667 | return ERR_CAST(tree); | 1717 | return ERR_CAST(tree); |
| @@ -1672,7 +1722,7 @@ void drop_collected_mounts(struct vfsmount *mnt) | |||
| 1672 | { | 1722 | { |
| 1673 | namespace_lock(); | 1723 | namespace_lock(); |
| 1674 | lock_mount_hash(); | 1724 | lock_mount_hash(); |
| 1675 | umount_tree(real_mount(mnt), 0); | 1725 | umount_tree(real_mount(mnt), UMOUNT_SYNC); |
| 1676 | unlock_mount_hash(); | 1726 | unlock_mount_hash(); |
| 1677 | namespace_unlock(); | 1727 | namespace_unlock(); |
| 1678 | } | 1728 | } |
| @@ -1855,7 +1905,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
| 1855 | out_cleanup_ids: | 1905 | out_cleanup_ids: |
| 1856 | while (!hlist_empty(&tree_list)) { | 1906 | while (!hlist_empty(&tree_list)) { |
| 1857 | child = hlist_entry(tree_list.first, struct mount, mnt_hash); | 1907 | child = hlist_entry(tree_list.first, struct mount, mnt_hash); |
| 1858 | umount_tree(child, 0); | 1908 | umount_tree(child, UMOUNT_SYNC); |
| 1859 | } | 1909 | } |
| 1860 | unlock_mount_hash(); | 1910 | unlock_mount_hash(); |
| 1861 | cleanup_group_ids(source_mnt, NULL); | 1911 | cleanup_group_ids(source_mnt, NULL); |
| @@ -2035,7 +2085,7 @@ static int do_loopback(struct path *path, const char *old_name, | |||
| 2035 | err = graft_tree(mnt, parent, mp); | 2085 | err = graft_tree(mnt, parent, mp); |
| 2036 | if (err) { | 2086 | if (err) { |
| 2037 | lock_mount_hash(); | 2087 | lock_mount_hash(); |
| 2038 | umount_tree(mnt, 0); | 2088 | umount_tree(mnt, UMOUNT_SYNC); |
| 2039 | unlock_mount_hash(); | 2089 | unlock_mount_hash(); |
| 2040 | } | 2090 | } |
| 2041 | out2: | 2091 | out2: |
| @@ -2406,7 +2456,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 2406 | while (!list_empty(&graveyard)) { | 2456 | while (!list_empty(&graveyard)) { |
| 2407 | mnt = list_first_entry(&graveyard, struct mount, mnt_expire); | 2457 | mnt = list_first_entry(&graveyard, struct mount, mnt_expire); |
| 2408 | touch_mnt_namespace(mnt->mnt_ns); | 2458 | touch_mnt_namespace(mnt->mnt_ns); |
| 2409 | umount_tree(mnt, 1); | 2459 | umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC); |
| 2410 | } | 2460 | } |
| 2411 | unlock_mount_hash(); | 2461 | unlock_mount_hash(); |
| 2412 | namespace_unlock(); | 2462 | namespace_unlock(); |
| @@ -2477,7 +2527,7 @@ static void shrink_submounts(struct mount *mnt) | |||
| 2477 | m = list_first_entry(&graveyard, struct mount, | 2527 | m = list_first_entry(&graveyard, struct mount, |
| 2478 | mnt_expire); | 2528 | mnt_expire); |
| 2479 | touch_mnt_namespace(m->mnt_ns); | 2529 | touch_mnt_namespace(m->mnt_ns); |
| 2480 | umount_tree(m, 1); | 2530 | umount_tree(m, UMOUNT_PROPAGATE|UMOUNT_SYNC); |
| 2481 | } | 2531 | } |
| 2482 | } | 2532 | } |
| 2483 | } | 2533 | } |
diff --git a/fs/pnode.c b/fs/pnode.c index 260ac8f898a4..6367e1e435c6 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
| @@ -362,6 +362,46 @@ int propagate_mount_busy(struct mount *mnt, int refcnt) | |||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | /* | 364 | /* |
| 365 | * Clear MNT_LOCKED when it can be shown to be safe. | ||
| 366 | * | ||
| 367 | * mount_lock lock must be held for write | ||
| 368 | */ | ||
| 369 | void propagate_mount_unlock(struct mount *mnt) | ||
| 370 | { | ||
| 371 | struct mount *parent = mnt->mnt_parent; | ||
| 372 | struct mount *m, *child; | ||
| 373 | |||
| 374 | BUG_ON(parent == mnt); | ||
| 375 | |||
| 376 | for (m = propagation_next(parent, parent); m; | ||
| 377 | m = propagation_next(m, parent)) { | ||
| 378 | child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); | ||
| 379 | if (child) | ||
| 380 | child->mnt.mnt_flags &= ~MNT_LOCKED; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | /* | ||
| 385 | * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted. | ||
| 386 | */ | ||
| 387 | static void mark_umount_candidates(struct mount *mnt) | ||
| 388 | { | ||
| 389 | struct mount *parent = mnt->mnt_parent; | ||
| 390 | struct mount *m; | ||
| 391 | |||
| 392 | BUG_ON(parent == mnt); | ||
| 393 | |||
| 394 | for (m = propagation_next(parent, parent); m; | ||
| 395 | m = propagation_next(m, parent)) { | ||
| 396 | struct mount *child = __lookup_mnt_last(&m->mnt, | ||
| 397 | mnt->mnt_mountpoint); | ||
| 398 | if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) { | ||
| 399 | SET_MNT_MARK(child); | ||
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /* | ||
| 365 | * NOTE: unmounting 'mnt' naturally propagates to all other mounts its | 405 | * NOTE: unmounting 'mnt' naturally propagates to all other mounts its |
| 366 | * parent propagates to. | 406 | * parent propagates to. |
| 367 | */ | 407 | */ |
| @@ -378,13 +418,16 @@ static void __propagate_umount(struct mount *mnt) | |||
| 378 | struct mount *child = __lookup_mnt_last(&m->mnt, | 418 | struct mount *child = __lookup_mnt_last(&m->mnt, |
| 379 | mnt->mnt_mountpoint); | 419 | mnt->mnt_mountpoint); |
| 380 | /* | 420 | /* |
| 381 | * umount the child only if the child has no | 421 | * umount the child only if the child has no children |
| 382 | * other children | 422 | * and the child is marked safe to unmount. |
| 383 | */ | 423 | */ |
| 384 | if (child && list_empty(&child->mnt_mounts)) { | 424 | if (!child || !IS_MNT_MARKED(child)) |
| 425 | continue; | ||
| 426 | CLEAR_MNT_MARK(child); | ||
| 427 | if (list_empty(&child->mnt_mounts)) { | ||
| 385 | list_del_init(&child->mnt_child); | 428 | list_del_init(&child->mnt_child); |
| 386 | hlist_del_init_rcu(&child->mnt_hash); | 429 | child->mnt.mnt_flags |= MNT_UMOUNT; |
| 387 | hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash); | 430 | list_move_tail(&child->mnt_list, &mnt->mnt_list); |
| 388 | } | 431 | } |
| 389 | } | 432 | } |
| 390 | } | 433 | } |
| @@ -396,11 +439,14 @@ static void __propagate_umount(struct mount *mnt) | |||
| 396 | * | 439 | * |
| 397 | * vfsmount lock must be held for write | 440 | * vfsmount lock must be held for write |
| 398 | */ | 441 | */ |
| 399 | int propagate_umount(struct hlist_head *list) | 442 | int propagate_umount(struct list_head *list) |
| 400 | { | 443 | { |
| 401 | struct mount *mnt; | 444 | struct mount *mnt; |
| 402 | 445 | ||
| 403 | hlist_for_each_entry(mnt, list, mnt_hash) | 446 | list_for_each_entry_reverse(mnt, list, mnt_list) |
| 447 | mark_umount_candidates(mnt); | ||
| 448 | |||
| 449 | list_for_each_entry(mnt, list, mnt_list) | ||
| 404 | __propagate_umount(mnt); | 450 | __propagate_umount(mnt); |
| 405 | return 0; | 451 | return 0; |
| 406 | } | 452 | } |
diff --git a/fs/pnode.h b/fs/pnode.h index 4a246358b031..7114ce6e6b9e 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
| @@ -19,6 +19,9 @@ | |||
| 19 | #define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED) | 19 | #define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED) |
| 20 | #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED) | 20 | #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED) |
| 21 | #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED) | 21 | #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED) |
| 22 | #define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED) | ||
| 23 | #define IS_MNT_LOCKED_AND_LAZY(m) \ | ||
| 24 | (((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED) | ||
| 22 | 25 | ||
| 23 | #define CL_EXPIRE 0x01 | 26 | #define CL_EXPIRE 0x01 |
| 24 | #define CL_SLAVE 0x02 | 27 | #define CL_SLAVE 0x02 |
| @@ -40,14 +43,14 @@ static inline void set_mnt_shared(struct mount *mnt) | |||
| 40 | void change_mnt_propagation(struct mount *, int); | 43 | void change_mnt_propagation(struct mount *, int); |
| 41 | int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, | 44 | int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, |
| 42 | struct hlist_head *); | 45 | struct hlist_head *); |
| 43 | int propagate_umount(struct hlist_head *); | 46 | int propagate_umount(struct list_head *); |
| 44 | int propagate_mount_busy(struct mount *, int); | 47 | int propagate_mount_busy(struct mount *, int); |
| 48 | void propagate_mount_unlock(struct mount *); | ||
| 45 | void mnt_release_group_id(struct mount *); | 49 | void mnt_release_group_id(struct mount *); |
| 46 | int get_dominating_id(struct mount *mnt, const struct path *root); | 50 | int get_dominating_id(struct mount *mnt, const struct path *root); |
| 47 | unsigned int mnt_get_count(struct mount *mnt); | 51 | unsigned int mnt_get_count(struct mount *mnt); |
| 48 | void mnt_set_mountpoint(struct mount *, struct mountpoint *, | 52 | void mnt_set_mountpoint(struct mount *, struct mountpoint *, |
| 49 | struct mount *); | 53 | struct mount *); |
| 50 | void umount_tree(struct mount *, int); | ||
| 51 | struct mount *copy_tree(struct mount *, struct dentry *, int); | 54 | struct mount *copy_tree(struct mount *, struct dentry *, int); |
| 52 | bool is_path_reachable(struct mount *, struct dentry *, | 55 | bool is_path_reachable(struct mount *, struct dentry *, |
| 53 | const struct path *root); | 56 | const struct path *root); |
diff --git a/include/linux/fs_pin.h b/include/linux/fs_pin.h index 9dc4e0384bfb..3886b3bffd7f 100644 --- a/include/linux/fs_pin.h +++ b/include/linux/fs_pin.h | |||
| @@ -13,6 +13,8 @@ struct vfsmount; | |||
| 13 | static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *)) | 13 | static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *)) |
| 14 | { | 14 | { |
| 15 | init_waitqueue_head(&p->wait); | 15 | init_waitqueue_head(&p->wait); |
| 16 | INIT_HLIST_NODE(&p->s_list); | ||
| 17 | INIT_HLIST_NODE(&p->m_list); | ||
| 16 | p->kill = kill; | 18 | p->kill = kill; |
| 17 | } | 19 | } |
| 18 | 20 | ||
diff --git a/include/linux/mount.h b/include/linux/mount.h index bca086d62b1a..f822c3c11377 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
| @@ -61,6 +61,7 @@ struct mnt_namespace; | |||
| 61 | #define MNT_DOOMED 0x1000000 | 61 | #define MNT_DOOMED 0x1000000 |
| 62 | #define MNT_SYNC_UMOUNT 0x2000000 | 62 | #define MNT_SYNC_UMOUNT 0x2000000 |
| 63 | #define MNT_MARKED 0x4000000 | 63 | #define MNT_MARKED 0x4000000 |
| 64 | #define MNT_UMOUNT 0x8000000 | ||
| 64 | 65 | ||
| 65 | struct vfsmount { | 66 | struct vfsmount { |
| 66 | struct dentry *mnt_root; /* root of the mounted tree */ | 67 | struct dentry *mnt_root; /* root of the mounted tree */ |
