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;