summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/mount.h1
-rw-r--r--fs/namespace.c1
-rw-r--r--fs/pnode.c35
3 files changed, 32 insertions, 5 deletions
diff --git a/fs/mount.h b/fs/mount.h
index bf1fda6eed8f..ede5a1d5cf99 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -58,6 +58,7 @@ struct mount {
58 struct mnt_namespace *mnt_ns; /* containing namespace */ 58 struct mnt_namespace *mnt_ns; /* containing namespace */
59 struct mountpoint *mnt_mp; /* where is it mounted */ 59 struct mountpoint *mnt_mp; /* where is it mounted */
60 struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */ 60 struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
61 struct list_head mnt_reparent; /* reparent list entry */
61#ifdef CONFIG_FSNOTIFY 62#ifdef CONFIG_FSNOTIFY
62 struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; 63 struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
63 __u32 mnt_fsnotify_mask; 64 __u32 mnt_fsnotify_mask;
diff --git a/fs/namespace.c b/fs/namespace.c
index 8bd3e4d448b9..51e49866e1fe 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -236,6 +236,7 @@ static struct mount *alloc_vfsmnt(const char *name)
236 INIT_LIST_HEAD(&mnt->mnt_slave_list); 236 INIT_LIST_HEAD(&mnt->mnt_slave_list);
237 INIT_LIST_HEAD(&mnt->mnt_slave); 237 INIT_LIST_HEAD(&mnt->mnt_slave);
238 INIT_HLIST_NODE(&mnt->mnt_mp_list); 238 INIT_HLIST_NODE(&mnt->mnt_mp_list);
239 INIT_LIST_HEAD(&mnt->mnt_reparent);
239 init_fs_pin(&mnt->mnt_umount, drop_mountpoint); 240 init_fs_pin(&mnt->mnt_umount, drop_mountpoint);
240 } 241 }
241 return mnt; 242 return mnt;
diff --git a/fs/pnode.c b/fs/pnode.c
index 5bc7896d122a..52aca0a118ff 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -439,7 +439,7 @@ static void mark_umount_candidates(struct mount *mnt)
439 * NOTE: unmounting 'mnt' naturally propagates to all other mounts its 439 * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
440 * parent propagates to. 440 * parent propagates to.
441 */ 441 */
442static void __propagate_umount(struct mount *mnt) 442static void __propagate_umount(struct mount *mnt, struct list_head *to_reparent)
443{ 443{
444 struct mount *parent = mnt->mnt_parent; 444 struct mount *parent = mnt->mnt_parent;
445 struct mount *m; 445 struct mount *m;
@@ -464,17 +464,38 @@ static void __propagate_umount(struct mount *mnt)
464 */ 464 */
465 topper = find_topper(child); 465 topper = find_topper(child);
466 if (topper) 466 if (topper)
467 mnt_change_mountpoint(child->mnt_parent, child->mnt_mp, 467 list_add_tail(&topper->mnt_reparent, to_reparent);
468 topper);
469 468
470 if (list_empty(&child->mnt_mounts)) { 469 if (topper || list_empty(&child->mnt_mounts)) {
471 list_del_init(&child->mnt_child); 470 list_del_init(&child->mnt_child);
471 list_del_init(&child->mnt_reparent);
472 child->mnt.mnt_flags |= MNT_UMOUNT; 472 child->mnt.mnt_flags |= MNT_UMOUNT;
473 list_move_tail(&child->mnt_list, &mnt->mnt_list); 473 list_move_tail(&child->mnt_list, &mnt->mnt_list);
474 } 474 }
475 } 475 }
476} 476}
477 477
478static void reparent_mounts(struct list_head *to_reparent)
479{
480 while (!list_empty(to_reparent)) {
481 struct mount *mnt, *parent;
482 struct mountpoint *mp;
483
484 mnt = list_first_entry(to_reparent, struct mount, mnt_reparent);
485 list_del_init(&mnt->mnt_reparent);
486
487 /* Where should this mount be reparented to? */
488 mp = mnt->mnt_mp;
489 parent = mnt->mnt_parent;
490 while (parent->mnt.mnt_flags & MNT_UMOUNT) {
491 mp = parent->mnt_mp;
492 parent = parent->mnt_parent;
493 }
494
495 mnt_change_mountpoint(parent, mp, mnt);
496 }
497}
498
478/* 499/*
479 * collect all mounts that receive propagation from the mount in @list, 500 * collect all mounts that receive propagation from the mount in @list,
480 * and return these additional mounts in the same list. 501 * and return these additional mounts in the same list.
@@ -485,11 +506,15 @@ static void __propagate_umount(struct mount *mnt)
485int propagate_umount(struct list_head *list) 506int propagate_umount(struct list_head *list)
486{ 507{
487 struct mount *mnt; 508 struct mount *mnt;
509 LIST_HEAD(to_reparent);
488 510
489 list_for_each_entry_reverse(mnt, list, mnt_list) 511 list_for_each_entry_reverse(mnt, list, mnt_list)
490 mark_umount_candidates(mnt); 512 mark_umount_candidates(mnt);
491 513
492 list_for_each_entry(mnt, list, mnt_list) 514 list_for_each_entry(mnt, list, mnt_list)
493 __propagate_umount(mnt); 515 __propagate_umount(mnt, &to_reparent);
516
517 reparent_mounts(&to_reparent);
518
494 return 0; 519 return 0;
495} 520}