VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
author: Eric W. Biederman <ebiederm@xmission.com> 2017-05-15 14:42:07 -0500 committer: Eric W. Biederman <ebiederm@xmission.com> 2017-05-23 08:40:32 -0500 commit: 570487d3faf2a1d8a220e6ee10f472163123d7da parent: c70d9d809fdeecedb96972457ee45c49a232d97f
Commit Summary:
mnt: In umount propagation reparent in a separate pass
Diffstat:
1 file changed, 26 insertions, 5 deletions
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)
  * NOTE: unmounting 'mnt' naturally propagates to all other mounts its
  * parent propagates to.
  */
-static void __propagate_umount(struct mount *mnt)
+static void __propagate_umount(struct mount *mnt, struct list_head *to_reparent)
 {
 	struct mount *parent = mnt->mnt_parent;
 	struct mount *m;
@@ -464,17 +464,38 @@ static void __propagate_umount(struct mount *mnt)
 		 */
 		topper = find_topper(child);
 		if (topper)
-			mnt_change_mountpoint(child->mnt_parent, child->mnt_mp,
-					      topper);
+			list_add_tail(&topper->mnt_reparent, to_reparent);
 
-		if (list_empty(&child->mnt_mounts)) {
+		if (topper || list_empty(&child->mnt_mounts)) {
 			list_del_init(&child->mnt_child);
+			list_del_init(&child->mnt_reparent);
 			child->mnt.mnt_flags |= MNT_UMOUNT;
 			list_move_tail(&child->mnt_list, &mnt->mnt_list);
 		}
 	}
 }
 
+static void reparent_mounts(struct list_head *to_reparent)
+{
+	while (!list_empty(to_reparent)) {
+		struct mount *mnt, *parent;
+		struct mountpoint *mp;
+
+		mnt = list_first_entry(to_reparent, struct mount, mnt_reparent);
+		list_del_init(&mnt->mnt_reparent);
+
+		/* Where should this mount be reparented to? */
+		mp = mnt->mnt_mp;
+		parent = mnt->mnt_parent;
+		while (parent->mnt.mnt_flags & MNT_UMOUNT) {
+			mp = parent->mnt_mp;
+			parent = parent->mnt_parent;
+		}
+
+		mnt_change_mountpoint(parent, mp, mnt);
+	}
+}
+
 /*
  * collect all mounts that receive propagation from the mount in @list,
  * and return these additional mounts in the same list.
@@ -485,11 +506,15 @@ static void __propagate_umount(struct mount *mnt)
 int propagate_umount(struct list_head *list)
 {
 	struct mount *mnt;
+	LIST_HEAD(to_reparent);
 
 	list_for_each_entry_reverse(mnt, list, mnt_list)
 		mark_umount_candidates(mnt);
 
 	list_for_each_entry(mnt, list, mnt_list)
-		__propagate_umount(mnt);
+		__propagate_umount(mnt, &to_reparent);
+
+	reparent_mounts(&to_reparent);
+
 	return 0;
 }