[CRIU] [PATCH] cgroup: don't fail on multi-headed freezer cgroup

Tycho Andersen tycho.andersen at canonical.com
Fri Feb 26 15:27:29 PST 2016


Consider the case where --freeze-cgroup=/lxc/foo, but (e.g. with systemd in
lxc), all of the tasks actually live in a set of sub cgroups, e.g.
/lxc/foo/init.scope and others. In this case, we will have a multi-headed
controller, since there is nothing in the common parent. We should just
save the freezer value in all of these heads instead of failing.

Note that this doesn't address the larger problem that only the top level
freezer.state file is c/r'd, or waht happens when the container itself has
frozen tasks but not at the top level. After some discussion, there is no
nice way to atomically test-and-set the cgroup freezer, so we'll need some
other kernel help. But I'll ignore this for now :)

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 criu/cgroup.c | 47 +++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/criu/cgroup.c b/criu/cgroup.c
index c4c6c55..7742fda 100644
--- a/criu/cgroup.c
+++ b/criu/cgroup.c
@@ -556,31 +556,34 @@ out:
 
 static int add_freezer_state(struct cg_controller *controller)
 {
-	struct cgroup_dir *root_dir;
-	struct cgroup_prop *prop;
-
-	/*
-	 * Here we rely on --freeze-cgroup option assumption that all tasks are in a
-	 * specified freezer cgroup hierarchy, so we need to dump only one root freezer cgroup.
-	 */
-	if (!list_is_singular(&controller->heads)) {
-		pr_err("Should be only one root freezer cgroup");
-		return -1;
-	}
-	root_dir = list_first_entry(&controller->heads, struct cgroup_dir, siblings);
+	struct cgroup_dir *it;
+
+	 /* There is one more case, that cgroup namespaces might
+	  * generate "multiple" heads if nothing is actually in the
+	  * root freezer cgroup, e.g. --freeze-cgroup=/lxc/foo and all
+	  * tasks in either /lxc/foo/a or /lxc/foo/b.
+	  *
+	  * In this case
+	  */
+	list_for_each_entry(it, &controller->heads, siblings) {
+		struct cgroup_dir *cg_head;
+		struct cgroup_prop *prop;
+
+		cg_head = list_first_entry(&controller->heads, struct cgroup_dir, siblings);
+
+		prop = create_cgroup_prop("freezer.state");
+		if (!prop)
+			return -1;
+		prop->value = xstrdup(get_real_freezer_state());
+		if (!prop->value) {
+			free_cgroup_prop(prop);
+			return -1;
+		}
 
-	prop = create_cgroup_prop("freezer.state");
-	if (!prop)
-		return -1;
-	prop->value = xstrdup(get_real_freezer_state());
-	if (!prop->value) {
-		free_cgroup_prop(prop);
-		return -1;
+		list_add_tail(&prop->list, &cg_head->properties);
+		cg_head->n_properties++;
 	}
 
-	list_add_tail(&prop->list, &root_dir->properties);
-	root_dir->n_properties++;
-
 	return 0;
 }
 
-- 
2.6.4



More information about the CRIU mailing list