From 54860ed02790c1c87bf1125c3b91b52ee1ee1c37 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 31 Jan 2018 16:44:30 +0100 Subject: [PATCH] confile: add lxc.cgroup2.[controller].[property] Signed-off-by: Christian Brauner --- doc/lxc.container.conf.sgml.in | 30 +++++--- src/lxc/conf.c | 33 ++++++--- src/lxc/conf.h | 10 ++- src/lxc/confile.c | 123 +++++++++++++++++++++++++-------- 4 files changed, 150 insertions(+), 46 deletions(-) diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 3ae4bfd18..dfb7ba05d 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1330,17 +1330,31 @@ dev/null proc/kcore none bind,relative 0 0 - + - specify the control group value to be set. The - subsystem name is the literal name of the control group - subsystem. The permitted names and the syntax of their - values is not dictated by LXC, instead it depends on the - features of the Linux kernel running at the time the - container is started, - eg. + Specify the control group value to be set on a legacy cgroup + hierarchy. The controller name is the literal name of the control + group. The permitted names and the syntax of their values is not + dictated by LXC, instead it depends on the features of the Linux + kernel running at the time the container is started, eg. + + + + + + + + + + + Specify the control group value to be set on the unified cgroup + shierarchy. The controller name is the literal name of the control + group. The permitted names and the syntax of their values is not + dictated by LXC, instead it depends on the features of the Linux + kernel running at the time the container is started, eg. + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index a080bbd7e..9b6868940 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2555,6 +2555,7 @@ struct lxc_conf *lxc_conf_init(void) } new->logfd = -1; lxc_list_init(&new->cgroup); + lxc_list_init(&new->cgroup2); lxc_list_init(&new->network); lxc_list_init(&new->mount_list); lxc_list_init(&new->caps); @@ -3446,23 +3447,38 @@ int lxc_clear_config_keepcaps(struct lxc_conf *c) return 0; } -int lxc_clear_cgroups(struct lxc_conf *c, const char *key) +int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) { - struct lxc_list *it,*next; - bool all = false; + char *global_token, *namespaced_token; + struct lxc_list *it, *next, *list; const char *k = NULL; + bool all = false; - if (strcmp(key, "lxc.cgroup") == 0) + if (version == CGROUP2_SUPER_MAGIC) { + global_token = "lxc.cgroup2"; + namespaced_token = "lxc.cgroup2."; + list = &c->cgroup2; + } else if (version == CGROUP_SUPER_MAGIC) { + global_token = "lxc.cgroup"; + namespaced_token = "lxc.cgroup."; + list = &c->cgroup; + } else { + return -1; + } + + if (strcmp(key, global_token) == 0) all = true; - else if (strncmp(key, "lxc.cgroup.", sizeof("lxc.cgroup.") - 1) == 0) - k = key + sizeof("lxc.cgroup.") - 1; + else if (strncmp(key, namespaced_token, sizeof(namespaced_token) - 1) == 0) + k = key + sizeof(namespaced_token) - 1; else return -1; - lxc_list_for_each_safe(it, &c->cgroup, next) { + lxc_list_for_each_safe(it, list, next) { struct lxc_cgroup *cg = it->elem; + if (!all && strcmp(cg->subsystem, k) != 0) continue; + lxc_list_del(it); free(cg->subsystem); free(cg->value); @@ -3680,7 +3696,8 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_seccomp_free(conf); lxc_clear_config_caps(conf); lxc_clear_config_keepcaps(conf); - lxc_clear_cgroups(conf, "lxc.cgroup"); + lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC); + lxc_clear_cgroups(conf, "lxc.cgroup2", CGROUP2_SUPER_MAGIC); lxc_clear_hooks(conf, "lxc.hook"); lxc_clear_mount_entries(conf); lxc_clear_idmaps(conf); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 1146a1d4f..2346b717f 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -52,6 +52,8 @@ typedef void * scmp_filter_ctx; * programmer to specify the right subsystem. * @subsystem : the targeted subsystem * @value : the value to set + * @version : The version of the cgroup filesystem on which the controller + * resides. * * @controllers : The controllers to use for this container. * @dir : The name of the directory containing the container's cgroup. @@ -61,6 +63,7 @@ struct lxc_cgroup { union { /* information about a specific controller */ struct /* controller */ { + int version; char *subsystem; char *value; }; @@ -282,7 +285,10 @@ struct lxc_conf { int reboot; signed long personality; struct utsname *utsname; - struct lxc_list cgroup; + struct { + struct lxc_list cgroup; + struct lxc_list cgroup2; + }; struct { struct lxc_list id_map; @@ -433,7 +439,7 @@ extern int lxc_create_tty(const char *name, struct lxc_conf *conf); extern void lxc_delete_tty(struct lxc_tty_info *tty_info); extern int lxc_clear_config_caps(struct lxc_conf *c); extern int lxc_clear_config_keepcaps(struct lxc_conf *c); -extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key); +extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version); extern int lxc_clear_mount_entries(struct lxc_conf *c); extern int lxc_clear_automounts(struct lxc_conf *c); extern int lxc_clear_hooks(struct lxc_conf *c, const char *key); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 3deec58bf..fa4f84da9 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -81,6 +81,7 @@ lxc_config_define(apparmor_profile); lxc_config_define(cap_drop); lxc_config_define(cap_keep); lxc_config_define(cgroup_controller); +lxc_config_define(cgroup2_controller); lxc_config_define(cgroup_dir); lxc_config_define(console_logfile); lxc_config_define(console_rotate); @@ -153,6 +154,7 @@ static struct lxc_config_t config[] = { { "lxc.autodev", false, set_config_autodev, get_config_autodev, clr_config_autodev, }, { "lxc.cap.drop", false, set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, }, { "lxc.cap.keep", false, set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, }, + { "lxc.cgroup2", false, set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, }, { "lxc.cgroup.dir", false, set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, }, { "lxc.cgroup", false, set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, }, { "lxc.console.buffer.logfile", false, set_config_console_buffer_logfile, get_config_console_buffer_logfile, clr_config_console_buffer_logfile, }, @@ -1374,28 +1376,33 @@ static int set_config_signal_stop(const char *key, const char *value, return 0; } -static int set_config_cgroup_controller(const char *key, const char *value, - struct lxc_conf *lxc_conf, void *data) +static int __set_config_cgroup_controller(const char *key, const char *value, + struct lxc_conf *lxc_conf, int version) { - char *subkey; - char *token = "lxc.cgroup."; + const char *subkey, *token; + size_t token_len; struct lxc_list *cglist = NULL; struct lxc_cgroup *cgelem = NULL; if (lxc_config_value_empty(value)) - return lxc_clear_cgroups(lxc_conf, key); + return lxc_clear_cgroups(lxc_conf, key, version); - subkey = strstr(key, token); - if (!subkey) - return -1; + if (version == CGROUP2_SUPER_MAGIC) { + token = "lxc.cgroup2."; + token_len = 12; + } else if (version == CGROUP_SUPER_MAGIC) { + token = "lxc.cgroup."; + token_len = 11; + } else { + return -EINVAL; + } - if (!strlen(subkey)) - return -1; + if (strncmp(key, token, token_len) != 0) + return -EINVAL; - if (strlen(subkey) == strlen(token)) - return -1; - - subkey += strlen(token); + subkey = key + token_len; + if (*subkey == '\0') + return -EINVAL; cglist = malloc(sizeof(*cglist)); if (!cglist) @@ -1407,14 +1414,21 @@ static int set_config_cgroup_controller(const char *key, const char *value, memset(cgelem, 0, sizeof(*cgelem)); cgelem->subsystem = strdup(subkey); - cgelem->value = strdup(value); - - if (!cgelem->subsystem || !cgelem->value) + if (!cgelem->subsystem) goto out; - cglist->elem = cgelem; + cgelem->value = strdup(value); + if (!cgelem->value) + goto out; - lxc_list_add_tail(&lxc_conf->cgroup, cglist); + cgelem->version = version; + + lxc_list_add_elem(cglist, cgelem); + + if (version == CGROUP2_SUPER_MAGIC) + lxc_list_add_tail(&lxc_conf->cgroup2, cglist); + else + lxc_list_add_tail(&lxc_conf->cgroup, cglist); return 0; @@ -1429,6 +1443,21 @@ out: return -1; } +static int set_config_cgroup_controller(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + return __set_config_cgroup_controller(key, value, lxc_conf, + CGROUP_SUPER_MAGIC); +} + +static int set_config_cgroup2_controller(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + return __set_config_cgroup_controller(key, value, lxc_conf, + CGROUP2_SUPER_MAGIC); +} + + static int set_config_cgroup_dir(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { @@ -2910,11 +2939,14 @@ static int get_config_selinux_context(const char *key, char *retv, int inlen, * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in * 'lxc.cgroup.subsystem.key = value' format. */ -static int get_config_cgroup_controller(const char *key, char *retv, int inlen, - struct lxc_conf *c, void *data) +static int __get_config_cgroup_controller(const char *key, char *retv, + int inlen, struct lxc_conf *c, + int version) { - struct lxc_list *it; int len; + size_t namespaced_token_len; + char *global_token, *namespaced_token; + struct lxc_list *it; int fulllen = 0; bool get_all = false; @@ -2923,10 +2955,22 @@ static int get_config_cgroup_controller(const char *key, char *retv, int inlen, else memset(retv, 0, inlen); - if (!strcmp(key, "lxc.cgroup")) + if (version == CGROUP2_SUPER_MAGIC) { + global_token = "lxc.cgroup2"; + namespaced_token = "lxc.cgroup2."; + namespaced_token_len = sizeof("lxc.cgroup2.") - 1;; + } else if (version == CGROUP_SUPER_MAGIC) { + global_token = "lxc.cgroup"; + namespaced_token = "lxc.cgroup."; + namespaced_token_len = sizeof("lxc.cgroup.") - 1;; + } else { + return -1; + } + + if (strcmp(key, global_token) == 0) get_all = true; - else if (!strncmp(key, "lxc.cgroup.", 11)) - key += 11; + else if (strncmp(key, namespaced_token, namespaced_token_len) == 0) + key += namespaced_token_len; else return -1; @@ -2934,8 +2978,11 @@ static int get_config_cgroup_controller(const char *key, char *retv, int inlen, struct lxc_cgroup *cg = it->elem; if (get_all) { - strprint(retv, inlen, "lxc.cgroup.%s = %s\n", - cg->subsystem, cg->value); + if (version != cg->version) + continue; + + strprint(retv, inlen, "%s.%s = %s\n", + global_token, cg->subsystem, cg->value); } else if (!strcmp(cg->subsystem, key)) { strprint(retv, inlen, "%s\n", cg->value); } @@ -2944,6 +2991,20 @@ static int get_config_cgroup_controller(const char *key, char *retv, int inlen, return fulllen; } +static int get_config_cgroup_controller(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + return __get_config_cgroup_controller(key, retv, inlen, c, + CGROUP_SUPER_MAGIC); +} + +static int get_config_cgroup2_controller(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + return __get_config_cgroup_controller(key, retv, inlen, c, + CGROUP2_SUPER_MAGIC); +} + static int get_config_cgroup_dir(const char *key, char *retv, int inlen, struct lxc_conf *lxc_conf, void *data) { @@ -3632,7 +3693,13 @@ static inline int clr_config_selinux_context(const char *key, static inline int clr_config_cgroup_controller(const char *key, struct lxc_conf *c, void *data) { - return lxc_clear_cgroups(c, key); + return lxc_clear_cgroups(c, key, CGROUP_SUPER_MAGIC); +} + +static inline int clr_config_cgroup2_controller(const char *key, + struct lxc_conf *c, void *data) +{ + return lxc_clear_cgroups(c, key, CGROUP2_SUPER_MAGIC); } static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,