cgroups: refactor cgroup handling

This replaces the constructor implementation of cgroup handling with a simpler, thread-safe on-demand model of cgroup driver initialization. Making the cgroup initialization code run in a constructor means that each time the shared library gets mapped the cgroup parsing code gets run. That's unnecessary overhead. It also feels to me that this is only accidently thread-safe because constructors are only run once. But should threads actually end up manipulating or freeing memory that is file-global to cgfsng.c we'd be screwed. Now, I might be wrong here but the cleaner implementation is to allocate a cgroup driver on demand whenever we need it. Take the chance and rework the cgroup_ops interface to make the functions it wants to have implemented a lot cleaner. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent e37266ab
......@@ -1272,10 +1272,17 @@ int lxc_attach(const char *name, const char *lxcpath,
/* Attach to cgroup, if requested. */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
if (!cgroup_attach(name, lxcpath, pid))
struct cgroup_ops *cgroup_ops;
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
goto on_error;
if (!cgroup_ops->attach(cgroup_ops, name, lxcpath, pid))
goto on_error;
TRACE("Moved intermediate process %d into container's "
"cgroups", pid);
cgroup_exit(cgroup_ops);
TRACE("Moved intermediate process %d into container's cgroups", pid);
}
/* Setup /proc limits */
......
......@@ -32,180 +32,61 @@
lxc_log_define(lxc_cgroup, lxc);
static struct cgroup_ops *ops = NULL;
extern struct cgroup_ops *cgfsng_ops_init(void);
__attribute__((constructor)) void cgroup_ops_init(void)
struct cgroup_ops *cgroup_init(struct lxc_handler *handler)
{
if (ops) {
INFO("Running with %s in version %s", ops->driver, ops->version);
return;
}
DEBUG("cgroup_init");
ops = cgfsng_ops_init();
if (ops)
INFO("Initialized cgroup driver %s", ops->driver);
}
struct cgroup_ops *cgroup_ops;
bool cgroup_init(struct lxc_handler *handler)
{
if (handler->cgroup_data) {
ERROR("cgroup_init called on already initialized handler");
return true;
cgroup_ops = cgfsng_ops_init();
if (!cgroup_ops) {
ERROR("Failed to initialize cgroup driver");
return NULL;
}
if (ops) {
INFO("cgroup driver %s initing for %s", ops->driver, handler->name);
handler->cgroup_data = ops->init(handler);
}
if (!cgroup_ops->data_init(cgroup_ops))
return NULL;
return handler->cgroup_data != NULL;
}
TRACE("Initialized cgroup driver %s", cgroup_ops->driver);
void cgroup_destroy(struct lxc_handler *handler)
{
if (ops) {
ops->destroy(handler->cgroup_data, handler->conf);
handler->cgroup_data = NULL;
}
}
if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_LEGACY)
TRACE("Running with legacy cgroup layout");
else if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_HYBRID)
TRACE("Running with hybrid cgroup layout");
else if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED)
TRACE("Running with unified cgroup layout");
else
WARN("Running with unknown cgroup layout");
/* Create the container cgroups for all requested controllers. */
bool cgroup_create(struct lxc_handler *handler)
{
if (ops)
return ops->create(handler->cgroup_data);
return false;
return cgroup_ops;
}
/* Enter the container init into its new cgroups for all requested controllers. */
bool cgroup_enter(struct lxc_handler *handler)
void cgroup_exit(struct cgroup_ops *ops)
{
if (ops)
return ops->enter(handler->cgroup_data, handler->pid);
struct hierarchy **it;
return false;
}
bool cgroup_create_legacy(struct lxc_handler *handler)
{
if (ops && ops->create_legacy)
return ops->create_legacy(handler->cgroup_data, handler->pid);
return true;
}
const char *cgroup_get_cgroup(struct lxc_handler *handler,
const char *subsystem)
{
if (ops)
return ops->get_cgroup(handler->cgroup_data, subsystem);
return NULL;
}
bool cgroup_escape(struct lxc_handler *handler)
{
if (ops)
return ops->escape(handler->cgroup_data);
return false;
}
int cgroup_num_hierarchies(void)
{
if (!ops)
return -1;
return ops->num_hierarchies();
}
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)
{
if (ops)
return ops->unfreeze(handler->cgroup_data);
return false;
}
bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
{
if (ops)
return ops->setup_limits(handler->cgroup_data,
handler->conf, with_devices);
return false;
}
return;
bool cgroup_chown(struct lxc_handler *handler)
{
if (ops && ops->chown)
return ops->chown(handler->cgroup_data, handler->conf);
free(ops->cgroup_use);
free(ops->cgroup_pattern);
free(ops->container_cgroup);
return true;
}
for (it = ops->hierarchies; it && *it; it++) {
char **ctrlr;
bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
{
if (ops)
return ops->mount_cgroup(handler, root, type);
return false;
}
for (ctrlr = (*it)->controllers; ctrlr && *ctrlr; ctrlr++)
free(*ctrlr);
free((*it)->controllers);
int cgroup_nrtasks(struct lxc_handler *handler)
{
if (ops) {
if (ops->nrtasks)
return ops->nrtasks(handler->cgroup_data);
else
WARN("cgroup driver \"%s\" doesn't implement nrtasks", ops->driver);
free((*it)->mountpoint);
free((*it)->base_cgroup);
free((*it)->fullcgpath);
free(*it);
}
free(ops->hierarchies);
return -1;
}
bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
{
if (ops)
return ops->attach(name, lxcpath, pid);
return false;
}
int lxc_cgroup_set(const char *filename, const char *value, const char *name,
const char *lxcpath)
{
if (ops)
return ops->set(filename, value, name, lxcpath);
return -1;
}
int lxc_cgroup_get(const char *filename, char *value, size_t len,
const char *name, const char *lxcpath)
{
if (ops)
return ops->get(filename, value, len, name, lxcpath);
return -1;
}
void cgroup_disconnect(void)
{
if (ops && ops->disconnect)
ops->disconnect();
return;
}
#define INIT_SCOPE "/init.scope"
......
......@@ -39,48 +39,114 @@ typedef enum {
CGROUP_LAYOUT_UNIFIED = 2,
} cgroup_layout_t;
/* A descriptor for a mounted hierarchy
*
* @controllers
* - legacy hierarchy
* Either NULL, or a null-terminated list of all the co-mounted controllers.
* - unified hierarchy
* Either NULL, or a null-terminated list of all enabled controllers.
*
* @mountpoint
* - The mountpoint we will use.
* - legacy hierarchy
* It will be either /sys/fs/cgroup/controller or
* /sys/fs/cgroup/controllerlist.
* - unified hierarchy
* It will either be /sys/fs/cgroup or /sys/fs/cgroup/<mountpoint-name>
* depending on whether this is a hybrid cgroup layout (mix of legacy and
* unified hierarchies) or a pure unified cgroup layout.
*
* @base_cgroup
* - The cgroup under which the container cgroup path
* is created. This will be either the caller's cgroup (if not root), or
* init's cgroup (if root).
*
* @fullcgpath
* - The full path to the containers cgroup.
*
* @version
* - legacy hierarchy
* If the hierarchy is a legacy hierarchy this will be set to
* CGROUP_SUPER_MAGIC.
* - unified hierarchy
* If the hierarchy is a legacy hierarchy this will be set to
* CGROUP2_SUPER_MAGIC.
*/
struct hierarchy {
char **controllers;
char *mountpoint;
char *base_cgroup;
char *fullcgpath;
int version;
};
struct cgroup_ops {
/* string constant */
const char *driver;
/* string constant */
const char *version;
void *(*init)(struct lxc_handler *handler);
void (*destroy)(void *hdata, struct lxc_conf *conf);
bool (*create)(void *hdata);
bool (*enter)(void *hdata, pid_t pid);
bool (*create_legacy)(void *hdata, pid_t pid);
const char *(*get_cgroup)(void *hdata, const char *subsystem);
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);
bool (*setup_limits)(void *hdata, struct lxc_conf *conf, bool with_devices);
bool (*chown)(void *hdata, struct lxc_conf *conf);
bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
bool (*mount_cgroup)(void *hdata, const char *root, int type);
int (*nrtasks)(void *hdata);
void (*disconnect)(void);
/* What controllers is the container supposed to use. */
char *cgroup_use;
char *cgroup_pattern;
char *container_cgroup;
/* @hierarchies
* - A NULL-terminated array of struct hierarchy, one per legacy
* hierarchy. No duplicates. First sufficient, writeable mounted
* hierarchy wins.
*/
struct hierarchy **hierarchies;
struct hierarchy *unified;
/*
* @cgroup_layout
* - What cgroup layout the container is running with.
* - CGROUP_LAYOUT_UNKNOWN
* The cgroup layout could not be determined. This should be treated
* as an error condition.
* - CGROUP_LAYOUT_LEGACY
* The container is running with all controllers mounted into legacy
* cgroup hierarchies.
* - CGROUP_LAYOUT_HYBRID
* The container is running with at least one controller mounted
* into a legacy cgroup hierarchy and a mountpoint for the unified
* hierarchy. The unified hierarchy can be empty (no controllers
* enabled) or non-empty (controllers enabled).
* - CGROUP_LAYOUT_UNIFIED
* The container is running on a pure unified cgroup hierarchy. The
* unified hierarchy can be empty (no controllers enabled) or
* non-empty (controllers enabled).
*/
cgroup_layout_t cgroup_layout;
bool (*data_init)(struct cgroup_ops *ops);
void (*destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
bool (*create)(struct cgroup_ops *ops, struct lxc_handler *handler);
bool (*enter)(struct cgroup_ops *ops, pid_t pid);
const char *(*get_cgroup)(struct cgroup_ops *ops, const char *controller);
bool (*escape)(const struct cgroup_ops *ops);
int (*num_hierarchies)(struct cgroup_ops *ops);
bool (*get_hierarchies)(struct cgroup_ops *ops, int n, char ***out);
int (*set)(struct cgroup_ops *ops, const char *filename,
const char *value, const char *name, const char *lxcpath);
int (*get)(struct cgroup_ops *ops, const char *filename, char *value,
size_t len, const char *name, const char *lxcpath);
bool (*unfreeze)(struct cgroup_ops *ops);
bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_conf *conf,
bool with_devices);
bool (*chown)(struct cgroup_ops *ops, struct lxc_conf *conf);
bool (*attach)(struct cgroup_ops *ops, const char *name,
const char *lxcpath, pid_t pid);
bool (*mount)(struct cgroup_ops *ops, struct lxc_handler *handler,
const char *root, int type);
int (*nrtasks)(struct cgroup_ops *ops);
};
extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
extern void cgroup_destroy(struct lxc_handler *handler);
extern bool cgroup_init(struct lxc_handler *handler);
extern bool cgroup_create(struct lxc_handler *handler);
extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
extern bool cgroup_chown(struct lxc_handler *handler);
extern bool cgroup_enter(struct lxc_handler *handler);
extern void cgroup_cleanup(struct lxc_handler *handler);
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();
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 struct cgroup_ops *cgroup_init(struct lxc_handler *handler);
extern void cgroup_exit(struct cgroup_ops *ops);
extern void prune_init_scope(char *cg);
extern bool is_crucial_cgroup_subsystem(const char *s);
......
......@@ -473,11 +473,12 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
{
const char *path;
struct lxc_cmd_rsp rsp;
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
if (req->datalen > 0)
path = cgroup_get_cgroup(handler, req->data);
path = cgroup_ops->get_cgroup(cgroup_ops, req->data);
else
path = cgroup_get_cgroup(handler, NULL);
path = cgroup_ops->get_cgroup(cgroup_ops, NULL);
if (!path)
return -1;
......@@ -637,6 +638,7 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
{
struct lxc_cmd_rsp rsp;
int stopsignal = SIGKILL;
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
if (handler->conf->stopsignal)
stopsignal = handler->conf->stopsignal;
......@@ -648,7 +650,7 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
* lxc_unfreeze() would do another cmd (GET_CGROUP) which would
* deadlock us.
*/
if (cgroup_unfreeze(handler))
if (cgroup_ops->unfreeze(cgroup_ops))
return 0;
ERROR("Failed to unfreeze container \"%s\"", handler->name);
......
......@@ -757,7 +757,10 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
if (flags & LXC_AUTO_CGROUP_FORCE)
cg_flags |= LXC_AUTO_CGROUP_FORCE;
if (!cgroup_mount(conf->rootfs.path ? conf->rootfs.mount : "", handler, cg_flags)) {
if (!handler->cgroup_ops->mount(handler->cgroup_ops,
handler,
conf->rootfs.path ? conf->rootfs.mount : "",
cg_flags)) {
SYSERROR("Failed to mount \"/sys/fs/cgroup\"");
return -1;
}
......
......@@ -171,7 +171,7 @@ static int cmp_version(const char *v1, const char *v2)
return -1;
}
static void exec_criu(struct criu_opts *opts)
static void exec_criu(struct cgroup_ops *cgroup_ops, struct criu_opts *opts)
{
char **argv, log[PATH_MAX];
int static_args = 23, argc = 0, i, ret;
......@@ -190,7 +190,7 @@ static void exec_criu(struct criu_opts *opts)
* /actual/ root cgroup so that lxcfs thinks criu has enough rights to
* see all cgroups.
*/
if (!cgroup_escape()) {
if (!cgroup_ops->escape(cgroup_ops)) {
ERROR("failed to escape cgroups");
return;
}
......@@ -248,8 +248,8 @@ static void exec_criu(struct criu_opts *opts)
return;
}
if (cgroup_num_hierarchies() > 0)
static_args += 2 * cgroup_num_hierarchies();
if (cgroup_ops->num_hierarchies(cgroup_ops) > 0)
static_args += 2 * cgroup_ops->num_hierarchies(cgroup_ops);
if (opts->user->verbose)
static_args++;
......@@ -306,11 +306,11 @@ static void exec_criu(struct criu_opts *opts)
DECLARE_ARG("-o");
DECLARE_ARG(log);
for (i = 0; i < cgroup_num_hierarchies(); i++) {
for (i = 0; i < cgroup_ops->num_hierarchies(cgroup_ops); i++) {
char **controllers = NULL, *fullname;
char *path, *tmp;
if (!cgroup_get_hierarchies(i, &controllers)) {
if (!cgroup_ops->get_hierarchies(cgroup_ops, i, &controllers)) {
ERROR("failed to get hierarchy %d", i);
goto err;
}
......@@ -328,7 +328,7 @@ static void exec_criu(struct criu_opts *opts)
} else {
const char *p;
p = cgroup_get_cgroup(opts->handler, controllers[0]);
p = cgroup_ops->get_cgroup(cgroup_ops, controllers[0]);
if (!p) {
ERROR("failed to get cgroup path for %s", controllers[0]);
goto err;
......@@ -937,6 +937,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
struct lxc_handler *handler;
int status = 0;
int pipes[2] = {-1, -1};
struct cgroup_ops *cgroup_ops;
/* Try to detach from the current controlling tty if it exists.
* Othwerise, lxc_init (via lxc_console) will attach the container's
......@@ -958,12 +959,12 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
if (lxc_init(c->name, handler) < 0)
goto out;
if (!cgroup_init(handler)) {
ERROR("failed initing cgroups");
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
goto out_fini_handler;
}
handler->cgroup_ops = cgroup_ops;
if (!cgroup_create(handler)) {
if (!cgroup_ops->create(cgroup_ops, handler)) {
ERROR("failed creating groups");
goto out_fini_handler;
}
......@@ -1052,7 +1053,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
os.console_name = c->lxc_conf->console.name;
/* exec_criu() returning is an error */
exec_criu(&os);
exec_criu(cgroup_ops, &os);
umount(rootfs->mount);
rmdir(rootfs->mount);
goto out_fini_handler;
......@@ -1253,16 +1254,21 @@ 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;
struct cgroup_ops *cgroup_ops;
close(criuout[0]);
lxc_zero_handler(&h);
h.name = c->name;
if (!cgroup_init(&h)) {
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops) {
ERROR("failed to cgroup_init()");
_exit(EXIT_FAILURE);
return -1;
}
h.cgroup_ops = cgroup_ops;
os.pipefd = criuout[1];
os.action = mode;
......@@ -1278,7 +1284,7 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
}
/* exec_criu() returning is an error */
exec_criu(&os);
exec_criu(cgroup_ops, &os);
free(criu_version);
_exit(EXIT_FAILURE);
} else {
......
......@@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/param.h>
#include "cgroup.h"
#include "commands.h"
#include "error.h"
#include "log.h"
......@@ -45,8 +46,14 @@ lxc_state_t freezer_state(const char *name, const char *lxcpath)
{
int ret;
char v[100];
struct cgroup_ops *cgroup_ops;
ret = lxc_cgroup_get("freezer.state", v, sizeof(v), name, lxcpath);
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
return -1;
ret = cgroup_ops->get(cgroup_ops, "freezer.state", v, sizeof(v), name, lxcpath);
cgroup_exit(cgroup_ops);
if (ret < 0)
return -1;
......@@ -60,19 +67,26 @@ static int do_freeze_thaw(bool freeze, const char *name, const char *lxcpath)
{
int ret;
char v[100];
struct cgroup_ops *cgroup_ops;
const char *state = freeze ? "FROZEN" : "THAWED";
size_t state_len = 6;
lxc_state_t new_state = freeze ? FROZEN : THAWED;
ret = lxc_cgroup_set("freezer.state", state, name, lxcpath);
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
return -1;
ret = cgroup_ops->set(cgroup_ops, "freezer.state", state, name, lxcpath);
if (ret < 0) {
cgroup_exit(cgroup_ops);
ERROR("Failed to freeze %s", name);
return -1;
}
for (;;) {
ret = lxc_cgroup_get("freezer.state", v, sizeof(v), name, lxcpath);
ret = cgroup_ops->get(cgroup_ops, "freezer.state", v, sizeof(v), name, lxcpath);
if (ret < 0) {
cgroup_exit(cgroup_ops);
ERROR("Failed to get freezer state of %s", name);
return -1;
}
......@@ -82,6 +96,7 @@ static int do_freeze_thaw(bool freeze, const char *name, const char *lxcpath)
ret = strncmp(v, state, state_len);
if (ret == 0) {
cgroup_exit(cgroup_ops);
lxc_cmd_serve_state_clients(name, lxcpath, new_state);
lxc_monitor_send_state(name, new_state, lxcpath);
return 0;
......
......@@ -98,29 +98,6 @@ extern int lxc_unfreeze(const char *name, const char *lxcpath);
extern lxc_state_t lxc_state(const char *name, const char *lxcpath);
/*
* Set a specified value for a specified subsystem. The specified
* subsystem must be fully specified, eg. "cpu.shares"
* @filename : the cgroup attribute filename
* @value : the value to be set
* @name : the name of the container
* @lxcpath : lxc config path for container
* Returns 0 on success, < 0 otherwise
*/
extern int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath);
/*
* Get a specified value for a specified subsystem. The specified
* subsystem must be fully specified, eg. "cpu.shares"
* @filename : the cgroup attribute filename
* @value : the value to be set
* @len : the len of the value variable
* @name : the name of the container
* @lxcpath : lxc config path for container
* Returns the number of bytes read, < 0 on error
*/
extern int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
/*
* Create and return a new lxccontainer struct.
*/
extern struct lxc_container *lxc_container_new(const char *name, const char *configpath);
......
......@@ -3141,6 +3141,7 @@ WRAP_API_1(bool, lxcapi_set_config_path, const char *)
static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value)
{
int ret;
struct cgroup_ops *cgroup_ops;
if (!c)
return false;
......@@ -3148,12 +3149,19 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy
if (is_stopped(c))
return false;
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
return false;
if (container_disk_lock(c))
return false;
ret = lxc_cgroup_set(subsys, value, c->name, c->config_path);
ret = cgroup_ops->set(cgroup_ops, subsys, value, c->name, c->config_path);
container_disk_unlock(c);
cgroup_exit(cgroup_ops);
return ret == 0;
}
......@@ -3162,6 +3170,7 @@ WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *)
static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen)
{
int ret;
struct cgroup_ops *cgroup_ops;
if (!c)
return -1;
......@@ -3169,12 +3178,20 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys
if (is_stopped(c))
return -1;
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
return -1;
if (container_disk_lock(c))
return -1;
ret = lxc_cgroup_get(subsys, retv, inlen, c->name, c->config_path);
ret = cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name,
c->config_path);
container_disk_unlock(c);
cgroup_exit(cgroup_ops);
return ret;
}
......
......@@ -849,6 +849,13 @@ int lxc_init(const char *name, struct lxc_handler *handler)
}
TRACE("Chowned console");
handler->cgroup_ops = cgroup_init(handler);
if (!handler->cgroup_ops) {
ERROR("Failed to initialize cgroup driver");
goto out_restore_sigmask;
}
TRACE("Initialized cgroup driver");
INFO("Container \"%s\" is initialized", name);
return 0;
......@@ -871,6 +878,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
struct lxc_list *cur, *next;
char *namespaces[LXC_NS_MAX + 1];
size_t namespace_count = 0;
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
/* The STOPPING state is there for future cleanup code which can take
* awhile.
......@@ -935,7 +943,8 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
while (namespace_count--)
free(namespaces[namespace_count]);
cgroup_destroy(handler);
cgroup_ops->destroy(cgroup_ops, handler);
cgroup_exit(cgroup_ops);
if (handler->conf->reboot == 0) {
/* For all new state clients simply close the command socket.
......@@ -1506,8 +1515,9 @@ static int lxc_spawn(struct lxc_handler *handler)
struct lxc_list *id_map;
const char *name = handler->name;
const char *lxcpath = handler->lxcpath;
bool cgroups_connected = false, share_ns = false;
bool share_ns = false;
struct lxc_conf *conf = handler->conf;
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
id_map = &conf->id_map;
wants_to_map_ids = !lxc_list_empty(id_map);
......@@ -1567,14 +1577,7 @@ static int lxc_spawn(struct lxc_handler *handler)
}
}
if (!cgroup_init(handler)) {
ERROR("Failed initializing cgroup support");
goto out_delete_net;
}
cgroups_connected = true;
if (!cgroup_create(handler)) {
if (!cgroup_ops->create(cgroup_ops, handler)) {
ERROR("Failed creating cgroups");
goto out_delete_net;
}
......@@ -1663,15 +1666,15 @@ static int lxc_spawn(struct lxc_handler *handler)
if (ret < 0)
goto out_delete_net;
if (!cgroup_setup_limits(handler, false)) {
if (!cgroup_ops->setup_limits(cgroup_ops, handler->conf, false)) {
ERROR("Failed to setup cgroup limits for container \"%s\"", name);
goto out_delete_net;
}
if (!cgroup_enter(handler))
if (!cgroup_ops->enter(cgroup_ops, handler->pid))
goto out_delete_net;
if (!cgroup_chown(handler))
if (!cgroup_ops->chown(cgroup_ops, handler->conf))
goto out_delete_net;
/* Now we're ready to preserve the network namespace */
......@@ -1736,15 +1739,12 @@ static int lxc_spawn(struct lxc_handler *handler)
if (ret < 0)
goto out_delete_net;
if (!cgroup_setup_limits(handler, true)) {
if (!cgroup_ops->setup_limits(cgroup_ops, handler->conf, true)) {
ERROR("Failed to setup legacy device cgroup controller limits");
goto out_delete_net;
}
TRACE("Set up legacy device cgroup controller limits");
cgroup_disconnect();
cgroups_connected = false;
if (handler->ns_clone_flags & CLONE_NEWCGROUP) {
/* Now we're ready to preserve the cgroup namespace */
ret = lxc_try_preserve_ns(handler->pid, "cgroup");
......@@ -1821,9 +1821,6 @@ static int lxc_spawn(struct lxc_handler *handler)
return 0;
out_delete_net:
if (cgroups_connected)
cgroup_disconnect();
if (handler->ns_clone_flags & CLONE_NEWNET)
lxc_delete_network(handler);
......
......@@ -132,6 +132,8 @@ struct lxc_handler {
* true.
*/
int exit_status;
struct cgroup_ops *cgroup_ops;
};
struct execute_args {
......
......@@ -53,6 +53,7 @@ static int test_running_container(const char *lxcpath,
char *cgrelpath;
char relpath[PATH_MAX+1];
char value[NAME_MAX], value_save[NAME_MAX];
struct cgroup_ops *cgroup_ops;
sprintf(relpath, "%s/%s", group ? group : "lxc", name);
......@@ -75,36 +76,41 @@ static int test_running_container(const char *lxcpath,
goto err3;
}
cgroup_ops = cgroup_init(NULL);
if (!cgroup_ops)
goto err3;
/* test get/set value using memory.soft_limit_in_bytes file */
ret = lxc_cgroup_get("memory.soft_limit_in_bytes", value, sizeof(value),
c->name, c->config_path);
ret = cgroup_ops->get(cgroup_ops, "memory.soft_limit_in_bytes", value,
sizeof(value), c->name, c->config_path);
if (ret < 0) {
TSTERR("lxc_cgroup_get failed");
TSTERR("cgroup_get failed");
goto err3;
}
strcpy(value_save, value);
ret = lxc_cgroup_set("memory.soft_limit_in_bytes", "512M", c->name, c->config_path);
ret = cgroup_ops->set(cgroup_ops, "memory.soft_limit_in_bytes", "512M",
c->name, c->config_path);
if (ret < 0) {
TSTERR("lxc_cgroup_set failed %d %d", ret, errno);
TSTERR("cgroup_set failed %d %d", ret, errno);
goto err3;
}
ret = lxc_cgroup_get("memory.soft_limit_in_bytes", value, sizeof(value),
c->name, c->config_path);
ret = cgroup_ops->get(cgroup_ops, "memory.soft_limit_in_bytes", value,
sizeof(value), c->name, c->config_path);
if (ret < 0) {
TSTERR("lxc_cgroup_get failed");
TSTERR("cgroup_get failed");
goto err3;
}
if (strcmp(value, "536870912\n")) {
TSTERR("lxc_cgroup_set_bypath failed to set value >%s<", value);
TSTERR("cgroup_set_bypath failed to set value >%s<", value);
goto err3;
}
/* restore original value */
ret = lxc_cgroup_set("memory.soft_limit_in_bytes", value_save,
c->name, c->config_path);
ret = cgroup_ops->set(cgroup_ops, "memory.soft_limit_in_bytes",
value_save, c->name, c->config_path);
if (ret < 0) {
TSTERR("lxc_cgroup_set failed");
TSTERR("cgroup_set failed");
goto err3;
}
......
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