Commit 651ef4ef by Stéphane Graber Committed by GitHub

Merge pull request #1194 from tych0/cgroup-root-on-dump

Cgroup root on dump
parents 127a74d7 09e80d0c
......@@ -2363,28 +2363,6 @@ static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
}
static const char *cgfs_canonical_path(void *hdata)
{
struct cgfs_data *d = hdata;
struct cgroup_process_info *info_ptr;
char *path = NULL;
if (!d)
return NULL;
for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
if (!path)
path = info_ptr->cgroup_path;
else if (strcmp(path, info_ptr->cgroup_path) != 0) {
ERROR("not all paths match %s, %s has path %s", path,
info_ptr->hierarchy->subsystems[0], info_ptr->cgroup_path);
return NULL;
}
}
return path;
}
static bool cgfs_escape(void *hdata)
{
struct cgroup_meta_data *md;
......@@ -2434,6 +2412,18 @@ out:
return ret;
}
static int cgfs_num_hierarchies(void)
{
/* not implemented */
return -1;
}
static bool cgfs_get_hierarchies(int i, char ***out)
{
/* not implemented */
return false;
}
static bool cgfs_unfreeze(void *hdata)
{
struct cgfs_data *d = hdata;
......@@ -2625,8 +2615,9 @@ static struct cgroup_ops cgfs_ops = {
.enter = cgfs_enter,
.create_legacy = cgfs_create_legacy,
.get_cgroup = cgfs_get_cgroup,
.canonical_path = cgfs_canonical_path,
.escape = cgfs_escape,
.num_hierarchies = cgfs_num_hierarchies,
.get_hierarchies = cgfs_get_hierarchies,
.get = lxc_cgroupfs_get,
.set = lxc_cgroupfs_set,
.unfreeze = cgfs_unfreeze,
......
......@@ -1087,13 +1087,6 @@ out_free:
return false;
}
static const char *cgfsng_canonical_path(void *hdata)
{
struct cgfsng_handler_data *d = hdata;
return d->container_cgroup;
}
static bool cgfsng_enter(void *hdata, pid_t pid)
{
char pidstr[25];
......@@ -1426,19 +1419,11 @@ static int cgfsng_nrtasks(void *hdata) {
/* Only root needs to escape to the cgroup of its init */
static bool cgfsng_escape()
{
struct cgfsng_handler_data *d;
int i;
bool ret = false;
if (geteuid())
return true;
d = cgfsng_init("criu-temp-cgfsng");
if (!d) {
ERROR("cgfsng_init failed");
return false;
}
for (i = 0; hierarchies[i]; i++) {
char *fullpath = must_make_path(hierarchies[i]->mountpoint,
hierarchies[i]->base_cgroup,
......@@ -1446,15 +1431,37 @@ static bool cgfsng_escape()
if (lxc_write_to_file(fullpath, "0", 2, false) != 0) {
SYSERROR("Failed to escape to %s", fullpath);
free(fullpath);
goto out;
return false;
}
free(fullpath);
}
ret = true;
out:
free_handler_data(d);
return ret;
return true;
}
static int cgfsng_num_hierarchies(void)
{
int i;
for (i = 0; hierarchies[i]; i++)
;
return i;
}
static bool cgfsng_get_hierarchies(int n, char ***out)
{
int i;
/* sanity check n */
for (i = 0; i < n; i++) {
if (!hierarchies[i])
return false;
}
*out = hierarchies[i]->controllers;
return true;
}
#define THAWED "THAWED"
......@@ -1672,8 +1679,9 @@ static struct cgroup_ops cgfsng_ops = {
.destroy = cgfsng_destroy,
.create = cgfsng_create,
.enter = cgfsng_enter,
.canonical_path = cgfsng_canonical_path,
.escape = cgfsng_escape,
.num_hierarchies = cgfsng_num_hierarchies,
.get_hierarchies = cgfsng_get_hierarchies,
.get_cgroup = cgfsng_get_cgroup,
.get = cgfsng_get,
.set = cgfsng_set,
......
......@@ -337,6 +337,18 @@ static bool cgm_escape(void *hdata)
return ret;
}
static int cgm_num_hierarchies(void)
{
/* not implemented */
return -1;
}
static bool cgm_get_hierarchies(int i, char ***out)
{
/* not implemented */
return false;
}
struct chown_data {
const char *cgroup_path;
uid_t origuid;
......@@ -734,15 +746,6 @@ static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
return d->cgroup_path;
}
static const char *cgm_canonical_path(void *hdata)
{
struct cgm_data *d = hdata;
if (!d || !d->cgroup_path)
return NULL;
return d->cgroup_path;
}
#if HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
static inline bool abs_cgroup_supported(void) {
return api_version >= CGM_SUPPORTS_GET_ABS;
......@@ -1655,8 +1658,9 @@ static struct cgroup_ops cgmanager_ops = {
.enter = cgm_enter,
.create_legacy = NULL,
.get_cgroup = cgm_get_cgroup,
.canonical_path = cgm_canonical_path,
.escape = cgm_escape,
.num_hierarchies = cgm_num_hierarchies,
.get_hierarchies = cgm_get_hierarchies,
.get = cgm_get,
.set = cgm_set,
.unfreeze = cgm_unfreeze,
......
......@@ -119,17 +119,20 @@ bool cgroup_escape(struct lxc_handler *handler)
return false;
}
const char *cgroup_canonical_path(struct lxc_handler *handler)
int cgroup_num_hierarchies(void)
{
if (geteuid()) {
WARN("cgroup_canonical_path only makes sense for privileged containers.\n");
return NULL;
}
if (!ops)
return -1;
if (ops)
return ops->canonical_path(handler->cgroup_data);
return ops->num_hierarchies();
}
return NULL;
bool cgroup_get_hierarchies(int n, char ***out)
{
if (!ops)
return false;
return ops->get_hierarchies(n, out);
}
bool cgroup_unfreeze(struct lxc_handler *handler)
......
......@@ -47,8 +47,9 @@ struct cgroup_ops {
bool (*enter)(void *hdata, pid_t pid);
bool (*create_legacy)(void *hdata, pid_t pid);
const char *(*get_cgroup)(void *hdata, const char *subsystem);
const char *(*canonical_path)(void *hdata);
bool (*escape)();
int (*num_hierarchies)();
bool (*get_hierarchies)(int n, char ***out);
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);
bool (*unfreeze)(void *hdata);
......@@ -74,11 +75,8 @@ extern bool cgroup_create_legacy(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 bool cgroup_escape();
/*
* Currently, this call only makes sense for privileged containers.
*/
extern const char *cgroup_canonical_path(struct lxc_handler *handler);
extern int cgroup_num_hierarchies();
extern bool cgroup_get_hierarchies(int i, char ***out);
extern bool cgroup_unfreeze(struct lxc_handler *handler);
extern void cgroup_disconnect(void);
extern cgroup_driver_t cgroup_driver(void);
......
......@@ -69,7 +69,7 @@ struct criu_opts {
char tty_id[32]; /* the criu tty id for /dev/console, i.e. "tty[${rdev}:${dev}]" */
/* restore: the file to write the init process' pid into */
const char *cgroup_path;
struct lxc_handler *handler;
int console_fd;
/* The path that is bind mounted from /dev/console, if any. We don't
* want to use `--ext-mount-map auto`'s result here because the pts
......@@ -140,7 +140,7 @@ static void exec_criu(struct criu_opts *opts)
/* The command line always looks like:
* criu $(action) --tcp-established --file-locks --link-remap \
* --manage-cgroups=full action-script foo.sh -D $(directory) \
* --manage-cgroups=full --action-script foo.sh -D $(directory) \
* -o $(directory)/$(action).log --ext-mount-map auto
* --enable-external-sharing --enable-external-masters
* --enable-fs hugetlbfs --enable-fs tracefs --ext-mount-map console:/dev/pts/n
......@@ -175,10 +175,10 @@ static void exec_criu(struct criu_opts *opts)
static_args += 2;
} else if (strcmp(opts->action, "restore") == 0) {
/* --root $(lxc_mount_point) --restore-detached
* --restore-sibling --cgroup-root $foo
* --restore-sibling
* --lsm-profile apparmor:whatever
*/
static_args += 8;
static_args += 6;
tty_info[0] = 0;
if (load_tty_major_minor(opts->user->directory, tty_info, sizeof(tty_info)))
......@@ -191,6 +191,9 @@ static void exec_criu(struct criu_opts *opts)
return;
}
if (cgroup_num_hierarchies() > 0)
static_args += 2 * cgroup_num_hierarchies();
if (opts->user->verbose)
static_args++;
......@@ -244,6 +247,66 @@ static void exec_criu(struct criu_opts *opts)
DECLARE_ARG("-o");
DECLARE_ARG(log);
for (i = 0; i < cgroup_num_hierarchies(); i++) {
char **controllers = NULL, *fullname;
char *path;
if (!cgroup_get_hierarchies(i, &controllers)) {
ERROR("failed to get hierarchy %d", i);
goto err;
}
/* if we are in a dump, we have to ask the monitor process what
* the right cgroup is. if this is a restore, we can just use
* the handler the restore task created.
*/
if (!strcmp(opts->action, "dump") || !strcmp(opts->action, "pre-dump")) {
path = lxc_cmd_get_cgroup_path(opts->c->name, opts->c->config_path, controllers[0]);
if (!path) {
ERROR("failed to get cgroup path for %s", controllers[0]);
goto err;
}
} else {
const char *p;
p = cgroup_get_cgroup(opts->handler, controllers[0]);
if (!p) {
ERROR("failed to get cgroup path for %s", controllers[0]);
goto err;
}
path = strdup(p);
if (!path) {
ERROR("strdup failed");
goto err;
}
}
if (!lxc_deslashify(path)) {
ERROR("failed to deslashify %s", path);
free(path);
goto err;
}
fullname = lxc_string_join(",", (const char **) controllers, false);
if (!fullname) {
ERROR("failed to join controllers");
free(path);
goto err;
}
ret = sprintf(buf, "%s:%s", fullname, path);
free(path);
free(fullname);
if (ret < 0 || ret >= sizeof(buf)) {
ERROR("sprintf of cgroup root arg failed");
goto err;
}
DECLARE_ARG("--cgroup-root");
DECLARE_ARG(buf);
}
if (opts->user->verbose)
DECLARE_ARG("-vvvvvv");
......@@ -329,8 +392,6 @@ static void exec_criu(struct criu_opts *opts)
DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
DECLARE_ARG("--restore-detached");
DECLARE_ARG("--restore-sibling");
DECLARE_ARG("--cgroup-root");
DECLARE_ARG(opts->cgroup_path);
if (tty_info[0]) {
if (opts->console_fd < 0) {
......@@ -682,9 +743,9 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
os.action = "restore";
os.user = opts;
os.c = c;
os.cgroup_path = cgroup_canonical_path(handler);
os.console_fd = c->lxc_conf->console.slave;
os.criu_version = criu_version;
os.handler = handler;
if (os.console_fd >= 0) {
/* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
......@@ -891,6 +952,13 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
if (pid == 0) {
struct criu_opts os;
struct lxc_handler h;
h.name = c->name;
if (!cgroup_init(&h)) {
ERROR("failed to cgroup_init()");
exit(1);
}
os.action = mode;
os.user = opts;
......
......@@ -716,6 +716,24 @@ char **lxc_normalize_path(const char *path)
return components;
}
bool lxc_deslashify(char *path)
{
char **parts = NULL, *path2;
parts = lxc_normalize_path(path);
if (!parts)
return false;
path2 = lxc_string_join("/", (const char **) parts, *path == '/');
lxc_free_array((void **) parts, free);
if (!path2)
return false;
strncpy(path, path2, strlen(path));
free(path2);
return true;
}
char *lxc_append_paths(const char *first, const char *second)
{
size_t len = strlen(first) + strlen(second) + 1;
......
......@@ -248,6 +248,8 @@ extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_pr
* foo//bar -> { foo, bar, NULL }
*/
extern char **lxc_normalize_path(const char *path);
/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */
extern bool lxc_deslashify(char *path);
extern char *lxc_append_paths(const char *first, const char *second);
/* Note: the following two functions use strtok(), so they will never
* consider an empty element, even if two delimiters are next to
......
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