[CRIU] [PATCH 04/11] mounts: if a mount can't be mounted, it is queued in postpone list (v2)

Andrey Vagin avagin at openvz.org
Tue Jul 30 12:25:29 EDT 2013


Try to restore mounts while a postpone list isn't empty and check
that each iteration has some progress, otherwice it will fails for
preventing infinite loops

v2: rework logic about postpone list
    add more comments

v3: one more attempt to make it more readable

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/proc_parse.h |  2 ++
 mount.c              | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/include/proc_parse.h b/include/proc_parse.h
index 99255c4..1a2a579 100644
--- a/include/proc_parse.h
+++ b/include/proc_parse.h
@@ -121,6 +121,8 @@ struct mount_info {
 	struct list_head mnt_slave_list;/* list of slave mounts */
 	struct list_head mnt_slave;	/* slave list entry */
 	struct mount_info *mnt_master;	/* slave is on master->mnt_slave_list */
+
+	struct list_head postpone;
 };
 
 struct proc_posix_timer {
diff --git a/mount.c b/mount.c
index d60fb9a..49ad16a 100644
--- a/mount.c
+++ b/mount.c
@@ -598,12 +598,32 @@ int dump_mnt_ns(int ns_pid, struct cr_fdset *fdset)
 	return 0;
 }
 
-#define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r) do {				\
+static int mount_progress;
+
+/*
+ * _fn_f  - pre-order traversal function
+ * _fn_f  - post-order traversal function
+ * _plist - a postpone list. _el is added to this list, if _fn_f returns
+ *	    a positive value, and all lower elements are not enumirated.
+ */
+#define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r, _plist) do {			\
 		struct mount_info *_mi = _r;					\
 										\
 		while (1) {							\
-			if (_fn_f(_mi))						\
+			int ret;						\
+										\
+			list_del_init(&_mi->postpone);				\
+										\
+			ret = _fn_f(_mi);					\
+			if (ret < 0)						\
 				return -1;					\
+			else if (ret > 0) {					\
+				list_add_tail(&_mi->postpone, _plist);		\
+				goto up;					\
+			}							\
+										\
+			mount_progress++;					\
+										\
 			if (!list_empty(&_mi->children)) {			\
 				_mi = list_entry(_mi->children._el,		\
 						struct mount_info, siblings);	\
@@ -626,10 +646,46 @@ int dump_mnt_ns(int ns_pid, struct cr_fdset *fdset)
 #define MNT_WALK_NONE	0 &&
 
 
-static int mnt_tree_for_each(struct mount_info *m,
+static int mnt_tree_for_each(struct mount_info *start,
 		int (*fn)(struct mount_info *))
 {
-	MNT_TREE_WALK(m, next, fn, MNT_WALK_NONE);
+	static LIST_HEAD(postpone);
+	struct mount_info *first_wo_progress = NULL;
+	int old_progress = mount_progress;
+
+again:
+	pr_debug("Start with %d:%s\n", start->mnt_id, start->mountpoint);
+
+	MNT_TREE_WALK(start, next, fn, MNT_WALK_NONE, &postpone);
+
+	if (old_progress == mount_progress) {
+		if (first_wo_progress == NULL)
+			first_wo_progress = start;
+	} else {
+		first_wo_progress = NULL;
+		old_progress = mount_progress;
+	}
+
+	if (!list_empty(&postpone)) {
+		start = list_first_entry(&postpone, struct mount_info, postpone);
+
+		/*
+		 * If we need to start from the same point in a second time
+		 * w/o intermediate progress, we are in an infinite loop.
+		 */
+		if (first_wo_progress == start) {
+			struct mount_info *m;
+
+			pr_err("A few mount points can't be mounted");
+			list_for_each_entry(m, &postpone, postpone) {
+				pr_err("%d:%d %s %s %s\n", m->mnt_id,
+					m->parent_mnt_id, m->root,
+					m->mountpoint, m->source);
+			}
+			return -1;
+		}
+		goto again;
+	}
 
 	return 0;
 }
@@ -637,7 +693,7 @@ static int mnt_tree_for_each(struct mount_info *m,
 static int mnt_tree_for_each_reverse(struct mount_info *m,
 		int (*fn)(struct mount_info *))
 {
-	MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn);
+	MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn, (struct list_head *) NULL);
 
 	return 0;
 }
@@ -798,6 +854,7 @@ struct mount_info *mnt_entry_alloc()
 		INIT_LIST_HEAD(&new->siblings);
 		INIT_LIST_HEAD(&new->mnt_slave_list);
 		INIT_LIST_HEAD(&new->mnt_share);
+		INIT_LIST_HEAD(&new->postpone);
 		new->mnt_master = NULL;
 	}
 	return new;
-- 
1.8.3.1



More information about the CRIU mailing list