[6/9] mount: improve can_mount_now using propagation groups

Submitted by Pavel Tikhomirov on July 10, 2018, 4:02 p.m.

Details

Message ID 20180710160231.1292-7-ptikhomirov@virtuozzo.com
State Accepted
Series "mount: better handling of mount propagation"
Commit a337d1e953389efd8668a0418d445f4db6160c87
Headers show

Commit Message

Pavel Tikhomirov July 10, 2018, 4:02 p.m.
1) redo waiting for parents of propagation group to be mounted using
pre-found propagation groups
2) for shared mount wait for children of that shared group which has no
propagation in our shared mount

(2) - effectively is a support of non-uniform shares, that means two
mounts of shared group can have different sets of children now - we will
mount them in the right order, but propagate_mount and validate_shared
are still preventing c/r-ing such shares, will fix the former and remove
the latter in separate(next) patches.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 criu/include/mount.h |  1 +
 criu/mount.c         | 77 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 61 insertions(+), 17 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/mount.h b/criu/include/mount.h
index 84c62c8d0..ca17b059a 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -66,6 +66,7 @@  struct mount_info {
 	struct list_head	mnt_slave;	/* slave list entry */
 	struct mount_info	*mnt_master;	/* slave is on master->mnt_slave_list */
 	struct list_head	mnt_propagate;	/* circular list of mounts which propagate from each other */
+	struct list_head	mnt_notprop;	/* temporary list used in can_mount_now */
 
 	struct list_head	postpone;
 
diff --git a/criu/mount.c b/criu/mount.c
index 40d841984..b2523f35f 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -2456,6 +2456,9 @@  static bool can_mount_now(struct mount_info *mi)
 	if (rst_mnt_is_root(mi))
 		return true;
 
+	/* Parent should be mounted already, that's how mnt_tree_for_each works */
+	BUG_ON(mi->parent && !mi->parent->mounted);
+
 	if (mi->external)
 		goto shared;
 
@@ -2485,28 +2488,67 @@  static bool can_mount_now(struct mount_info *mi)
 		return false;
 
 shared:
-	if (mi->parent->shared_id) {
-		struct mount_info *n;
+	/* Mount only after all parents of our propagation group mounted */
+	if (!list_empty(&mi->mnt_propagate)) {
+		struct mount_info *p;
 
-		list_for_each_entry(n, &mi->parent->mnt_share, mnt_share)
-			/*
-			 * All mounts from mi's parent shared group which
-			 * have mi's 'sibling' should receive it through
-			 * mount propagation, so all such mounts in parent
-			 * shared group should be mounted beforehand.
-			 */
-			if (!n->mounted) {
-				char path[PATH_MAX], *mp;
-				struct mount_info *c;
+		list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) {
+			BUG_ON(!p->parent);
+			if (!p->parent->mounted)
+				return false;
+		}
+	}
+
+	/*
+	 * Mount only after all children of share, which shouldn't
+	 * (but can if wrong order) propagate to us, are mounted
+	 */
+	if (mi->shared_id) {
+		struct mount_info *s, *c, *p, *t;
+		LIST_HEAD(mi_notprop);
+		bool can = true;
+
+		/* Add all children of the shared group */
+		list_for_each_entry(s, &mi->mnt_share, mnt_share) {
+			list_for_each_entry(c, &s->children, siblings) {
+				char root_path[PATH_MAX];
+				int ret;
+
+				ret = root_path_from_parent(c, root_path, PATH_MAX);
+				BUG_ON(ret);
 
-				mp = mnt_get_sibling_path(mi, n, path, sizeof(path));
-				if (mp == NULL)
+				/* Mount is out of our root */
+				if (!issubpath(root_path, mi->root))
 					continue;
 
-				list_for_each_entry(c, &n->children, siblings)
-					if (mounts_equal(mi, c) && !strcmp(mp, c->mountpoint))
-						return false;
+				list_add(&c->mnt_notprop, &mi_notprop);
 			}
+		}
+
+		/* Delete all members of our children's propagation groups */
+		list_for_each_entry(c, &mi->children, siblings) {
+			list_for_each_entry(p, &c->mnt_propagate, mnt_propagate) {
+				list_del_init(&p->mnt_notprop);
+			}
+		}
+
+		/* Delete all members of our propagation group */
+		list_for_each_entry(p, &mi->mnt_propagate, mnt_propagate) {
+			list_del_init(&p->mnt_notprop);
+		}
+
+		/* Delete self */
+		list_del_init(&mi->mnt_notprop);
+
+		/* Check not propagated mounts mounted and cleanup list */
+		list_for_each_entry_safe(p, t, &mi_notprop, mnt_notprop) {
+			if (!p->mounted)
+				can = false;
+			list_del_init(&p->mnt_notprop);
+		}
+
+		if (!can)
+			return false;
 	}
 
 	return true;
@@ -2798,6 +2840,7 @@  struct mount_info *mnt_entry_alloc()
 		INIT_LIST_HEAD(&new->mnt_share);
 		INIT_LIST_HEAD(&new->mnt_bind);
 		INIT_LIST_HEAD(&new->mnt_propagate);
+		INIT_LIST_HEAD(&new->mnt_notprop);
 		INIT_LIST_HEAD(&new->postpone);
 	}
 	return new;