Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBui Quang Minh <minhquangbui99@gmail.com>2022-09-04 10:46:33 +0300
committerAndrei Vagin <avagin@gmail.com>2022-11-02 07:35:04 +0300
commitf5ad26cf7da6e3302af46ecde93d17b4239c31f5 (patch)
tree8cec6775b0cf57cc9005391cb5b470f316b5abe4
parent83ed54b5498a012da0082057245a8bb959ec34a7 (diff)
cgroup-v2: Checkpoint and restore some global properties
This commit supports checkpoint/restore some new global properties in cgroup-v2 cgroup.subtree_control cgroup.max.descendants cgroup.max.depth cgroup.freeze cgroup.type Only cgroup.subtree_control, cgroup.type need some more code to handle. cgroup.subtree_control value needs to be set with "+", "-" prefix and cgroup.type can only be written with value "threaded" if we want to make this controller threaded. cgroup.type is a special property because this property must be restored before any processes can move into this controller. Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
-rw-r--r--criu/cgroup-props.c17
-rw-r--r--criu/cgroup.c108
-rw-r--r--criu/include/cgroup-props.h1
3 files changed, 116 insertions, 10 deletions
diff --git a/criu/cgroup-props.c b/criu/cgroup-props.c
index 5bed7dd9d..1b85c5b5a 100644
--- a/criu/cgroup-props.c
+++ b/criu/cgroup-props.c
@@ -35,12 +35,29 @@ static const char *____criu_global_props____[] = {
"tasks",
};
+/* cgroup2 global properties */
+// clang-format off
+static const char *____criu_global_props_v2____[] = {
+ "cgroup.subtree_control",
+ "cgroup.max.descendants",
+ "cgroup.max.depth",
+ "cgroup.freeze",
+ "cgroup.type",
+};
+// clang-format on
+
cgp_t cgp_global = {
.name = "____criu_global_props____",
.nr_props = ARRAY_SIZE(____criu_global_props____),
.props = ____criu_global_props____,
};
+cgp_t cgp_global_v2 = {
+ .name = "____criu_global_props_v2____",
+ .nr_props = ARRAY_SIZE(____criu_global_props_v2____),
+ .props = ____criu_global_props_v2____,
+};
+
typedef struct {
struct list_head list;
cgp_t cgp;
diff --git a/criu/cgroup.c b/criu/cgroup.c
index 6f6117c21..4f68836be 100644
--- a/criu/cgroup.c
+++ b/criu/cgroup.c
@@ -441,7 +441,15 @@ static int add_cgroup_properties(const char *fpath, struct cgroup_dir *ncd, stru
pr_err("dumping known properties failed\n");
return -1;
}
+ }
+ /* cgroup v2 */
+ if (controller->controllers[0][0] == 0) {
+ if (dump_cg_props_array(fpath, ncd, &cgp_global_v2) < 0) {
+ pr_err("dumping global properties v2 failed\n");
+ return -1;
+ }
+ } else {
if (dump_cg_props_array(fpath, ncd, &cgp_global) < 0) {
pr_err("dumping global properties failed\n");
return -1;
@@ -1061,8 +1069,15 @@ static int ctrl_dir_and_opt(CgControllerEntry *ctl, char *dir, int ds, char *opt
* it. We restore these properties as soon as the cgroup is created.
*/
static const char *special_props[] = {
- "cpuset.cpus", "cpuset.mems", "devices.list", "memory.kmem.limit_in_bytes",
- "memory.swappiness", "memory.oom_control", "memory.use_hierarchy", NULL,
+ "cpuset.cpus",
+ "cpuset.mems",
+ "devices.list",
+ "memory.kmem.limit_in_bytes",
+ "memory.swappiness",
+ "memory.oom_control",
+ "memory.use_hierarchy",
+ "cgroup.type",
+ NULL,
};
bool is_special_property(const char *prop)
@@ -1303,6 +1318,65 @@ static int restore_perms(int fd, const char *path, CgroupPerms *perms)
return 0;
}
+static int add_subtree_control_prop_prefix(char *input, char *output, char prefix)
+{
+ char *current, *next;
+ size_t len, off = 0;
+
+ current = input;
+ do {
+ next = strchrnul(current, ' ');
+ len = next - current;
+
+ output[off] = prefix;
+ off++;
+ memcpy(output + off, current, len);
+ off += len;
+ output[off] = ' ';
+ off++;
+
+ current = next + 1;
+ } while (*next != '\0');
+
+ return off;
+}
+
+static int restore_cgroup_subtree_control(const CgroupPropEntry *cg_prop_entry_p, int fd)
+{
+ char buf[1024];
+ char line[1024];
+ int ret, off = 0;
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ pr_perror("read from cgroup.subtree_control");
+ return ret;
+ }
+ /* Remove the trailing newline */
+ buf[ret] = '\0';
+
+ /* Remove all current subsys in subtree_control */
+ if (buf[0] != '\0')
+ off = add_subtree_control_prop_prefix(buf, line, '-');
+
+ /* Add subsys need to be restored in subtree_control */
+ if (cg_prop_entry_p->value[0] != '\0')
+ off += add_subtree_control_prop_prefix(cg_prop_entry_p->value, line + off, '+');
+
+ /* Remove the trailing space */
+ if (off != 0) {
+ off--;
+ line[off] = '\0';
+ }
+
+ if (write(fd, line, off) != off) {
+ pr_perror("write to cgroup.subtree_control");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Note: The path string can be modified in this function,
* the length of path string should be at least PATH_MAX.
@@ -1310,8 +1384,9 @@ static int restore_perms(int fd, const char *path, CgroupPerms *perms)
static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, char *path, int off, bool split_lines,
bool skip_fails)
{
- int cg, fd, ret = -1;
+ int cg, fd, ret = -1, flag;
CgroupPerms *perms = cg_prop_entry_p->perms;
+ int is_subtree_control = !strcmp(cg_prop_entry_p->name, "cgroup.subtree_control");
if (opts.manage_cgroups == CG_MODE_IGNORE)
return 0;
@@ -1328,8 +1403,13 @@ static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, char *pat
pr_info("Restoring cgroup property value [%s] to [%s]\n", cg_prop_entry_p->value, path);
+ if (is_subtree_control)
+ flag = O_RDWR;
+ else
+ flag = O_WRONLY;
+
cg = get_service_fd(CGROUP_YARD);
- fd = openat(cg, path, O_WRONLY);
+ fd = openat(cg, path, flag);
if (fd < 0) {
pr_perror("bad cgroup path: %s", path);
return -1;
@@ -1344,6 +1424,17 @@ static int restore_cgroup_prop(const CgroupPropEntry *cg_prop_entry_p, char *pat
goto out;
}
+ if (is_subtree_control) {
+ ret = restore_cgroup_subtree_control(cg_prop_entry_p, fd);
+ goto out;
+ }
+
+ /* skip restoring cgroup.type if its value is not "threaded" */
+ if (!strcmp(cg_prop_entry_p->name, "cgroup.type") && strcmp(cg_prop_entry_p->value, "threaded")) {
+ ret = 0;
+ goto out;
+ }
+
if (split_lines) {
char *line = cg_prop_entry_p->value;
char *next_line;
@@ -1688,12 +1779,9 @@ static int prepare_cgroup_dirs(char **controllers, int n_controllers, char *paux
return -1;
for (j = 0; j < n_controllers; j++) {
- if (!strcmp(controllers[j], "cpuset") || !strcmp(controllers[j], "memory") ||
- !strcmp(controllers[j], "devices")) {
- if (restore_special_props(paux, off2, e) < 0) {
- pr_err("Restoring special cpuset props failed!\n");
- return -1;
- }
+ if (restore_special_props(paux, off2, e) < 0) {
+ pr_err("Restoring special cpuset props failed!\n");
+ return -1;
}
}
} else {
diff --git a/criu/include/cgroup-props.h b/criu/include/cgroup-props.h
index 11b677548..10a7061b8 100644
--- a/criu/include/cgroup-props.h
+++ b/criu/include/cgroup-props.h
@@ -10,6 +10,7 @@ typedef struct {
} cgp_t;
extern cgp_t cgp_global;
+extern cgp_t cgp_global_v2;
extern const cgp_t *cgp_get_props(const char *name);
extern bool cgp_should_skip_controller(const char *name);
extern bool cgp_add_dump_controller(const char *name);