Commit c80a84f8 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

cg: Add ability to dump custom cgroup properties

We have some common predefined properties such as "cpuset.cpus" and etc gathered
in @cgp_predefined set, but there might be situation when only predefined ones
are not enough, so add ability to specify properties via --cgroup-props
and/or --cgroup-props-file options.

For example one may pass file with content

"cpu":
 - "strategy": "merge"
 - "properties": ["cpu.shares", "cpu.cfs_period_us"]

to dump custom properties for cpu controller.

The description is implemented in almost valid yaml, probably we will
need to support the various forms, but oneline is enough for now.
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent ee0d1be1
...@@ -5,6 +5,7 @@ obj-y += aio.o ...@@ -5,6 +5,7 @@ obj-y += aio.o
obj-y += bfd.o obj-y += bfd.o
obj-y += bitmap.o obj-y += bitmap.o
obj-y += cgroup.o obj-y += cgroup.o
obj-y += cgroup-props.o
obj-y += cr-check.o obj-y += cr-check.o
obj-y += cr-dedup.o obj-y += cr-dedup.o
obj-y += cr-dump.o obj-y += cr-dump.o
......
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "compiler.h"
#include "cgroup-props.h"
#include "cr_options.h"
#include "config.h"
#include "xmalloc.h"
#include "string.h"
#include "util.h"
#include "list.h"
#include "log.h"
#include "bug.h"
#undef LOG_PREFIX
#define LOG_PREFIX "cg-prop: "
enum {
CGP_MERGE,
CGP_REPLACE,
};
static const char *____criu_global_props____[] = {
"cgroup.clone_children",
"notify_on_release",
"cgroup.procs",
"tasks",
};
cgp_t cgp_global = {
.name = "____criu_global_props____",
.nr_props = ARRAY_SIZE(____criu_global_props____),
.props = ____criu_global_props____,
};
typedef struct {
struct list_head list;
cgp_t cgp;
} cgp_list_entry_t;
static LIST_HEAD(cgp_list);
static void cgp_free(cgp_list_entry_t *p)
{
size_t i;
if (p) {
for (i = 0; i < p->cgp.nr_props; i++)
xfree((void *)p->cgp.props[i]);
xfree((void *)p->cgp.name);
xfree((void *)p->cgp.props);
xfree(p);
}
}
static int cgp_merge_props(cgp_list_entry_t *d, cgp_list_entry_t *s)
{
size_t nr_props, i, j;
nr_props = d->cgp.nr_props + s->cgp.nr_props;
if (xrealloc_safe(&d->cgp.props, nr_props * sizeof(char *)))
return -ENOMEM;
/*
* FIXME: Check for duplicates in propties?
*/
for (i = d->cgp.nr_props, j = 0; i < nr_props; i++, j++) {
d->cgp.props[i] = xstrdup(s->cgp.props[j]);
if (!d->cgp.props[i])
return -ENOMEM;
d->cgp.nr_props++;
}
return 0;
}
static int cgp_handle_props(cgp_list_entry_t *p, int strategy)
{
cgp_list_entry_t *t;
list_for_each_entry(t, &cgp_list, list) {
if (strcmp(t->cgp.name, p->cgp.name))
continue;
pr_debug("%s \"%s\" controller properties\n",
strategy == CGP_MERGE ?
"Merging" : "Replacing",
p->cgp.name);
if (strategy == CGP_MERGE) {
int ret;
ret = cgp_merge_props(t, p);
cgp_free(p);
return ret;
} else if (strategy == CGP_REPLACE) {
/*
* Simply drop out previous instance.
*/
list_del(&t->list);
cgp_free(t);
break;
} else
BUG();
}
/*
* New controller, simply add it.
*/
list_add(&p->list, &cgp_list);
return 0;
}
static char *skip_spaces(char **stream, size_t *len)
{
if (stream && *len) {
char *p = *stream;
while (p && *len && *p == ' ')
p++, (*len)--;
if (p != *stream)
*stream = p;
return p;
}
return NULL;
}
static bool eat_symbol(char **stream, size_t *len, char sym, bool skip_ws)
{
char *p = skip_ws ? skip_spaces(stream, len) : (stream ? *stream : NULL);
if (!p || *p != sym || !*len)
return false;
(*stream) = p + 1;
(*len)--;
return true;
}
static bool eat_symbols(char **stream, size_t *len, char *syms, size_t n_syms, bool skip_ws)
{
char *p = skip_ws ? skip_spaces(stream, len) : (stream ? *stream : NULL);
size_t i;
if (p && *len) {
char *stream_orig = *stream;
size_t len_orig = *len;
for (i = 0; i < n_syms; i++) {
if (!eat_symbol(stream, len, syms[i], false)) {
*stream = stream_orig;
*len = len_orig;
goto nomatch;
}
}
return true;
}
nomatch:
return false;
}
static bool eat_word(char **stream, size_t *len, char *word, size_t word_len, bool skip_ws)
{
char *p = skip_ws ? skip_spaces(stream, len) : (stream ? *stream : NULL);
if (p && *len >= word_len) {
if (!strncmp(p, word, word_len)) {
(*stream) += word_len;
(*len) -= word_len;
return true;
}
}
return false;
}
static char *get_quoted(char **stream, size_t *len, bool skip_ws)
{
char *p = skip_ws ? skip_spaces(stream, len) : (stream ? *stream : NULL);
char *from = p + 1;
char *dst;
if (!p || *p != '\"')
return NULL;
for (p = from, (*len)--; (*len); p++, (*len)--) {
if (*p == '\"') {
if (p == from)
break;
dst = xmalloc(p - from + 1);
if (!dst)
break;
memcpy(dst, from, p - from);
dst[p - from] = '\0';
(*stream) = p + 1;
(*len)--;
return dst;
}
}
return NULL;
}
static int cgp_parse_stream(char *stream, size_t len)
{
cgp_list_entry_t *cgp_entry = NULL;
int strategy;
int ret = 0;
char *p;
/*
* We expect the following format here
* (very simplified YAML!)
*
* "cpu":
* - "strategy": "replace"
* - "properties": ["cpu.shares", "cpu.cfs_period_us"]
* "memory":
* - "strategy": "merge"
* - "properties": ["memory.limit_in_bytes", "memory.memsw.limit_in_bytes"]
*
* and etc.
*/
while (len) {
/*
* Controller name.
*/
p = get_quoted(&stream, &len, false);
if (!p) {
pr_err("Expecting controller name\n");
goto err_parse;
}
pr_info("Parsing controller \"%s\"\n", p);
cgp_entry = xzalloc(sizeof(*cgp_entry));
if (cgp_entry) {
INIT_LIST_HEAD(&cgp_entry->list);
cgp_entry->cgp.name = p;
} else {
pr_err("Can't allocate memory for controller %s\n", p);
xfree(p);
return -ENOMEM;
}
if (!eat_symbols(&stream, &len, ":\n - ", 5, true)) {
pr_err("Expected \':\\n - \' sequence controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
if (!eat_word(&stream, &len, "\"strategy\":", 11, true)) {
pr_err("Expected \'stategy:\' keyword in controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
p = get_quoted(&stream, &len, true);
if (!p) {
pr_err("Expected strategy in controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
};
if (!strcmp(p, "merge")) {
strategy = CGP_MERGE;
} else if (!strcmp(p, "replace")) {
strategy = CGP_REPLACE;
} else {
xfree(p);
pr_err("Unknown strategy \"%s\" in controller's %s stream\n",
p, cgp_entry->cgp.name);
goto err_parse;
}
pr_info("\tStrategy \"%s\"\n", p);
xfree(p);
if (!eat_symbols(&stream, &len, "\n - ", 4, true)) {
pr_err("Expected \':\\n - \' sequence controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
if (!eat_word(&stream, &len, "\"properties\":", 13, true)) {
pr_err("Expected \"properties:\" keyword in controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
if (!eat_symbol(&stream, &len, '[', true)) {
pr_err("Expected \'[\' sequence controller's %s properties stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
while ((p = get_quoted(&stream, &len, true))) {
if (!p) {
pr_err("Expected property name for controller %s\n",
cgp_entry->cgp.name);
goto err_parse;
}
if (xrealloc_safe(&cgp_entry->cgp.props,
(cgp_entry->cgp.nr_props + 1) * sizeof(char *))) {
pr_err("Can't allocate property for controller %s\n",
cgp_entry->cgp.name);
return -1;
}
cgp_entry->cgp.props[cgp_entry->cgp.nr_props++] = p;
pr_info("\tProperty \"%s\"\n", p);
if (!eat_symbol(&stream, &len, ',', true)) {
if (stream[0] == ']') {
stream++, len--;
break;
}
pr_err("Expected ']' in controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
}
if (!eat_symbol(&stream, &len, '\n', true) && len) {
pr_err("Expected \'\\n\' symbol in controller's %s stream\n",
cgp_entry->cgp.name);
goto err_parse;
}
if (cgp_handle_props(cgp_entry, strategy))
goto err_parse;
cgp_entry = NULL;
}
ret = 0;
out:
return ret;
err_parse:
cgp_free(cgp_entry);
ret = -EINVAL;
goto out;
}
static int cgp_parse_file(char *path)
{
void *mem = MAP_FAILED;
int fd = -1, ret = -1;
struct stat st;
fd = open(path, O_RDONLY);
if (fd < 0) {
pr_perror("Can't open file %s\n", path);
goto err;
}
if (fstat(fd, &st)) {
pr_perror("Can't stat file %s\n", path);
goto err;
}
mem = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FILE, fd, 0);
if (mem == MAP_FAILED) {
pr_perror("Can't mmap file %s\n", path);
goto err;
}
if (cgp_parse_stream(mem, st.st_size)) {
pr_err("Failed to parse file `%s'\n", path);
goto err;
}
ret = 0;
err:
if (mem != MAP_FAILED)
munmap(mem, st.st_size);
close_safe(&fd);
return ret;
}
static int cgp_parse_builtins(void)
{
static const char predefined_stream[] =
"\"cpu\":\n"
" - \"strategy\": \"replace\"\n"
" - \"properties\": "
"[ "
"\"cpu.shares\", "
"\"cpu.cfs_period_us\", "
"\"cpu.cfs_quota_us\", "
"\"cpu.rt_period_us\", "
"\"cpu.rt_runtime_us\", "
"\"notify_on_release\" "
"]\n"
/* limit_in_bytes and memsw.limit_in_bytes must be set in this order */
"\"memory\":\n"
" - \"strategy\": \"replace\"\n"
" - \"properties\": "
"[ "
"\"memory.limit_in_bytes\", "
"\"memory.memsw.limit_in_bytes\", "
"\"memory.use_hierarchy\", "
"\"notify_on_release\" "
"]\n"
/*
* cpuset.cpus and cpuset.mems must be set before the process moves
* into its cgroup; they are "initialized" below to whatever the root
* values are in copy_special_cg_props so as not to cause ENOSPC when
* values are restored via this code.
*/
"\"cpuset\":\n"
" - \"strategy\": \"replace\"\n"
" - \"properties\": "
"[ "
"\"cpuset.cpus\", "
"\"cpuset.mems\", "
"\"cpuset.memory_migrate\", "
"\"cpuset.cpu_exclusive\", "
"\"cpuset.mem_exclusive\", "
"\"cpuset.mem_hardwall\", "
"\"cpuset.memory_spread_page\", "
"\"cpuset.memory_spread_slab\", "
"\"cpuset.sched_load_balance\", "
"\"cpuset.sched_relax_domain_level\", "
"\"notify_on_release\" "
"]\n"
"\"blkio\":\n"
" - \"strategy\": \"replace\"\n"
" - \"properties\": "
"[ "
"\"blkio.weight\", "
"\"notify_on_release\" "
"]\n"
"\"freezer\":\n"
" - \"strategy\": \"replace\"\n"
" - \"properties\": "
"[ "
"\"notify_on_release\" "
"]\n";
return cgp_parse_stream((void *)predefined_stream,
strlen(predefined_stream));
}
int cgp_init(char *stream, size_t len, char *path)
{
int ret;
ret = cgp_parse_builtins();
if (ret)
goto err;
if (stream && len) {
ret = cgp_parse_stream(stream, len);
if (ret)
goto err;
}
if (path)
ret = cgp_parse_file(path);
err:
return ret;
}
bool cgp_should_skip_controller(const char *name)
{
/*
* FIXME Implement!
*/
return false;
}
const cgp_t *cgp_get_props(const char *name)
{
cgp_list_entry_t *p;
list_for_each_entry(p, &cgp_list, list) {
if (!strcmp(p->cgp.name, name))
return &p->cgp;
}
return NULL;
}
void cgp_fini(void)
{
cgp_list_entry_t *p, *t;
list_for_each_entry_safe(p, t, &cgp_list, list)
cgp_free(p);
INIT_LIST_HEAD(&cgp_list);
}
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "list.h" #include "list.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "cgroup.h" #include "cgroup.h"
#include "cgroup-props.h"
#include "cr_options.h" #include "cr_options.h"
#include "pstree.h" #include "pstree.h"
#include "proc_parse.h" #include "proc_parse.h"
...@@ -24,73 +25,6 @@ ...@@ -24,73 +25,6 @@
#include "images/core.pb-c.h" #include "images/core.pb-c.h"
#include "images/cgroup.pb-c.h" #include "images/cgroup.pb-c.h"
/*
* These string arrays have the names of all the properties that will be
* restored. To add a property for a cgroup type, add it to the
* corresponding char array above the NULL terminator. If you are adding
* a new cgroup family all together, you must also edit get_known_properties()
* Currently the code only supports properties with 1 value
*/
static const char *cpu_props[] = {
"cpu.shares",
"cpu.cfs_period_us",
"cpu.cfs_quota_us",
"cpu.rt_period_us",
"cpu.rt_runtime_us",
"notify_on_release",
NULL
};
static const char *memory_props[] = {
/* limit_in_bytes and memsw.limit_in_bytes must be set in this order */
"memory.limit_in_bytes",
"memory.memsw.limit_in_bytes",
"memory.use_hierarchy",
"notify_on_release",
NULL
};
static const char *cpuset_props[] = {
/*
* cpuset.cpus and cpuset.mems must be set before the process moves
* into its cgroup; they are "initialized" below to whatever the root
* values are in copy_special_cg_props so as not to cause ENOSPC when
* values are restored via this code.
*/
"cpuset.cpus",
"cpuset.mems",
"cpuset.memory_migrate",
"cpuset.cpu_exclusive",
"cpuset.mem_exclusive",
"cpuset.mem_hardwall",
"cpuset.memory_spread_page",
"cpuset.memory_spread_slab",
"cpuset.sched_load_balance",
"cpuset.sched_relax_domain_level",
"notify_on_release",
NULL
};
static const char *blkio_props[] = {
"blkio.weight",
"notify_on_release",
NULL
};
static const char *freezer_props[] = {
"notify_on_release",
NULL
};
static const char *global_props[] = {
"cgroup.clone_children",
"notify_on_release",
"cgroup.procs",
"tasks",
NULL
};
/* /*
* This structure describes set of controller groups * This structure describes set of controller groups
* a task lives in. The cg_ctl entries are stored in * a task lives in. The cg_ctl entries are stored in
...@@ -421,33 +355,14 @@ static void free_all_cgroup_props(struct cgroup_dir *ncd) ...@@ -421,33 +355,14 @@ static void free_all_cgroup_props(struct cgroup_dir *ncd)
ncd->n_properties = 0; ncd->n_properties = 0;
} }
static const char **get_known_properties(char *controller) static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd, const cgp_t *cgp)
{
const char **prop_arr = NULL;
if (!strcmp(controller, "cpu"))
prop_arr = cpu_props;
else if (!strcmp(controller, "memory"))
prop_arr = memory_props;
else if (!strcmp(controller, "cpuset"))
prop_arr = cpuset_props;
else if (!strcmp(controller, "blkio"))
prop_arr = blkio_props;
else if (!strcmp(controller, "freezer"))
prop_arr = freezer_props;
return prop_arr;
}
static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd,
const char **prop_arr)
{ {
int j; int j;
char buf[PATH_MAX]; char buf[PATH_MAX];
struct cgroup_prop *prop; struct cgroup_prop *prop;
for (j = 0; prop_arr != NULL && prop_arr[j] != NULL; ++j) { for (j = 0; cgp && j < cgp->nr_props; j++) {
if (snprintf(buf, PATH_MAX, "%s/%s", fpath, prop_arr[j]) >= PATH_MAX) { if (snprintf(buf, PATH_MAX, "%s/%s", fpath, cgp->props[j]) >= PATH_MAX) {
pr_err("snprintf output was truncated\n"); pr_err("snprintf output was truncated\n");
return -1; return -1;
} }
...@@ -457,7 +372,7 @@ static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd, ...@@ -457,7 +372,7 @@ static int dump_cg_props_array(const char *fpath, struct cgroup_dir *ncd,
continue; continue;
} }
prop = create_cgroup_prop(prop_arr[j]); prop = create_cgroup_prop(cgp->props[j]);
if (!prop) { if (!prop) {
free_all_cgroup_props(ncd); free_all_cgroup_props(ncd);
return -1; return -1;
...@@ -483,15 +398,14 @@ static int add_cgroup_properties(const char *fpath, struct cgroup_dir *ncd, ...@@ -483,15 +398,14 @@ static int add_cgroup_properties(const char *fpath, struct cgroup_dir *ncd,
int i; int i;
for (i = 0; i < controller->n_controllers; ++i) { for (i = 0; i < controller->n_controllers; ++i) {
const cgp_t *cgp = cgp_get_props(controller->controllers[i]);
const char **prop_arr = get_known_properties(controller->controllers[i]); if (dump_cg_props_array(fpath, ncd, cgp) < 0) {
if (dump_cg_props_array(fpath, ncd, prop_arr) < 0) {
pr_err("dumping known properties failed"); pr_err("dumping known properties failed");
return -1; return -1;
} }
if (dump_cg_props_array(fpath, ncd, global_props) < 0) { if (dump_cg_props_array(fpath, ncd, &cgp_global) < 0) {
pr_err("dumping global properties failed"); pr_err("dumping global properties failed");
return -1; return -1;
} }
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include "cpu.h" #include "cpu.h"
#include "elf.h" #include "elf.h"
#include "cgroup.h" #include "cgroup.h"
#include "cgroup-props.h"
#include "file-lock.h" #include "file-lock.h"
#include "page-xfer.h" #include "page-xfer.h"
#include "kerndat.h" #include "kerndat.h"
...@@ -1538,6 +1539,7 @@ static int cr_dump_finish(int ret) ...@@ -1538,6 +1539,7 @@ static int cr_dump_finish(int ret)
ret = -1; ret = -1;
cr_plugin_fini(CR_PLUGIN_STAGE__DUMP, ret); cr_plugin_fini(CR_PLUGIN_STAGE__DUMP, ret);
cgp_fini();
if (!ret) { if (!ret) {
/* /*
...@@ -1637,6 +1639,12 @@ int cr_dump_tasks(pid_t pid) ...@@ -1637,6 +1639,12 @@ int cr_dump_tasks(pid_t pid)
if (vdso_init()) if (vdso_init())
goto err; goto err;
if (cgp_init(opts.cgroup_props,
opts.cgroup_props ?
strlen(opts.cgroup_props) : 0,
opts.cgroup_props_file))
goto err;
if (parse_cg_info()) if (parse_cg_info())
goto err; goto err;
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "mount.h" #include "mount.h"
#include "namespaces.h" #include "namespaces.h"
#include "cgroup.h" #include "cgroup.h"
#include "cgroup-props.h"
#include "cpu.h" #include "cpu.h"
#include "action-scripts.h" #include "action-scripts.h"
#include "irmap.h" #include "irmap.h"
...@@ -275,6 +276,8 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -275,6 +276,8 @@ int main(int argc, char *argv[], char *envp[])
{ "extra", no_argument, 0, 1077 }, { "extra", no_argument, 0, 1077 },
{ "experimental", no_argument, 0, 1078 }, { "experimental", no_argument, 0, 1078 },
{ "all", no_argument, 0, 1079 }, { "all", no_argument, 0, 1079 },
{ "cgroup-props", required_argument, 0, 1080 },
{ "cgroup-props-file", required_argument, 0, 1081 },
{ }, { },
}; };
...@@ -569,6 +572,12 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -569,6 +572,12 @@ int main(int argc, char *argv[], char *envp[])
opts.check_extra_features = true; opts.check_extra_features = true;
opts.check_experimental_features = true; opts.check_experimental_features = true;
break; break;
case 1080:
opts.cgroup_props = optarg;
break;
case 1081:
opts.cgroup_props_file = optarg;
break;
case 'V': case 'V':
pr_msg("Version: %s\n", CRIU_VERSION); pr_msg("Version: %s\n", CRIU_VERSION);
if (strcmp(CRIU_GITID, "0")) if (strcmp(CRIU_GITID, "0"))
...@@ -806,6 +815,13 @@ usage: ...@@ -806,6 +815,13 @@ usage:
" change the root cgroup the controller will be\n" " change the root cgroup the controller will be\n"
" installed into. No controller means that root is the\n" " installed into. No controller means that root is the\n"
" default for all controllers not specified.\n" " default for all controllers not specified.\n"
" --cgroup-props STRING\n"
" define cgroup controllers and properties\n"
" to be checkpointed, which are described\n"
" via STRING using simplified YAML format.\n"
" --cgroup-props-file FILE\n"
" same as --cgroup-props but taking descrition\n"
" from the path specified.\n"
" --skip-mnt PATH ignore this mountpoint when dumping the mount namespace.\n" " --skip-mnt PATH ignore this mountpoint when dumping the mount namespace.\n"
" --enable-fs FSNAMES a comma separated list of filesystem names or \"all\".\n" " --enable-fs FSNAMES a comma separated list of filesystem names or \"all\".\n"
" force criu to (try to) dump/restore these filesystem's\n" " force criu to (try to) dump/restore these filesystem's\n"
......
#ifndef __CR_CGROUP_PROPS_H__
#define __CR_CGROUP_PROPS_H__
#include <stdbool.h>
typedef struct {
const char *name;
size_t nr_props;
const char **props;
} cgp_t;
extern cgp_t cgp_global;
extern const cgp_t *cgp_get_props(const char *name);
extern bool cgp_should_skip_controller(const char *name);
extern int cgp_init(char *stream, size_t len, char *path);
extern void cgp_fini(void);
#endif /* __CR_CGROUP_PROPS_H__ */
...@@ -95,6 +95,8 @@ struct cr_options { ...@@ -95,6 +95,8 @@ struct cr_options {
char **exec_cmd; char **exec_cmd;
unsigned int manage_cgroups; unsigned int manage_cgroups;
char *new_global_cg_root; char *new_global_cg_root;
char *cgroup_props;
char *cgroup_props_file;
struct list_head new_cgroup_roots; struct list_head new_cgroup_roots;
bool autodetect_ext_mounts; bool autodetect_ext_mounts;
bool enable_external_sharing; bool enable_external_sharing;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "namespaces.h" #include "namespaces.h"
#include "files-reg.h" #include "files-reg.h"
#include "cgroup.h" #include "cgroup.h"
#include "cgroup-props.h"
#include "protobuf.h" #include "protobuf.h"
#include "images/fdinfo.pb-c.h" #include "images/fdinfo.pb-c.h"
...@@ -2232,6 +2233,18 @@ int parse_cgroup_file(FILE *f, struct list_head *retl, unsigned int *n) ...@@ -2232,6 +2233,18 @@ int parse_cgroup_file(FILE *f, struct list_head *retl, unsigned int *n)
if (e) if (e)
*e = '\0'; *e = '\0';
/*
* Controllers and their props might be
* configured the way some of them are
* not taken into the image for migration
* sake or container specifics.
*/
if (cgp_should_skip_controller(name)) {
pr_debug("cg-prop: Skipping controller %s\n", name);
xfree(ncc);
continue;
}
ncc->name = xstrdup(name); ncc->name = xstrdup(name);
ncc->path = xstrdup(path); ncc->path = xstrdup(path);
ncc->cgns_prefix = 0; ncc->cgns_prefix = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment