diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/pnode.c | 32 | ||||
-rw-r--r-- | fs/pnode.h | 1 |
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 | */ | ||
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 | /* | ||
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 |