[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