From 94f6c87c9f90c1f8554f8210c8a2dce36ae151cf Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Fri, 15 Aug 2014 17:02:21 -0500 Subject: [PATCH] cg: add --cgroup-root option 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 Signed-off-by: Pavel Emelyanov --- 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 f738b1a6b..3c7e48a8d 100644 --- a/cgroup.c +++ b/cgroup.c @@ -1171,6 +1171,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; @@ -1189,6 +1260,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; @@ -1206,3 +1280,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 6caea0876..da870690d 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 c49fb1972..14fef6745 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 0d11aa71f..73ec50c37 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;