return &cgfs_ops;
}
-static void *cgfs_init(const char *name)
+static void *cgfs_init(struct lxc_handler *handler)
{
struct cgfs_data *d;
return NULL;
memset(d, 0, sizeof(*d));
- d->name = strdup(name);
+ d->name = strdup(handler->name);
if (!d->name)
goto err1;
#include "cgroup.h"
#include "cgroup_utils.h"
#include "commands.h"
+#include "conf.h"
#include "log.h"
-#include "storage.h"
+#include "storage/storage.h"
#include "utils.h"
lxc_log_define(lxc_cgfsng, lxc);
/*
* The cgroup data which is attached to the lxc_handler.
- * @cgroup_pattern - a copy of the lxc.cgroup.pattern
- * @container_cgroup - if not null, the cgroup which was created for
- * the container. For each hierarchy, it is created under the
- * @hierarchy->base_cgroup directory. Relative to the base_cgroup
- * it is the same for all hierarchies.
- * @name - the container name
+ * @cgroup_pattern : A copy of the lxc.cgroup.pattern
+ * @container_cgroup : If not null, the cgroup which was created for the
+ * container. For each hierarchy, it is created under the
+ * @hierarchy->base_cgroup directory. Relative to the
+ * base_cgroup it is the same for all hierarchies.
+ * @name : The name of the container.
+ * @cgroup_meta : A copy of the container's cgroup information. This
+ * overrides @cgroup_pattern.
*/
struct cgfsng_handler_data {
char *cgroup_pattern;
char *container_cgroup; /* cgroup we created for the container */
char *name; /* container name */
+ /* per-container cgroup information */
+ struct lxc_cgroup cgroup_meta;
};
/*
free(d->cgroup_pattern);
free(d->container_cgroup);
free(d->name);
+ if (d->cgroup_meta.dir)
+ free(d->cgroup_meta.dir);
+ if (d->cgroup_meta.controllers)
+ free(d->cgroup_meta.controllers);
free(d);
}
printf("Cgroup information:\n");
printf(" container name: %s\n", d->name ? d->name : "(null)");
printf(" lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
- printf(" lxc.cgroup.pattern: %s\n", d->cgroup_pattern ? d->cgroup_pattern : "(null)");
- printf(" cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(null)");
+ printf(" lxc.cgroup.pattern: %s\n",
+ d->cgroup_pattern ? d->cgroup_pattern : "(null)");
+ printf(" lxc.cgroup.dir: %s\n",
+ d->cgroup_meta.dir ? d->cgroup_meta.dir : "(null)");
+ printf(" cgroup: %s\n",
+ d->container_cgroup ? d->container_cgroup : "(null)");
}
static void lxc_cgfsng_print_hierarchies()
return parse_hierarchies();
}
-static void *cgfsng_init(const char *name)
+static void *cgfsng_init(struct lxc_handler *handler)
{
- struct cgfsng_handler_data *d;
const char *cgroup_pattern;
+ struct cgfsng_handler_data *d;
d = must_alloc(sizeof(*d));
memset(d, 0, sizeof(*d));
- d->name = must_copy_string(name);
+ /* copy container name */
+ d->name = must_copy_string(handler->name);
+
+ /* copy per-container cgroup information */
+ d->cgroup_meta.dir = must_copy_string(handler->conf->cgroup_meta.dir);
+ d->cgroup_meta.controllers = must_copy_string(handler->conf->cgroup_meta.controllers);
+ /* copy system-wide cgroup information */
cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
- if (!cgroup_pattern) { /* lxc.cgroup.pattern is only NULL on error */
+ if (!cgroup_pattern) {
+ /* lxc.cgroup.pattern is only NULL on error. */
ERROR("Error getting cgroup pattern");
goto out_free;
}
if (!d)
return false;
+
if (d->container_cgroup) {
WARN("cgfsng_create called a second time");
return false;
}
- tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
+ if (d->cgroup_meta.dir)
+ tmp = strdup(d->cgroup_meta.dir);
+ else
+ tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
if (!tmp) {
ERROR("Failed expanding cgroup name pattern");
return false;
INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
}
-static void *cgm_init(const char *name)
+static void *cgm_init(struct lxc_handler *handler)
{
struct cgm_data *d;
}
memset(d, 0, sizeof(*d));
- d->name = strdup(name);
+ d->name = strdup(handler->name);
if (!d->name) {
cgm_dbus_disconnect();
goto err1;
if (ops) {
INFO("cgroup driver %s initing for %s", ops->name, handler->name);
- handler->cgroup_data = ops->init(handler->name);
+ handler->cgroup_data = ops->init(handler);
}
return handler->cgroup_data != NULL;
return -1;
}
-void cgroup_disconnect(void) {
+void cgroup_disconnect(void)
+{
if (ops && ops->disconnect)
ops->disconnect();
}
struct cgroup_ops {
const char *name;
- void *(*init)(const char *name);
+ 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);
* default to running as UID/GID 0 when using lxc-execute */
new->init_uid = 0;
new->init_gid = 0;
+ memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
return new;
}
lxc_clear_aliens(conf);
lxc_clear_environment(conf);
lxc_clear_limits(conf, "lxc.prlimit");
+ free(conf->cgroup_meta.dir);
+ free(conf->cgroup_meta.controllers);
free(conf);
}
};
/*
- * Defines a generic struct to configure the control group.
- * It is up to the programmer to specify the right subsystem.
+ * Defines a generic struct to configure the control group. It is up to the
+ * programmer to specify the right subsystem.
* @subsystem : the targeted subsystem
* @value : the value to set
+ *
+ * @controllers : The controllers to use for this container.
+ * @dir : The name of the directory containing the container's cgroup.
+ * Not that this is a per-container setting.
*/
struct lxc_cgroup {
- char *subsystem;
- char *value;
+ union {
+ /* information about a specific controller */
+ struct /* controller */ {
+ char *subsystem;
+ char *value;
+ };
+
+ /* meta information about cgroup configuration */
+ struct /* meta */ {
+ char *controllers;
+ char *dir;
+ };
+ };
};
#if !HAVE_SYS_RESOURCE_H
* legacy configuration keys.
*/
bool contains_legacy_key;
+
+ /* Contains generic info about the cgroup configuration for this
+ * container. Note that struct lxc_cgroup contains a union. It is only
+ * valid to access the members of the anonymous "meta" struct within
+ * that union.
+ */
+ struct lxc_cgroup cgroup_meta;
};
#ifdef HAVE_TLS
extern void lxc_clear_includes(struct lxc_conf *conf);
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
const char *lxcpath);
-struct cgroup_process_info;
extern int lxc_setup(struct lxc_handler *handler);
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
lxc_config_define(apparmor_profile);
lxc_config_define(apparmor_allow_incomplete);
lxc_config_define(selinux_context);
-lxc_config_define(cgroup);
+lxc_config_define(cgroup_controller);
+lxc_config_define(cgroup_dir);
lxc_config_define(idmaps);
lxc_config_define(log_level);
lxc_config_define(log_file);
{ "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.keep", false, set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
- { "lxc.cgroup", false, set_config_cgroup, get_config_cgroup, clr_config_cgroup, },
+ { "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.console.logfile", false, set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
{ "lxc.console.path", false, set_config_console_path, get_config_console_path, clr_config_console_path, },
{ "lxc.environment", false, set_config_environment, get_config_environment, clr_config_environment, },
return 0;
}
-static int set_config_cgroup(const char *key, const char *value,
- struct lxc_conf *lxc_conf, void *data)
+static int set_config_cgroup_controller(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
{
char *subkey;
char *token = "lxc.cgroup.";
return -1;
}
+static int set_config_cgroup_dir(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ if (lxc_config_value_empty(value))
+ return clr_config_cgroup_dir(key, lxc_conf, NULL);
+
+ if (lxc_conf->cgroup_meta.dir)
+ clr_config_cgroup_dir(key, lxc_conf, NULL);
+
+ return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
+}
+
static int set_config_prlimit(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
* If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
* 'lxc.cgroup.subsystem.key = value' format.
*/
-static int get_config_cgroup(const char *key, char *retv, int inlen,
- struct lxc_conf *c, void *data)
+static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
{
struct lxc_list *it;
int len;
return fulllen;
}
+static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ int len;
+ int fulllen = 0;
+
+ if (!retv)
+ inlen = 0;
+ else
+ memset(retv, 0, inlen);
+
+ strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
+
+ return fulllen;
+}
+
static int get_config_idmaps(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
return 0;
}
-static inline int clr_config_cgroup(const char *key, struct lxc_conf *c,
- void *data)
+static inline int clr_config_cgroup_controller(const char *key,
+ struct lxc_conf *c, void *data)
{
return lxc_clear_cgroups(c, key);
}
+static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
+ void *data)
+{
+ if (lxc_conf->cgroup_meta.dir) {
+ free(lxc_conf->cgroup_meta.dir);
+ lxc_conf->cgroup_meta.dir = NULL;
+ }
+
+ return 0;
+}
+
static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
void *data)
{