aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pnode.c')
-rw-r--r--fs/pnode.c60
1 files changed, 53 insertions, 7 deletions
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 */
369void 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 */
387static 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 */
399int propagate_umount(struct hlist_head *list) 442int 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}