[CRIU] [PATCH 1/2] cg: add --cgroup-root option

Tycho Andersen tycho.andersen at canonical.com
Fri Aug 15 15:02:21 PDT 2014


The motivation for this is to be able to restore containers into cgroups other
than what they were dumped in (if, e.g. they might conflict with an existing
container). Suppose you have a container in:

memory:/mycontainer
cpuacct,cpu:/mycontainer
blkio:/mycontainer
name=systemd:/mycontainer

You could then restore them to /mycontainer2 via --cgroup-root /mycontainer2.
If you want to restore different controllers to different paths, you can
provide multiple arguments, for example, passing:

--cgroup-root /mycontainer2 --cgroup-root cpuacct,cpu:/specialcpu \
--cgroup-root name=systemd:/specialsystemd

Would result in things being restored to:

memory:/mycontainer2
cpuacct,cpu:/specialcpu
blkio:/mycontainer2
name=systemd:/specialsystemd

i.e. a --cgroup-root without a controller prefix specifies the new default root
for all cgroups.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 cgroup.c             | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 crtools.c            | 22 +++++++++++++
 include/cgroup.h     |  2 +-
 include/cr_options.h |  8 +++++
 4 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/cgroup.c b/cgroup.c
index 264957c..36a8ae8 100644
--- a/cgroup.c
+++ b/cgroup.c
@@ -1161,6 +1161,77 @@ err:
 	return -1;
 }
 
+static int rewrite_cgsets(CgroupEntry *cge, char **controllers, int n_controllers,
+			  char *from, char *to)
+{
+	int i, j;
+	for (i = 0; i < cge->n_sets; i++) {
+		CgSetEntry *set = cge->sets[i];
+		for (j = 0; j < set->n_ctls; j++) {
+			CgMemberEntry *cg = set->ctls[j];
+			if (cgroup_contains(controllers, n_controllers, cg->name) &&
+					/* +1 to get rid of leading / */
+					strstartswith(cg->path + 1, from)) {
+
+				/* +1 to get rid of leading /, again */
+				int off = strlen(from) + 1;
+
+				/* +1 for trailing NULL */
+				int newlen = strlen(to) + strlen(cg->path + off) + 1;
+				char *m = malloc(newlen * sizeof(char*));
+				if (!m)
+					return -1;
+
+				sprintf(m, "%s%s", to, cg->path + off);
+				free(cg->path);
+				cg->path = m;
+			}
+		}
+
+	}
+	return 0;
+}
+
+static int rewrite_cgroup_roots(CgroupEntry *cge)
+{
+	int i, j;
+	struct cg_root_opt *o;
+	char *newroot = NULL;
+
+	for (i = 0; i < cge->n_controllers; i++) {
+		CgControllerEntry *ctrl = cge->controllers[i];
+		newroot = opts.new_global_cg_root;
+
+		list_for_each_entry(o, &opts.new_cgroup_roots, node) {
+			if (cgroup_contains(ctrl->cnames, ctrl->n_cnames, o->controller)) {
+				newroot = o->newroot;
+				break;
+			}
+
+		}
+
+		if (newroot) {
+			for (j = 0; j < ctrl->n_dirs; j++) {
+				CgroupDirEntry *cgde = ctrl->dirs[j];
+				char *m;
+
+				pr_info("rewriting %s to %s\n", cgde->dir_name, newroot);
+				if (rewrite_cgsets(cge, ctrl->cnames, ctrl->n_cnames, cgde->dir_name, newroot))
+					return -1;
+
+				m = xstrdup(newroot);
+				if (!m)
+					return -1;
+
+				free(cgde->dir_name);
+				cgde->dir_name = m;
+			}
+		}
+	}
+
+	return 0;
+}
+
 int prepare_cgroup(void)
 {
 	int fd, ret;
@@ -1179,6 +1250,9 @@ int prepare_cgroup(void)
 	if (ret <= 0) /* Zero is OK -- no sets there. */
 		return ret;
 
+	if (rewrite_cgroup_roots(ce))
+		return -1;
+
 	n_sets = ce->n_sets;
 	rst_sets = ce->sets;
 	n_controllers = ce->n_controllers;
@@ -1196,3 +1270,17 @@ int prepare_cgroup(void)
 
 	return ret;
 }
+
+int new_cg_root_add(char *controller, char *newroot)
+{
+	struct cg_root_opt *o;
+
+	o = xmalloc(sizeof(*o));
+	if (!o)
+		return -1;
+
+	o->controller = controller;
+	o->newroot = newroot;
+	list_add(&o->node, &opts.new_cgroup_roots);
+	return 0;
+}
diff --git a/crtools.c b/crtools.c
index 6caea08..da87069 100644
--- a/crtools.c
+++ b/crtools.c
@@ -35,6 +35,7 @@
 #include "cr-service.h"
 #include "plugin.h"
 #include "mount.h"
+#include "cgroup.h"
 
 struct cr_options opts;
 
@@ -47,6 +48,7 @@ void init_opts(void)
 	INIT_LIST_HEAD(&opts.veth_pairs);
 	INIT_LIST_HEAD(&opts.scripts);
 	INIT_LIST_HEAD(&opts.ext_mounts);
+	INIT_LIST_HEAD(&opts.new_cgroup_roots);
 
 	opts.cpu_cap = CPU_CAP_ALL;
 	opts.manage_cgroups = false;
@@ -169,6 +171,7 @@ int main(int argc, char *argv[])
 		{ "ext-mount-map", required_argument, 0, 'M'},
 		{ "exec-cmd", no_argument, 0, 59},
 		{ "manage-cgroups", no_argument, 0, 60},
+		{ "cgroup-root", required_argument, 0, 61},
 		{ },
 	};
 
@@ -358,6 +361,21 @@ int main(int argc, char *argv[])
 		case 60:
 			opts.manage_cgroups = true;
 			break;
+		case 61:
+			{
+				char *aux;
+
+				aux = strchr(optarg, ':');
+				if (!aux) {
+					opts.new_global_cg_root = optarg;
+				} else {
+					*aux = '\0';
+					if (new_cg_root_add(optarg, aux + 1))
+						return -1;
+				}
+
+			}
+			break;
 		case 'M':
 			{
 				char *aux;
@@ -547,6 +565,10 @@ usage:
 "  -M|--ext-mount-map KEY:VALUE\n"
 "                        add external mount mapping\n"
 "  --manage-cgroups      dump or restore cgroups the process is in\n"
+"  --cgroup-root [controller:]/newroot\n"
+"                        change the root cgroup the controller will be\n"
+"                        installed into. No controller means that root is the\n"
+"                        default for all controllers not specified.\n"
 "\n"
 "* Logging:\n"
 "  -o|--log-file FILE    log file name\n"
diff --git a/include/cgroup.h b/include/cgroup.h
index c49fb19..14fef67 100644
--- a/include/cgroup.h
+++ b/include/cgroup.h
@@ -55,5 +55,5 @@ struct cg_controller *new_controller(const char *name, int heirarchy);
 
 /* parse all global cgroup information into structures */
 int parse_cg_info(void);
-
+int new_cg_root_add(char *controller, char *newroot);
 #endif /* __CR_CGROUP_H__ */
diff --git a/include/cr_options.h b/include/cr_options.h
index 0d11aa7..73ec50c 100644
--- a/include/cr_options.h
+++ b/include/cr_options.h
@@ -19,6 +19,12 @@ struct script {
 #define CPU_CAP_FPU		(1u)
 #define CPU_CAP_ALL		(-1u)
 
+struct cg_root_opt {
+	struct list_head node;
+	char *controller;
+	char *newroot;
+};
+
 struct cr_options {
 	int			final_state;
 	char			*show_dump_file;
@@ -52,6 +58,8 @@ struct cr_options {
 	bool			force_irmap;
 	char			**exec_cmd;
 	bool			manage_cgroups;
+	char			*new_global_cg_root;
+	struct list_head	new_cgroup_roots;
 };
 
 extern struct cr_options opts;
-- 
1.9.1



More information about the CRIU mailing list