mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-09 12:43:43 +00:00
Merge pull request #2117 from brauner/2018-01-26/cgroup_v2_support
cgroups: add unified hierarchy support
This commit is contained in:
commit
3fb8253d91
@ -1330,17 +1330,31 @@ dev/null proc/kcore none bind,relative 0 0
|
|||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option>lxc.cgroup.[subsystem name]</option>
|
<option>lxc.cgroup.[controller name]</option>
|
||||||
</term>
|
</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
specify the control group value to be set. The
|
Specify the control group value to be set on a legacy cgroup
|
||||||
subsystem name is the literal name of the control group
|
hierarchy. The controller name is the literal name of the control
|
||||||
subsystem. The permitted names and the syntax of their
|
group. The permitted names and the syntax of their values is not
|
||||||
values is not dictated by LXC, instead it depends on the
|
dictated by LXC, instead it depends on the features of the Linux
|
||||||
features of the Linux kernel running at the time the
|
kernel running at the time the container is started, eg.
|
||||||
container is started,
|
<option>lxc.cgroup.cpuset.cpus</option>
|
||||||
eg. <option>lxc.cgroup.cpuset.cpus</option>
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>lxc.cgroup2.[controller name]</option>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
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.
|
||||||
|
<option>lxc.cgroup2.memory.high</option>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -2525,14 +2525,14 @@ static bool cgfs_unfreeze(void *hdata)
|
|||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cgroupfs_setup_limits(void *hdata, struct lxc_list *cgroup_conf,
|
static bool cgroupfs_setup_limits(void *hdata, struct lxc_conf *conf,
|
||||||
bool with_devices)
|
bool with_devices)
|
||||||
{
|
{
|
||||||
struct cgfs_data *d = hdata;
|
struct cgfs_data *d = hdata;
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
return false;
|
return false;
|
||||||
return do_setup_cgroup_limits(d, cgroup_conf, with_devices) == 0;
|
return do_setup_cgroup_limits(d, &conf->cgroup, with_devices) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
|
static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1479,11 +1479,12 @@ static bool cgm_unfreeze(void *hdata)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
|
static bool cgm_setup_limits(void *hdata, struct lxc_conf *conf, bool do_devices)
|
||||||
{
|
{
|
||||||
struct cgm_data *d = hdata;
|
struct cgm_data *d = hdata;
|
||||||
struct lxc_list *iterator, *sorted_cgroup_settings, *next;
|
struct lxc_list *iterator, *sorted_cgroup_settings, *next;
|
||||||
struct lxc_cgroup *cg;
|
struct lxc_cgroup *cg;
|
||||||
|
struct lxc_list *cgroup_settings = &conf->cgroup;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (lxc_list_empty(cgroup_settings))
|
if (lxc_list_empty(cgroup_settings))
|
||||||
|
@ -150,7 +150,7 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
|
|||||||
{
|
{
|
||||||
if (ops)
|
if (ops)
|
||||||
return ops->setup_limits(handler->cgroup_data,
|
return ops->setup_limits(handler->cgroup_data,
|
||||||
&handler->conf->cgroup, with_devices);
|
handler->conf, with_devices);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,13 @@ struct lxc_handler;
|
|||||||
struct lxc_conf;
|
struct lxc_conf;
|
||||||
struct lxc_list;
|
struct lxc_list;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CGROUP_LAYOUT_UNKNOWN = -1,
|
||||||
|
CGROUP_LAYOUT_LEGACY = 0,
|
||||||
|
CGROUP_LAYOUT_HYBRID = 1,
|
||||||
|
CGROUP_LAYOUT_UNIFIED = 2,
|
||||||
|
} cgroup_layout_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CGFS,
|
CGFS,
|
||||||
CGMANAGER,
|
CGMANAGER,
|
||||||
@ -53,7 +60,7 @@ struct cgroup_ops {
|
|||||||
int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
|
int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
|
||||||
int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
|
int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
|
||||||
bool (*unfreeze)(void *hdata);
|
bool (*unfreeze)(void *hdata);
|
||||||
bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
|
bool (*setup_limits)(void *hdata, struct lxc_conf *conf, bool with_devices);
|
||||||
bool (*chown)(void *hdata, struct lxc_conf *conf);
|
bool (*chown)(void *hdata, struct lxc_conf *conf);
|
||||||
bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
|
bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
|
||||||
bool (*mount_cgroup)(void *hdata, const char *root, int type);
|
bool (*mount_cgroup)(void *hdata, const char *root, int type);
|
||||||
@ -73,7 +80,8 @@ extern bool cgroup_enter(struct lxc_handler *handler);
|
|||||||
extern void cgroup_cleanup(struct lxc_handler *handler);
|
extern void cgroup_cleanup(struct lxc_handler *handler);
|
||||||
extern bool cgroup_create_legacy(struct lxc_handler *handler);
|
extern bool cgroup_create_legacy(struct lxc_handler *handler);
|
||||||
extern int cgroup_nrtasks(struct lxc_handler *handler);
|
extern int cgroup_nrtasks(struct lxc_handler *handler);
|
||||||
extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
|
extern const char *cgroup_get_cgroup(struct lxc_handler *handler,
|
||||||
|
const char *subsystem);
|
||||||
extern bool cgroup_escape();
|
extern bool cgroup_escape();
|
||||||
extern int cgroup_num_hierarchies();
|
extern int cgroup_num_hierarchies();
|
||||||
extern bool cgroup_get_hierarchies(int i, char ***out);
|
extern bool cgroup_get_hierarchies(int i, char ***out);
|
||||||
|
@ -35,12 +35,12 @@
|
|||||||
int get_cgroup_version(char *line)
|
int get_cgroup_version(char *line)
|
||||||
{
|
{
|
||||||
if (is_cgroupfs_v1(line))
|
if (is_cgroupfs_v1(line))
|
||||||
return CGROUP_V1;
|
return CGROUP_SUPER_MAGIC;
|
||||||
|
|
||||||
if (is_cgroupfs_v2(line))
|
if (is_cgroupfs_v2(line))
|
||||||
return CGROUP_V2;
|
return CGROUP2_SUPER_MAGIC;
|
||||||
|
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_cgroupfs_v1(char *line)
|
bool is_cgroupfs_v1(char *line)
|
||||||
|
@ -28,10 +28,6 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define CGROUP_V1 0
|
|
||||||
#define CGROUP_V2 1
|
|
||||||
#define LXCFS_CGROUP 2
|
|
||||||
|
|
||||||
/* Retrieve the cgroup version of a given entry from /proc/<pid>/mountinfo. */
|
/* Retrieve the cgroup version of a given entry from /proc/<pid>/mountinfo. */
|
||||||
extern int get_cgroup_version(char *line);
|
extern int get_cgroup_version(char *line);
|
||||||
|
|
||||||
|
@ -445,11 +445,16 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
|
|||||||
struct lxc_cmd_rr cmd = {
|
struct lxc_cmd_rr cmd = {
|
||||||
.req = {
|
.req = {
|
||||||
.cmd = LXC_CMD_GET_CGROUP,
|
.cmd = LXC_CMD_GET_CGROUP,
|
||||||
.datalen = strlen(subsystem) + 1,
|
|
||||||
.data = subsystem,
|
.data = subsystem,
|
||||||
|
.datalen = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cmd.req.data = subsystem;
|
||||||
|
cmd.req.datalen = 0;
|
||||||
|
if (subsystem)
|
||||||
|
cmd.req.datalen = strlen(subsystem) + 1;
|
||||||
|
|
||||||
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
|
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -469,10 +474,10 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
|
|||||||
const char *path;
|
const char *path;
|
||||||
struct lxc_cmd_rsp rsp;
|
struct lxc_cmd_rsp rsp;
|
||||||
|
|
||||||
if (req->datalen < 1)
|
if (req->datalen > 0)
|
||||||
return -1;
|
|
||||||
|
|
||||||
path = cgroup_get_cgroup(handler, req->data);
|
path = cgroup_get_cgroup(handler, req->data);
|
||||||
|
else
|
||||||
|
path = cgroup_get_cgroup(handler, NULL);
|
||||||
if (!path)
|
if (!path)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -2555,6 +2555,7 @@ struct lxc_conf *lxc_conf_init(void)
|
|||||||
}
|
}
|
||||||
new->logfd = -1;
|
new->logfd = -1;
|
||||||
lxc_list_init(&new->cgroup);
|
lxc_list_init(&new->cgroup);
|
||||||
|
lxc_list_init(&new->cgroup2);
|
||||||
lxc_list_init(&new->network);
|
lxc_list_init(&new->network);
|
||||||
lxc_list_init(&new->mount_list);
|
lxc_list_init(&new->mount_list);
|
||||||
lxc_list_init(&new->caps);
|
lxc_list_init(&new->caps);
|
||||||
@ -3446,23 +3447,38 @@ int lxc_clear_config_keepcaps(struct lxc_conf *c)
|
|||||||
return 0;
|
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;
|
char *global_token, *namespaced_token;
|
||||||
bool all = false;
|
struct lxc_list *it, *next, *list;
|
||||||
const char *k = NULL;
|
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;
|
all = true;
|
||||||
else if (strncmp(key, "lxc.cgroup.", sizeof("lxc.cgroup.") - 1) == 0)
|
else if (strncmp(key, namespaced_token, sizeof(namespaced_token) - 1) == 0)
|
||||||
k = key + sizeof("lxc.cgroup.") - 1;
|
k = key + sizeof(namespaced_token) - 1;
|
||||||
else
|
else
|
||||||
return -1;
|
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;
|
struct lxc_cgroup *cg = it->elem;
|
||||||
|
|
||||||
if (!all && strcmp(cg->subsystem, k) != 0)
|
if (!all && strcmp(cg->subsystem, k) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lxc_list_del(it);
|
lxc_list_del(it);
|
||||||
free(cg->subsystem);
|
free(cg->subsystem);
|
||||||
free(cg->value);
|
free(cg->value);
|
||||||
@ -3680,7 +3696,8 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|||||||
lxc_seccomp_free(conf);
|
lxc_seccomp_free(conf);
|
||||||
lxc_clear_config_caps(conf);
|
lxc_clear_config_caps(conf);
|
||||||
lxc_clear_config_keepcaps(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_hooks(conf, "lxc.hook");
|
||||||
lxc_clear_mount_entries(conf);
|
lxc_clear_mount_entries(conf);
|
||||||
lxc_clear_idmaps(conf);
|
lxc_clear_idmaps(conf);
|
||||||
|
@ -52,6 +52,8 @@ typedef void * scmp_filter_ctx;
|
|||||||
* programmer to specify the right subsystem.
|
* programmer to specify the right subsystem.
|
||||||
* @subsystem : the targeted subsystem
|
* @subsystem : the targeted subsystem
|
||||||
* @value : the value to set
|
* @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.
|
* @controllers : The controllers to use for this container.
|
||||||
* @dir : The name of the directory containing the container's cgroup.
|
* @dir : The name of the directory containing the container's cgroup.
|
||||||
@ -61,6 +63,7 @@ struct lxc_cgroup {
|
|||||||
union {
|
union {
|
||||||
/* information about a specific controller */
|
/* information about a specific controller */
|
||||||
struct /* controller */ {
|
struct /* controller */ {
|
||||||
|
int version;
|
||||||
char *subsystem;
|
char *subsystem;
|
||||||
char *value;
|
char *value;
|
||||||
};
|
};
|
||||||
@ -282,7 +285,10 @@ struct lxc_conf {
|
|||||||
int reboot;
|
int reboot;
|
||||||
signed long personality;
|
signed long personality;
|
||||||
struct utsname *utsname;
|
struct utsname *utsname;
|
||||||
|
struct {
|
||||||
struct lxc_list cgroup;
|
struct lxc_list cgroup;
|
||||||
|
struct lxc_list cgroup2;
|
||||||
|
};
|
||||||
struct {
|
struct {
|
||||||
struct lxc_list id_map;
|
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 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_caps(struct lxc_conf *c);
|
||||||
extern int lxc_clear_config_keepcaps(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_mount_entries(struct lxc_conf *c);
|
||||||
extern int lxc_clear_automounts(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);
|
extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
|
||||||
|
@ -81,6 +81,7 @@ lxc_config_define(apparmor_profile);
|
|||||||
lxc_config_define(cap_drop);
|
lxc_config_define(cap_drop);
|
||||||
lxc_config_define(cap_keep);
|
lxc_config_define(cap_keep);
|
||||||
lxc_config_define(cgroup_controller);
|
lxc_config_define(cgroup_controller);
|
||||||
|
lxc_config_define(cgroup2_controller);
|
||||||
lxc_config_define(cgroup_dir);
|
lxc_config_define(cgroup_dir);
|
||||||
lxc_config_define(console_logfile);
|
lxc_config_define(console_logfile);
|
||||||
lxc_config_define(console_rotate);
|
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.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.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.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.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.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, },
|
{ "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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_config_cgroup_controller(const char *key, const char *value,
|
static int __set_config_cgroup_controller(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, int version)
|
||||||
{
|
{
|
||||||
char *subkey;
|
const char *subkey, *token;
|
||||||
char *token = "lxc.cgroup.";
|
size_t token_len;
|
||||||
struct lxc_list *cglist = NULL;
|
struct lxc_list *cglist = NULL;
|
||||||
struct lxc_cgroup *cgelem = NULL;
|
struct lxc_cgroup *cgelem = NULL;
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
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 (version == CGROUP2_SUPER_MAGIC) {
|
||||||
if (!subkey)
|
token = "lxc.cgroup2.";
|
||||||
return -1;
|
token_len = 12;
|
||||||
|
} else if (version == CGROUP_SUPER_MAGIC) {
|
||||||
|
token = "lxc.cgroup.";
|
||||||
|
token_len = 11;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strlen(subkey))
|
if (strncmp(key, token, token_len) != 0)
|
||||||
return -1;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strlen(subkey) == strlen(token))
|
subkey = key + token_len;
|
||||||
return -1;
|
if (*subkey == '\0')
|
||||||
|
return -EINVAL;
|
||||||
subkey += strlen(token);
|
|
||||||
|
|
||||||
cglist = malloc(sizeof(*cglist));
|
cglist = malloc(sizeof(*cglist));
|
||||||
if (!cglist)
|
if (!cglist)
|
||||||
@ -1407,13 +1414,20 @@ static int set_config_cgroup_controller(const char *key, const char *value,
|
|||||||
memset(cgelem, 0, sizeof(*cgelem));
|
memset(cgelem, 0, sizeof(*cgelem));
|
||||||
|
|
||||||
cgelem->subsystem = strdup(subkey);
|
cgelem->subsystem = strdup(subkey);
|
||||||
cgelem->value = strdup(value);
|
if (!cgelem->subsystem)
|
||||||
|
|
||||||
if (!cgelem->subsystem || !cgelem->value)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
cglist->elem = cgelem;
|
cgelem->value = strdup(value);
|
||||||
|
if (!cgelem->value)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
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);
|
lxc_list_add_tail(&lxc_conf->cgroup, cglist);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1429,6 +1443,21 @@ out:
|
|||||||
return -1;
|
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,
|
static int set_config_cgroup_dir(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
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
|
* If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
|
||||||
* 'lxc.cgroup.subsystem.key = value' format.
|
* 'lxc.cgroup.subsystem.key = value' format.
|
||||||
*/
|
*/
|
||||||
static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
|
static int __get_config_cgroup_controller(const char *key, char *retv,
|
||||||
struct lxc_conf *c, void *data)
|
int inlen, struct lxc_conf *c,
|
||||||
|
int version)
|
||||||
{
|
{
|
||||||
struct lxc_list *it;
|
|
||||||
int len;
|
int len;
|
||||||
|
size_t namespaced_token_len;
|
||||||
|
char *global_token, *namespaced_token;
|
||||||
|
struct lxc_list *it;
|
||||||
int fulllen = 0;
|
int fulllen = 0;
|
||||||
bool get_all = false;
|
bool get_all = false;
|
||||||
|
|
||||||
@ -2923,10 +2955,22 @@ static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
|
|||||||
else
|
else
|
||||||
memset(retv, 0, inlen);
|
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;
|
get_all = true;
|
||||||
else if (!strncmp(key, "lxc.cgroup.", 11))
|
else if (strncmp(key, namespaced_token, namespaced_token_len) == 0)
|
||||||
key += 11;
|
key += namespaced_token_len;
|
||||||
else
|
else
|
||||||
return -1;
|
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;
|
struct lxc_cgroup *cg = it->elem;
|
||||||
|
|
||||||
if (get_all) {
|
if (get_all) {
|
||||||
strprint(retv, inlen, "lxc.cgroup.%s = %s\n",
|
if (version != cg->version)
|
||||||
cg->subsystem, cg->value);
|
continue;
|
||||||
|
|
||||||
|
strprint(retv, inlen, "%s.%s = %s\n",
|
||||||
|
global_token, cg->subsystem, cg->value);
|
||||||
} else if (!strcmp(cg->subsystem, key)) {
|
} else if (!strcmp(cg->subsystem, key)) {
|
||||||
strprint(retv, inlen, "%s\n", cg->value);
|
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;
|
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,
|
static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
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,
|
static inline int clr_config_cgroup_controller(const char *key,
|
||||||
struct lxc_conf *c, void *data)
|
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,
|
static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
|
||||||
|
@ -2307,6 +2307,33 @@ char *must_make_path(const char *first, ...)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *must_append_path(char *first, ...)
|
||||||
|
{
|
||||||
|
char *cur;
|
||||||
|
size_t full_len;
|
||||||
|
va_list args;
|
||||||
|
char *dest = first;
|
||||||
|
|
||||||
|
full_len = strlen(first);
|
||||||
|
va_start(args, first);
|
||||||
|
while ((cur = va_arg(args, char *)) != NULL) {
|
||||||
|
full_len += strlen(cur);
|
||||||
|
|
||||||
|
if (cur[0] != '/')
|
||||||
|
full_len++;
|
||||||
|
|
||||||
|
dest = must_realloc(dest, full_len + 1);
|
||||||
|
|
||||||
|
if (cur[0] != '/')
|
||||||
|
strcat(dest, "/");
|
||||||
|
|
||||||
|
strcat(dest, cur);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
char *must_copy_string(const char *entry)
|
char *must_copy_string(const char *entry)
|
||||||
{
|
{
|
||||||
char *ret;
|
char *ret;
|
||||||
|
@ -86,6 +86,14 @@
|
|||||||
#define CAP_SYS_ADMIN 21
|
#define CAP_SYS_ADMIN 21
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CGROUP_SUPER_MAGIC
|
||||||
|
#define CGROUP_SUPER_MAGIC 0x27e0eb
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CGROUP2_SUPER_MAGIC
|
||||||
|
#define CGROUP2_SUPER_MAGIC 0x63677270
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Useful macros */
|
/* Useful macros */
|
||||||
/* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
|
/* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
|
||||||
#define LXC_NUMSTRLEN64 21
|
#define LXC_NUMSTRLEN64 21
|
||||||
@ -529,7 +537,8 @@ extern int run_command(char *buf, size_t buf_size, int (*child_fn)(void *),
|
|||||||
/* Concatenate all passed-in strings into one path. Do not fail. If any piece
|
/* Concatenate all passed-in strings into one path. Do not fail. If any piece
|
||||||
* is not prefixed with '/', add a '/'.
|
* is not prefixed with '/', add a '/'.
|
||||||
*/
|
*/
|
||||||
extern char *must_make_path(const char *first, ...) __attribute__((sentinel));
|
__attribute__((sentinel)) extern char *must_make_path(const char *first, ...);
|
||||||
|
__attribute__((sentinel)) extern char *must_append_path(char *first, ...);
|
||||||
|
|
||||||
/* return copy of string @entry; do not fail. */
|
/* return copy of string @entry; do not fail. */
|
||||||
extern char *must_copy_string(const char *entry);
|
extern char *must_copy_string(const char *entry);
|
||||||
|
Loading…
Reference in New Issue
Block a user