aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/pnode.c32
-rw-r--r--fs/pnode.h1
2 files changed, 30 insertions, 3 deletions
diff --git a/fs/pnode.c b/fs/pnode.c
index 89890293dd0a..6367e1e435c6 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -382,6 +382,26 @@ void propagate_mount_unlock(struct mount *mnt)
382} 382}
383 383
384/* 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/*
385 * NOTE: unmounting 'mnt' naturally propagates to all other mounts its 405 * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
386 * parent propagates to. 406 * parent propagates to.
387 */ 407 */
@@ -398,10 +418,13 @@ static void __propagate_umount(struct mount *mnt)
398 struct mount *child = __lookup_mnt_last(&m->mnt, 418 struct mount *child = __lookup_mnt_last(&m->mnt,
399 mnt->mnt_mountpoint); 419 mnt->mnt_mountpoint);
400 /* 420 /*
401 * umount the child only if the child has no 421 * umount the child only if the child has no children
402 * other children 422 * and the child is marked safe to unmount.
403 */ 423 */
404 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)) {
405 list_del_init(&child->mnt_child); 428 list_del_init(&child->mnt_child);
406 child->mnt.mnt_flags |= MNT_UMOUNT; 429 child->mnt.mnt_flags |= MNT_UMOUNT;
407 list_move_tail(&child->mnt_list, &mnt->mnt_list); 430 list_move_tail(&child->mnt_list, &mnt->mnt_list);
@@ -420,6 +443,9 @@ int propagate_umount(struct list_head *list)
420{ 443{
421 struct mount *mnt; 444 struct mount *mnt;
422 445
446 list_for_each_entry_reverse(mnt, list, mnt_list)
447 mark_umount_candidates(mnt);
448
423 list_for_each_entry(mnt, list, mnt_list) 449 list_for_each_entry(mnt, list, mnt_list)
424 __propagate_umount(mnt); 450 __propagate_umount(mnt);
425 return 0; 451 return 0;
diff --git a/fs/pnode.h b/fs/pnode.h
index af47d4bd7b31..0fcdbe7ca648 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -19,6 +19,7 @@
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)
22 23
23#define CL_EXPIRE 0x01 24#define CL_EXPIRE 0x01
24#define CL_SLAVE 0x02 25#define CL_SLAVE 0x02