mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-14 11:39:56 +00:00
split cgroup handling into discrete backends
- refactor cgroup into two backends, the classic cgfs driver and the new cgmanager. Instead of lxc_handler knowing about the internals of each, have it just store an opaque pointer to a struct that is private to each backend. - rename a couple of cgroup functions for consistency: those that are considered an API (ie. exported by lxc.h) begin with lxc_ and those that are not are just cgroup_* - made as many backend routines static as possible, only cg*_ops_init is exported - made a nrtasks op which is needed by the utmp code for monitoring container shutdown, currently only implemented for the cgfs backend Signed-off-by: Dwight Engen <dwight.engen@oracle.com> Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
This commit is contained in:
parent
20e2ae994f
commit
4fb3cba5bc
@ -62,7 +62,8 @@ liblxc_so_SOURCES = \
|
||||
freezer.c \
|
||||
error.h error.c \
|
||||
parse.c parse.h \
|
||||
cgfs.c cgroup.h \
|
||||
cgfs.c \
|
||||
cgroup.c cgroup.h \
|
||||
lxc.h \
|
||||
utils.c utils.h \
|
||||
sync.c sync.h \
|
||||
|
@ -699,7 +699,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
|
||||
|
||||
/* attach to cgroup, if requested */
|
||||
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) {
|
||||
if (!lxc_cgroup_attach(name, lxcpath, pid))
|
||||
if (!cgroup_attach(name, lxcpath, pid))
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
|
518
src/lxc/cgfs.c
518
src/lxc/cgfs.c
@ -55,7 +55,75 @@
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
|
||||
lxc_log_define(lxc_cgroup, lxc);
|
||||
struct cgroup_hierarchy;
|
||||
struct cgroup_meta_data;
|
||||
struct cgroup_mount_point;
|
||||
|
||||
/*
|
||||
* cgroup_meta_data: the metadata about the cgroup infrastructure on this
|
||||
* host
|
||||
*/
|
||||
struct cgroup_meta_data {
|
||||
ptrdiff_t ref; /* simple refcount */
|
||||
struct cgroup_hierarchy **hierarchies;
|
||||
struct cgroup_mount_point **mount_points;
|
||||
int maximum_hierarchy;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_hierarchy: describes a single cgroup hierarchy
|
||||
* (may have multiple mount points)
|
||||
*/
|
||||
struct cgroup_hierarchy {
|
||||
int index;
|
||||
bool used; /* false if the hierarchy should be ignored by lxc */
|
||||
char **subsystems;
|
||||
struct cgroup_mount_point *rw_absolute_mount_point;
|
||||
struct cgroup_mount_point *ro_absolute_mount_point;
|
||||
struct cgroup_mount_point **all_mount_points;
|
||||
size_t all_mount_point_capacity;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_mount_point: a mount point to where a hierarchy
|
||||
* is mounted to
|
||||
*/
|
||||
struct cgroup_mount_point {
|
||||
struct cgroup_hierarchy *hierarchy;
|
||||
char *mount_point;
|
||||
char *mount_prefix;
|
||||
bool read_only;
|
||||
bool need_cpuset_init;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_process_info: describes the membership of a
|
||||
* process to the different cgroup
|
||||
* hierarchies
|
||||
*
|
||||
* Note this is the per-process info tracked by the cgfs_ops.
|
||||
* This is not used with cgmanager.
|
||||
*/
|
||||
struct cgroup_process_info {
|
||||
struct cgroup_process_info *next;
|
||||
struct cgroup_meta_data *meta_ref;
|
||||
struct cgroup_hierarchy *hierarchy;
|
||||
char *cgroup_path;
|
||||
char *cgroup_path_sub;
|
||||
char **created_paths;
|
||||
size_t created_paths_capacity;
|
||||
size_t created_paths_count;
|
||||
struct cgroup_mount_point *designated_mount_point;
|
||||
};
|
||||
|
||||
struct cgfs_data {
|
||||
char *name;
|
||||
const char *cgroup_pattern;
|
||||
struct cgroup_meta_data *meta;
|
||||
struct cgroup_process_info *info;
|
||||
};
|
||||
|
||||
lxc_log_define(lxc_cgfs, lxc);
|
||||
|
||||
static struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta);
|
||||
static char **subsystems_from_mount_options(const char *mount_options, char **kernel_list);
|
||||
@ -68,27 +136,22 @@ static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *
|
||||
static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
|
||||
static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
|
||||
static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value);
|
||||
static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_allow);
|
||||
static int do_setup_cgroup_limits(struct lxc_handler *h, struct lxc_list *cgroup_settings, bool do_devices);
|
||||
static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d, char *v, bool for_allow);
|
||||
static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices);
|
||||
static int cgroup_recursive_task_count(const char *cgroup_path);
|
||||
static int count_lines(const char *fn);
|
||||
static int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path);
|
||||
static bool init_cpuset_if_needed(struct cgroup_mount_point *mp, const char *path);
|
||||
|
||||
static struct cgroup_ops cgfs_ops;
|
||||
struct cgroup_ops *active_cg_ops = &cgfs_ops;
|
||||
static void init_cg_ops(void);
|
||||
static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
|
||||
static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
|
||||
static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
|
||||
|
||||
#ifdef HAVE_CGMANAGER
|
||||
/* this needs to be mutexed for api use */
|
||||
extern bool cgmanager_initialized;
|
||||
extern bool use_cgmanager;
|
||||
extern bool lxc_init_cgmanager(void);
|
||||
#else
|
||||
static bool cgmanager_initialized = false;
|
||||
static bool use_cgmanager = false;
|
||||
static bool lxc_init_cgmanager(void) { return false; }
|
||||
#endif
|
||||
/* free process membership information */
|
||||
static void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
|
||||
static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info);
|
||||
|
||||
static struct cgroup_ops cgfs_ops;
|
||||
|
||||
static int cgroup_rmdir(char *dirname)
|
||||
{
|
||||
@ -159,7 +222,7 @@ static int cgroup_rmdir(char *dirname)
|
||||
return failed ? -1 : 0;
|
||||
}
|
||||
|
||||
struct cgroup_meta_data *lxc_cgroup_load_meta()
|
||||
static struct cgroup_meta_data *lxc_cgroup_load_meta()
|
||||
{
|
||||
const char *cgroup_use = NULL;
|
||||
char **cgroup_use_list = NULL;
|
||||
@ -184,7 +247,7 @@ struct cgroup_meta_data *lxc_cgroup_load_meta()
|
||||
}
|
||||
|
||||
/* Step 1: determine all kernel subsystems */
|
||||
bool find_cgroup_subsystems(char ***kernel_subsystems)
|
||||
static bool find_cgroup_subsystems(char ***kernel_subsystems)
|
||||
{
|
||||
FILE *proc_cgroups;
|
||||
bool bret = false;
|
||||
@ -470,7 +533,7 @@ out:
|
||||
return bret;
|
||||
}
|
||||
|
||||
struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
|
||||
static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
|
||||
{
|
||||
bool all_kernel_subsystems = true;
|
||||
bool all_named_subsystems = false;
|
||||
@ -526,13 +589,13 @@ out_error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
|
||||
static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
|
||||
{
|
||||
meta_data->ref++;
|
||||
return meta_data;
|
||||
}
|
||||
|
||||
struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
|
||||
static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
|
||||
{
|
||||
size_t i;
|
||||
if (!meta_data)
|
||||
@ -549,7 +612,7 @@ struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
|
||||
static struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
|
||||
@ -560,7 +623,7 @@ struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
|
||||
static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
|
||||
{
|
||||
struct cgroup_mount_point **mps;
|
||||
struct cgroup_mount_point *current_result = NULL;
|
||||
@ -600,7 +663,7 @@ struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *
|
||||
return current_result;
|
||||
}
|
||||
|
||||
char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
|
||||
static char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
|
||||
{
|
||||
struct cgroup_meta_data *meta_data;
|
||||
struct cgroup_hierarchy *h;
|
||||
@ -634,19 +697,19 @@ out_error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
|
||||
static struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
|
||||
{
|
||||
char pid_buf[32];
|
||||
snprintf(pid_buf, 32, "/proc/%lu/cgroup", (unsigned long)pid);
|
||||
return lxc_cgroup_process_info_getx(pid_buf, meta);
|
||||
}
|
||||
|
||||
struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
|
||||
static struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
|
||||
{
|
||||
return lxc_cgroup_process_info_get(1, meta);
|
||||
}
|
||||
|
||||
struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
|
||||
static struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
|
||||
{
|
||||
struct cgroup_process_info *i;
|
||||
i = lxc_cgroup_process_info_getx("/proc/self/cgroup", meta);
|
||||
@ -724,7 +787,7 @@ static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, p
|
||||
}
|
||||
|
||||
/* create a new cgroup */
|
||||
struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
|
||||
static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
|
||||
{
|
||||
char **cgroup_path_components = NULL;
|
||||
char **p = NULL;
|
||||
@ -985,7 +1048,7 @@ out_initial_error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
|
||||
static int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
|
||||
{
|
||||
struct cgroup_process_info *info_ptr;
|
||||
int r;
|
||||
@ -1016,7 +1079,7 @@ int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *
|
||||
}
|
||||
|
||||
/* get the cgroup membership of a given container */
|
||||
struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
|
||||
static struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
|
||||
{
|
||||
struct cgroup_process_info *result = NULL;
|
||||
int saved_errno = 0;
|
||||
@ -1064,7 +1127,7 @@ out_error:
|
||||
}
|
||||
|
||||
/* move a processs to the cgroups specified by the membership */
|
||||
int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
|
||||
static int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
|
||||
{
|
||||
char pid_buf[32];
|
||||
char *cgroup_tasks_fn;
|
||||
@ -1148,9 +1211,8 @@ void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
|
||||
lxc_cgroup_process_info_free_and_remove(next);
|
||||
}
|
||||
|
||||
static char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler)
|
||||
static char *lxc_cgroup_get_hierarchy_path_data(const char *subsystem, struct cgfs_data *d)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *info = d->info;
|
||||
info = find_info_for_subsystem(info, subsystem);
|
||||
if (!info)
|
||||
@ -1158,14 +1220,8 @@ static char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct
|
||||
return info->cgroup_path;
|
||||
}
|
||||
|
||||
char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, const char *lxcpath)
|
||||
static char *lxc_cgroup_get_hierarchy_abs_path_data(const char *subsystem, struct cgfs_data *d)
|
||||
{
|
||||
return lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
|
||||
}
|
||||
|
||||
char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *info = d->info;
|
||||
struct cgroup_mount_point *mp = NULL;
|
||||
|
||||
@ -1182,7 +1238,7 @@ char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lx
|
||||
return cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
|
||||
}
|
||||
|
||||
char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
|
||||
static char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
|
||||
{
|
||||
struct cgroup_meta_data *meta;
|
||||
struct cgroup_process_info *base_info, *info;
|
||||
@ -1214,7 +1270,7 @@ out1:
|
||||
return result;
|
||||
}
|
||||
|
||||
int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler)
|
||||
static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfs_data *d)
|
||||
{
|
||||
char *subsystem = NULL, *p, *path;
|
||||
int ret = -1;
|
||||
@ -1224,7 +1280,7 @@ int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_h
|
||||
if ((p = index(subsystem, '.')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
|
||||
path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d);
|
||||
if (path) {
|
||||
ret = do_cgroup_set(path, filename, value);
|
||||
free(path);
|
||||
@ -1232,25 +1288,7 @@ int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_h
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct lxc_handler *handler)
|
||||
{
|
||||
char *subsystem = NULL, *p, *path;
|
||||
int ret = -1;
|
||||
|
||||
subsystem = alloca(strlen(filename) + 1);
|
||||
strcpy(subsystem, filename);
|
||||
if ((p = index(subsystem, '.')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
|
||||
if (path) {
|
||||
ret = do_cgroup_get(path, filename, value, len);
|
||||
free(path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
|
||||
static int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
|
||||
{
|
||||
char *subsystem = NULL, *p, *path;
|
||||
int ret = -1;
|
||||
@ -1268,7 +1306,7 @@ int lxc_cgroupfs_set(const char *filename, const char *value, const char *name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
|
||||
static int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
|
||||
{
|
||||
char *subsystem = NULL, *p, *path;
|
||||
int ret = -1;
|
||||
@ -1286,48 +1324,7 @@ int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* lxc_cgroup_path_get: Get the absolute pathname for a cgroup
|
||||
* file for a running container.
|
||||
*
|
||||
* @filename : the file of interest (e.g. "freezer.state") or
|
||||
* the subsystem name (e.g. "freezer") in which case
|
||||
* the directory where the cgroup may be modified
|
||||
* will be returned
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* This is the exported function, which determines cgpath from the
|
||||
* lxc-start of the @name container running in @lxcpath.
|
||||
*
|
||||
* Returns path on success, NULL on error. The caller must free()
|
||||
* the returned path.
|
||||
*/
|
||||
char *lxc_cgroup_path_get(const char *filename, const char *name,
|
||||
const char *lxcpath)
|
||||
{
|
||||
char *subsystem = NULL, *longer_file = NULL, *p, *group, *path;
|
||||
|
||||
subsystem = alloca(strlen(filename) + 1);
|
||||
strcpy(subsystem, filename);
|
||||
if ((p = index(subsystem, '.')) != NULL) {
|
||||
*p = '\0';
|
||||
longer_file = alloca(strlen(filename) + 2);
|
||||
longer_file[0] = '/';
|
||||
strcpy(longer_file + 1, filename);
|
||||
}
|
||||
|
||||
group = lxc_cgroup_get_hierarchy_path(subsystem, name, lxcpath);
|
||||
if (!group)
|
||||
return NULL;
|
||||
|
||||
path = lxc_cgroup_find_abs_path(subsystem, group, true, p ? longer_file : NULL);
|
||||
free(group);
|
||||
return path;
|
||||
}
|
||||
|
||||
static bool cgroupfs_mount_cgroup(const char *root,
|
||||
struct lxc_cgroup_info *cgroup_info, int type)
|
||||
static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
|
||||
{
|
||||
size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
|
||||
char *path = NULL;
|
||||
@ -1339,9 +1336,9 @@ static bool cgroupfs_mount_cgroup(const char *root,
|
||||
struct cgroup_process_info *info, *base_info;
|
||||
int r, saved_errno = 0;
|
||||
|
||||
init_cg_ops();
|
||||
|
||||
cgfs_d = cgroup_info->data;
|
||||
cgfs_d = hdata;
|
||||
if (!cgfs_d)
|
||||
return false;
|
||||
base_info = cgfs_d->info;
|
||||
|
||||
if (type < LXC_AUTO_CGROUP_RO || type > LXC_AUTO_CGROUP_FULL_MIXED) {
|
||||
@ -1510,14 +1507,20 @@ out_error:
|
||||
return false;
|
||||
}
|
||||
|
||||
int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler)
|
||||
static int cgfs_nrtasks(void *hdata)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *info = d->info;
|
||||
struct cgfs_data *d = hdata;
|
||||
struct cgroup_process_info *info;
|
||||
struct cgroup_mount_point *mp = NULL;
|
||||
char *abs_path = NULL;
|
||||
int ret;
|
||||
|
||||
if (!d) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = d->info;
|
||||
if (!info) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
@ -1842,7 +1845,7 @@ static int do_cgroup_set(const char *cgroup_path, const char *sub_filename,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_setup_cgroup_limits(struct lxc_handler *h,
|
||||
static int do_setup_cgroup_limits(struct cgfs_data *d,
|
||||
struct lxc_list *cgroup_settings, bool do_devices)
|
||||
{
|
||||
struct lxc_list *iterator;
|
||||
@ -1857,14 +1860,14 @@ static int do_setup_cgroup_limits(struct lxc_handler *h,
|
||||
|
||||
if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
|
||||
if (strcmp(cg->subsystem, "devices.deny") == 0 &&
|
||||
cgroup_devices_has_allow_or_deny(h, cg->value, false))
|
||||
cgroup_devices_has_allow_or_deny(d, cg->value, false))
|
||||
continue;
|
||||
if (strcmp(cg->subsystem, "devices.allow") == 0 &&
|
||||
cgroup_devices_has_allow_or_deny(h, cg->value, true))
|
||||
cgroup_devices_has_allow_or_deny(d, cg->value, true))
|
||||
continue;
|
||||
if (lxc_cgroup_set_handler(cg->subsystem, cg->value, h)) {
|
||||
if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
|
||||
ERROR("Error setting %s to %s for %s\n",
|
||||
cg->subsystem, cg->value, h->name);
|
||||
cg->subsystem, cg->value, d->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -1878,7 +1881,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h,
|
||||
static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d,
|
||||
char *v, bool for_allow)
|
||||
{
|
||||
char *path;
|
||||
@ -1898,7 +1901,7 @@ static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h,
|
||||
if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
|
||||
return false;
|
||||
|
||||
parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_handler("devices", h);
|
||||
parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_data("devices", d);
|
||||
if (!parts[0])
|
||||
return false;
|
||||
path = lxc_string_join("/", parts, false);
|
||||
@ -2167,124 +2170,127 @@ static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
|
||||
do_init_cpuset_file(mp, path, "/cpuset.mems") );
|
||||
}
|
||||
|
||||
extern void lxc_monitor_send_state(const char *name, lxc_state_t state,
|
||||
const char *lxcpath);
|
||||
int do_unfreeze(int freeze, const char *name, const char *lxcpath)
|
||||
struct cgroup_ops *cgfs_ops_init(void)
|
||||
{
|
||||
char v[100];
|
||||
const char *state = freeze ? "FROZEN" : "THAWED";
|
||||
|
||||
if (lxc_cgroup_set("freezer.state", state, name, lxcpath) < 0) {
|
||||
ERROR("Failed to freeze %s:%s", lxcpath, name);
|
||||
return -1;
|
||||
}
|
||||
while (1) {
|
||||
if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0) {
|
||||
ERROR("Failed to get new freezer state for %s:%s", lxcpath, name);
|
||||
return -1;
|
||||
}
|
||||
if (v[strlen(v)-1] == '\n')
|
||||
v[strlen(v)-1] = '\0';
|
||||
if (strncmp(v, state, strlen(state)) == 0) {
|
||||
if (name)
|
||||
lxc_monitor_send_state(name, freeze ? FROZEN : THAWED, lxcpath);
|
||||
return 0;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
return &cgfs_ops;
|
||||
}
|
||||
|
||||
int freeze_unfreeze(const char *name, int freeze, const char *lxcpath)
|
||||
static void *cgfs_init(const char *name)
|
||||
{
|
||||
return do_unfreeze(freeze, name, lxcpath);
|
||||
struct cgfs_data *d;
|
||||
|
||||
d = malloc(sizeof(*d));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
d->name = strdup(name);
|
||||
if (!d->name)
|
||||
goto err1;
|
||||
|
||||
/* if we are running as root, use system cgroup pattern, otherwise
|
||||
* just create a cgroup under the current one. But also fall back to
|
||||
* that if for some reason reading the configuration fails and no
|
||||
* default value is available
|
||||
*/
|
||||
if (geteuid() == 0)
|
||||
d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
|
||||
if (!d->cgroup_pattern)
|
||||
d->cgroup_pattern = "%n";
|
||||
|
||||
d->meta = lxc_cgroup_load_meta();
|
||||
if (!d->meta) {
|
||||
ERROR("cgroupfs failed to detect cgroup metadata");
|
||||
goto err2;
|
||||
}
|
||||
return d;
|
||||
|
||||
err2:
|
||||
free(d->name);
|
||||
err1:
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lxc_state_t freezer_state(const char *name, const char *lxcpath)
|
||||
static void cgfs_destroy(void *hdata)
|
||||
{
|
||||
char v[100];
|
||||
if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0)
|
||||
return -1;
|
||||
struct cgfs_data *d = hdata;
|
||||
|
||||
if (v[strlen(v)-1] == '\n')
|
||||
v[strlen(v)-1] = '\0';
|
||||
return lxc_str2state(v);
|
||||
}
|
||||
|
||||
static void cgfs_destroy(struct lxc_handler *handler)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
if (!d)
|
||||
return;
|
||||
if (d->name)
|
||||
free(d->name);
|
||||
if (d->info)
|
||||
lxc_cgroup_process_info_free_and_remove(d->info);
|
||||
if (d->meta)
|
||||
lxc_cgroup_put_meta(d->meta);
|
||||
free(d);
|
||||
handler->cgroup_info->data = NULL;
|
||||
}
|
||||
|
||||
static inline bool cgfs_init(struct lxc_handler *handler)
|
||||
static inline bool cgfs_create(void *hdata)
|
||||
{
|
||||
struct cgfs_data *d = malloc(sizeof(*d));
|
||||
struct cgfs_data *d = hdata;
|
||||
struct cgroup_process_info *i;
|
||||
struct cgroup_meta_data *md;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
d->info = NULL;
|
||||
d->meta = lxc_cgroup_load_meta();
|
||||
|
||||
if (!d->meta) {
|
||||
ERROR("cgroupfs failed to detect cgroup metadata");
|
||||
free(d);
|
||||
return false;
|
||||
}
|
||||
handler->cgroup_info->data = d;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool cgfs_create(struct lxc_handler *handler)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *i;
|
||||
struct cgroup_meta_data *md = d->meta;
|
||||
i = lxc_cgroupfs_create(handler->name, handler->cgroup_info->cgroup_pattern, md, NULL);
|
||||
md = d->meta;
|
||||
i = lxc_cgroupfs_create(d->name, d->cgroup_pattern, md, NULL);
|
||||
if (!i)
|
||||
return false;
|
||||
d->info = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool cgfs_enter(struct lxc_handler *handler)
|
||||
static inline bool cgfs_enter(void *hdata, pid_t pid)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *i = d->info;
|
||||
struct cgfs_data *d = hdata;
|
||||
struct cgroup_process_info *i;
|
||||
int ret;
|
||||
|
||||
ret = lxc_cgroupfs_enter(i, handler->pid, false);
|
||||
if (!d)
|
||||
return false;
|
||||
i = d->info;
|
||||
ret = lxc_cgroupfs_enter(i, pid, false);
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
static inline bool cgfs_create_legacy(struct lxc_handler *handler)
|
||||
static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
|
||||
{
|
||||
struct cgfs_data *d = handler->cgroup_info->data;
|
||||
struct cgroup_process_info *i = d->info;
|
||||
if (lxc_cgroup_create_legacy(i, handler->name, handler->pid) < 0) {
|
||||
ERROR("failed to create legacy ns cgroups for '%s'", handler->name);
|
||||
struct cgfs_data *d = hdata;
|
||||
struct cgroup_process_info *i;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
i = d->info;
|
||||
if (lxc_cgroup_create_legacy(i, d->name, pid) < 0) {
|
||||
ERROR("failed to create legacy ns cgroups for '%s'", d->name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *cgfs_get_cgroup(struct lxc_handler *handler, const char *subsystem)
|
||||
static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
|
||||
{
|
||||
return lxc_cgroup_get_hierarchy_path_handler(subsystem, handler);
|
||||
struct cgfs_data *d = hdata;
|
||||
|
||||
if (!d)
|
||||
return NULL;
|
||||
return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
|
||||
}
|
||||
|
||||
static bool cgfs_unfreeze_fromhandler(struct lxc_handler *handler)
|
||||
static bool cgfs_unfreeze(void *hdata)
|
||||
{
|
||||
struct cgfs_data *d = hdata;
|
||||
char *cgabspath, *cgrelpath;
|
||||
int ret;
|
||||
|
||||
cgrelpath = lxc_cgroup_get_hierarchy_path_handler("freezer", handler);
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
cgrelpath = lxc_cgroup_get_hierarchy_path_data("freezer", d);
|
||||
cgabspath = lxc_cgroup_find_abs_path("freezer", cgrelpath, true, NULL);
|
||||
if (!cgabspath)
|
||||
return false;
|
||||
@ -2294,12 +2300,17 @@ static bool cgfs_unfreeze_fromhandler(struct lxc_handler *handler)
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
bool cgroupfs_setup_limits(struct lxc_handler *h, bool with_devices)
|
||||
static bool cgroupfs_setup_limits(void *hdata, struct lxc_list *cgroup_conf,
|
||||
bool with_devices)
|
||||
{
|
||||
return do_setup_cgroup_limits(h, &h->conf->cgroup, with_devices) == 0;
|
||||
struct cgfs_data *d = hdata;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
return do_setup_cgroup_limits(d, cgroup_conf, with_devices) == 0;
|
||||
}
|
||||
|
||||
bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
|
||||
static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
|
||||
{
|
||||
struct cgroup_meta_data *meta_data;
|
||||
struct cgroup_process_info *container_info;
|
||||
@ -2328,134 +2339,19 @@ bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
|
||||
}
|
||||
|
||||
static struct cgroup_ops cgfs_ops = {
|
||||
.destroy = cgfs_destroy,
|
||||
.init = cgfs_init,
|
||||
.destroy = cgfs_destroy,
|
||||
.create = cgfs_create,
|
||||
.enter = cgfs_enter,
|
||||
.create_legacy = cgfs_create_legacy,
|
||||
.get_cgroup = cgfs_get_cgroup,
|
||||
.get = lxc_cgroupfs_get,
|
||||
.set = lxc_cgroupfs_set,
|
||||
.unfreeze_fromhandler = cgfs_unfreeze_fromhandler,
|
||||
.unfreeze = cgfs_unfreeze,
|
||||
.setup_limits = cgroupfs_setup_limits,
|
||||
.name = "cgroupfs",
|
||||
.attach = lxc_cgroupfs_attach,
|
||||
.chown = NULL,
|
||||
.mount_cgroup = cgroupfs_mount_cgroup,
|
||||
.nrtasks = cgfs_nrtasks,
|
||||
};
|
||||
static void init_cg_ops(void)
|
||||
{
|
||||
if (!use_cgmanager)
|
||||
return;
|
||||
if (cgmanager_initialized)
|
||||
return;
|
||||
if (!lxc_init_cgmanager()) {
|
||||
ERROR("Could not contact cgroup manager, falling back to cgroupfs");
|
||||
active_cg_ops = &cgfs_ops;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the backend-independent cgroup handlers for container
|
||||
* start and stop
|
||||
*/
|
||||
|
||||
/* Free all cgroup info held by the handler */
|
||||
void cgroup_destroy(struct lxc_handler *handler)
|
||||
{
|
||||
if (!handler->cgroup_info)
|
||||
return;
|
||||
if (active_cg_ops)
|
||||
active_cg_ops->destroy(handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a lxc_cgroup_info for the active cgroup
|
||||
* backend, and assign it to the handler
|
||||
*/
|
||||
bool cgroup_init(struct lxc_handler *handler)
|
||||
{
|
||||
init_cg_ops();
|
||||
handler->cgroup_info = malloc(sizeof(struct lxc_cgroup_info));
|
||||
if (!handler->cgroup_info)
|
||||
return false;
|
||||
memset(handler->cgroup_info, 0, sizeof(struct lxc_cgroup_info));
|
||||
/* if we are running as root, use system cgroup pattern, otherwise
|
||||
* just create a cgroup under the current one. But also fall back to
|
||||
* that if for some reason reading the configuration fails and no
|
||||
* default value is available
|
||||
*/
|
||||
if (geteuid() == 0)
|
||||
handler->cgroup_info->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
|
||||
if (!handler->cgroup_info->cgroup_pattern)
|
||||
handler->cgroup_info->cgroup_pattern = "%n";
|
||||
|
||||
return active_cg_ops->init(handler);
|
||||
}
|
||||
|
||||
/* Create the container cgroups for all requested controllers */
|
||||
bool cgroup_create(struct lxc_handler *handler)
|
||||
{
|
||||
return active_cg_ops->create(handler);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enter the container init into its new cgroups for all
|
||||
* requested controllers */
|
||||
bool cgroup_enter(struct lxc_handler *handler)
|
||||
{
|
||||
return active_cg_ops->enter(handler);
|
||||
}
|
||||
|
||||
bool cgroup_create_legacy(struct lxc_handler *handler)
|
||||
{
|
||||
if (active_cg_ops->create_legacy)
|
||||
return active_cg_ops->create_legacy(handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
|
||||
{
|
||||
return active_cg_ops->get_cgroup(handler, subsystem);
|
||||
}
|
||||
|
||||
int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
|
||||
{
|
||||
init_cg_ops();
|
||||
return active_cg_ops->set(filename, value, name, lxcpath);
|
||||
}
|
||||
|
||||
int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
|
||||
{
|
||||
init_cg_ops();
|
||||
return active_cg_ops->get(filename, value, len, name, lxcpath);
|
||||
}
|
||||
|
||||
bool lxc_unfreeze_fromhandler(struct lxc_handler *handler)
|
||||
{
|
||||
return active_cg_ops->unfreeze_fromhandler(handler);
|
||||
}
|
||||
|
||||
bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
|
||||
{
|
||||
return active_cg_ops->setup_limits(handler, with_devices);
|
||||
}
|
||||
|
||||
bool cgroup_chown(struct lxc_handler *handler)
|
||||
{
|
||||
if (active_cg_ops->chown)
|
||||
return active_cg_ops->chown(handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
|
||||
{
|
||||
init_cg_ops();
|
||||
return active_cg_ops->attach(name, lxcpath, pid);
|
||||
}
|
||||
|
||||
bool lxc_setup_mount_cgroup(const char *root,
|
||||
struct lxc_cgroup_info *cgroup_info, int type)
|
||||
{
|
||||
return active_cg_ops->mount_cgroup(root, cgroup_info, type);
|
||||
}
|
||||
|
@ -58,24 +58,74 @@ lxc_log_define(lxc_cgmanager, lxc);
|
||||
#include <nih/alloc.h>
|
||||
#include <nih/error.h>
|
||||
#include <nih/string.h>
|
||||
NihDBusProxy *cgroup_manager = NULL;
|
||||
|
||||
extern struct cgroup_ops *active_cg_ops;
|
||||
bool cgmanager_initialized = false;
|
||||
bool use_cgmanager = true;
|
||||
struct cgm_data {
|
||||
char *name;
|
||||
char *cgroup_path;
|
||||
const char *cgroup_pattern;
|
||||
};
|
||||
|
||||
static NihDBusProxy *cgroup_manager = NULL;
|
||||
static struct cgroup_ops cgmanager_ops;
|
||||
static int nr_subsystems;
|
||||
static char **subsystems;
|
||||
|
||||
bool lxc_init_cgmanager(void);
|
||||
static void cgmanager_disconnected(DBusConnection *connection)
|
||||
#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
|
||||
static void cgm_dbus_disconnected(DBusConnection *connection);
|
||||
static bool cgm_dbus_connect(void)
|
||||
{
|
||||
DBusError dbus_error;
|
||||
DBusConnection *connection;
|
||||
dbus_error_init(&dbus_error);
|
||||
|
||||
connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgm_dbus_disconnected);
|
||||
if (!connection) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
DEBUG("Unable to open cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
|
||||
nerr->message);
|
||||
nih_free(nerr);
|
||||
dbus_error_free(&dbus_error);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_set_exit_on_disconnect(connection, FALSE);
|
||||
dbus_error_free(&dbus_error);
|
||||
cgroup_manager = nih_dbus_proxy_new(NULL, connection,
|
||||
NULL /* p2p */,
|
||||
"/org/linuxcontainers/cgmanager", NULL, NULL);
|
||||
dbus_connection_unref(connection);
|
||||
if (!cgroup_manager) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("Error opening cgmanager proxy: %s", nerr->message);
|
||||
nih_free(nerr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// force fd passing negotiation
|
||||
if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("Error pinging cgroup manager: %s", nerr->message);
|
||||
nih_free(nerr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cgm_dbus_disconnect(void)
|
||||
{
|
||||
nih_free(cgroup_manager);
|
||||
cgroup_manager = NULL;
|
||||
}
|
||||
|
||||
static void cgm_dbus_disconnected(DBusConnection *connection)
|
||||
{
|
||||
WARN("Cgroup manager connection was terminated");
|
||||
cgroup_manager = NULL;
|
||||
cgmanager_initialized = false;
|
||||
if (lxc_init_cgmanager()) {
|
||||
cgmanager_initialized = true;
|
||||
if (cgm_dbus_connect()) {
|
||||
INFO("New cgroup manager connection was opened");
|
||||
} else {
|
||||
WARN("Cgroup manager unable to re-open connection");
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,47 +165,6 @@ static int send_creds(int sock, int rpid, int ruid, int rgid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
|
||||
bool lxc_init_cgmanager(void)
|
||||
{
|
||||
DBusError dbus_error;
|
||||
DBusConnection *connection;
|
||||
dbus_error_init(&dbus_error);
|
||||
|
||||
connection = nih_dbus_connect(CGMANAGER_DBUS_SOCK, cgmanager_disconnected);
|
||||
if (!connection) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("Error opening cgmanager connection at %s: %s", CGMANAGER_DBUS_SOCK,
|
||||
nerr->message);
|
||||
nih_free(nerr);
|
||||
dbus_error_free(&dbus_error);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_set_exit_on_disconnect(connection, FALSE);
|
||||
dbus_error_free(&dbus_error);
|
||||
cgroup_manager = nih_dbus_proxy_new(NULL, connection,
|
||||
NULL /* p2p */,
|
||||
"/org/linuxcontainers/cgmanager", NULL, NULL);
|
||||
dbus_connection_unref(connection);
|
||||
if (!cgroup_manager) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("Error opening cgmanager proxy: %s", nerr->message);
|
||||
nih_free(nerr);
|
||||
return false;
|
||||
}
|
||||
active_cg_ops = &cgmanager_ops;
|
||||
// force fd passing negotiation
|
||||
if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("Error pinging cgroup manager: %s", nerr->message);
|
||||
nih_free(nerr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
|
||||
{
|
||||
if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
|
||||
@ -341,19 +350,49 @@ static void cgm_remove_cgroup(const char *controller, const char *path)
|
||||
INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
|
||||
}
|
||||
|
||||
static void cgm_destroy(struct lxc_handler *handler)
|
||||
static void *cgm_init(const char *name)
|
||||
{
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
struct cgm_data *d;
|
||||
|
||||
d = malloc(sizeof(*d));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
d->name = strdup(name);
|
||||
if (!d->name)
|
||||
goto err1;
|
||||
|
||||
/* if we are running as root, use system cgroup pattern, otherwise
|
||||
* just create a cgroup under the current one. But also fall back to
|
||||
* that if for some reason reading the configuration fails and no
|
||||
* default value is available
|
||||
*/
|
||||
if (geteuid() == 0)
|
||||
d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
|
||||
if (!d->cgroup_pattern)
|
||||
d->cgroup_pattern = "%n";
|
||||
return d;
|
||||
|
||||
err1:
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cgm_destroy(void *hdata)
|
||||
{
|
||||
struct cgm_data *d = hdata;
|
||||
int i;
|
||||
|
||||
if (!cgroup_path)
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_subsystems; i++)
|
||||
cgm_remove_cgroup(subsystems[i], cgroup_path);
|
||||
cgm_remove_cgroup(subsystems[i], d->cgroup_path);
|
||||
|
||||
free(cgroup_path);
|
||||
handler->cgroup_info->data = NULL;
|
||||
free(d->name);
|
||||
if (d->cgroup_path)
|
||||
free(d->cgroup_path);
|
||||
free(d);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -366,19 +405,21 @@ static inline void cleanup_cgroups(char *path)
|
||||
cgm_remove_cgroup(subsystems[i], path);
|
||||
}
|
||||
|
||||
static inline bool cgm_create(struct lxc_handler *handler)
|
||||
static inline bool cgm_create(void *hdata)
|
||||
{
|
||||
struct cgm_data *d = hdata;
|
||||
int i, index=0, baselen, ret;
|
||||
int32_t existed;
|
||||
char result[MAXPATHLEN], *tmp;
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
char result[MAXPATHLEN], *tmp, *cgroup_path;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
// XXX we should send a hint to the cgmanager that when these
|
||||
// cgroups become empty they should be deleted. Requires a cgmanager
|
||||
// extension
|
||||
|
||||
memset(result, 0, MAXPATHLEN);
|
||||
tmp = lxc_string_replace("%n", handler->name, handler->cgroup_info->cgroup_pattern);
|
||||
tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
|
||||
if (!tmp)
|
||||
return false;
|
||||
if (strlen(tmp) > MAXPATHLEN)
|
||||
@ -415,7 +456,7 @@ again:
|
||||
cleanup_cgroups(tmp);
|
||||
return false;
|
||||
}
|
||||
handler->cgroup_info->data = cgroup_path;
|
||||
d->cgroup_path = cgroup_path;
|
||||
return true;
|
||||
next:
|
||||
cleanup_cgroups(tmp);
|
||||
@ -454,19 +495,25 @@ static bool do_cgm_enter(pid_t pid, const char *cgroup_path)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool cgm_enter(struct lxc_handler *handler)
|
||||
static inline bool cgm_enter(void *hdata, pid_t pid)
|
||||
{
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
return do_cgm_enter(handler->pid, cgroup_path);
|
||||
struct cgm_data *d = hdata;
|
||||
|
||||
if (!d || !d->cgroup_path)
|
||||
return false;
|
||||
return do_cgm_enter(pid, d->cgroup_path);
|
||||
}
|
||||
|
||||
static char *cgm_get_cgroup(struct lxc_handler *handler, const char *subsystem)
|
||||
static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
|
||||
{
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
return cgroup_path;
|
||||
struct cgm_data *d = hdata;
|
||||
|
||||
if (!d || !d->cgroup_path)
|
||||
return NULL;
|
||||
return d->cgroup_path;
|
||||
}
|
||||
|
||||
int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
|
||||
static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
|
||||
{
|
||||
char *result, *controller, *key, *cgroup;
|
||||
size_t newlen;
|
||||
@ -531,7 +578,7 @@ static int cgm_do_set(const char *controller, const char *file,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
|
||||
static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
|
||||
{
|
||||
char *controller, *key, *cgroup;
|
||||
int ret;
|
||||
@ -555,10 +602,21 @@ int cgm_set(const char *filename, const char *value, const char *name, const cha
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_subsystems(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_subsystems; i++)
|
||||
free(subsystems[i]);
|
||||
free(subsystems);
|
||||
subsystems = NULL;
|
||||
nr_subsystems = 0;
|
||||
}
|
||||
|
||||
static bool collect_subsytems(void)
|
||||
{
|
||||
char *line = NULL, *tab1;
|
||||
size_t sz = 0, i;
|
||||
size_t sz = 0;
|
||||
FILE *f;
|
||||
|
||||
if (subsystems) // already initialized
|
||||
@ -598,51 +656,62 @@ static bool collect_subsytems(void)
|
||||
|
||||
out_free:
|
||||
fclose(f);
|
||||
for (i = 0; i < nr_subsystems; i++)
|
||||
free(subsystems[i]);
|
||||
free(subsystems);
|
||||
subsystems = NULL;
|
||||
nr_subsystems = 0;
|
||||
free_subsystems();
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool cgm_init(struct lxc_handler *handler)
|
||||
struct cgroup_ops *cgm_ops_init(void)
|
||||
{
|
||||
if (!collect_subsytems())
|
||||
return false;
|
||||
if (geteuid())
|
||||
return true;
|
||||
return NULL;
|
||||
if (!cgm_dbus_connect())
|
||||
goto err1;
|
||||
|
||||
// root; try to escape to root cgroup
|
||||
return lxc_cgmanager_escape();
|
||||
if (geteuid() == 0 && !lxc_cgmanager_escape())
|
||||
goto err2;
|
||||
|
||||
return &cgmanager_ops;
|
||||
|
||||
err2:
|
||||
cgm_dbus_disconnect();
|
||||
err1:
|
||||
free_subsystems();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool cgm_unfreeze_fromhandler(struct lxc_handler *handler)
|
||||
static bool cgm_unfreeze(void *hdata)
|
||||
{
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
struct cgm_data *d = hdata;
|
||||
|
||||
if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", cgroup_path,
|
||||
if (!d || !d->cgroup_path)
|
||||
return false;
|
||||
|
||||
if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
|
||||
"freezer.state", "THAWED") != 0) {
|
||||
NihError *nerr;
|
||||
nerr = nih_error_get();
|
||||
ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
|
||||
nih_free(nerr);
|
||||
ERROR("Error unfreezing %s", cgroup_path);
|
||||
ERROR("Error unfreezing %s", d->cgroup_path);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setup_limits(struct lxc_handler *h, bool do_devices)
|
||||
static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
|
||||
{
|
||||
struct cgm_data *d = hdata;
|
||||
struct lxc_list *iterator;
|
||||
struct lxc_cgroup *cg;
|
||||
bool ret = false;
|
||||
struct lxc_list *cgroup_settings = &h->conf->cgroup;
|
||||
char *cgroup_path = h->cgroup_info->data;
|
||||
|
||||
if (lxc_list_empty(cgroup_settings))
|
||||
return true;
|
||||
|
||||
if (!d || !d->cgroup_path)
|
||||
return false;
|
||||
|
||||
lxc_list_for_each(iterator, cgroup_settings) {
|
||||
char controller[100], *p;
|
||||
cg = iterator->elem;
|
||||
@ -654,10 +723,10 @@ static bool setup_limits(struct lxc_handler *h, bool do_devices)
|
||||
p = strchr(controller, '.');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
if (cgm_do_set(controller, cg->subsystem, cgroup_path
|
||||
if (cgm_do_set(controller, cg->subsystem, d->cgroup_path
|
||||
, cg->value) < 0) {
|
||||
ERROR("Error setting %s to %s for %s\n",
|
||||
cg->subsystem, cg->value, h->name);
|
||||
cg->subsystem, cg->value, d->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -670,20 +739,17 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool cgm_setup_limits(struct lxc_handler *handler, bool with_devices)
|
||||
static bool cgm_chown(void *hdata, struct lxc_conf *conf)
|
||||
{
|
||||
return setup_limits(handler, with_devices);
|
||||
}
|
||||
|
||||
static bool cgm_chown(struct lxc_handler *handler)
|
||||
{
|
||||
char *cgroup_path = handler->cgroup_info->data;
|
||||
struct cgm_data *d = hdata;
|
||||
int i;
|
||||
|
||||
if (!d || !d->cgroup_path)
|
||||
return false;
|
||||
for (i = 0; i < nr_subsystems; i++) {
|
||||
if (!chown_cgroup(subsystems[i], cgroup_path, handler->conf))
|
||||
if (!chown_cgroup(subsystems[i], d->cgroup_path, conf))
|
||||
WARN("Failed to chown %s:%s to container root",
|
||||
subsystems[i], cgroup_path);
|
||||
subsystems[i], d->cgroup_path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -771,8 +837,7 @@ static bool cgm_bind_dir(const char *root, const char *dirname)
|
||||
*/
|
||||
#define CGMANAGER_LOWER_SOCK "/sys/fs/cgroup/cgmanager.lower"
|
||||
#define CGMANAGER_UPPER_SOCK "/sys/fs/cgroup/cgmanager"
|
||||
static bool cgm_mount_cgroup(const char *root,
|
||||
struct lxc_cgroup_info *cgroup_info, int type)
|
||||
static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
|
||||
{
|
||||
if (dir_exists(CGMANAGER_LOWER_SOCK))
|
||||
return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
|
||||
@ -783,19 +848,20 @@ static bool cgm_mount_cgroup(const char *root,
|
||||
}
|
||||
|
||||
static struct cgroup_ops cgmanager_ops = {
|
||||
.destroy = cgm_destroy,
|
||||
.init = cgm_init,
|
||||
.destroy = cgm_destroy,
|
||||
.create = cgm_create,
|
||||
.enter = cgm_enter,
|
||||
.create_legacy = NULL,
|
||||
.get_cgroup = cgm_get_cgroup,
|
||||
.get = cgm_get,
|
||||
.set = cgm_set,
|
||||
.unfreeze_fromhandler = cgm_unfreeze_fromhandler,
|
||||
.unfreeze = cgm_unfreeze,
|
||||
.setup_limits = cgm_setup_limits,
|
||||
.name = "cgmanager",
|
||||
.chown = cgm_chown,
|
||||
.attach = cgm_attach,
|
||||
.mount_cgroup = cgm_mount_cgroup,
|
||||
.nrtasks = NULL,
|
||||
};
|
||||
#endif
|
||||
|
169
src/lxc/cgroup.c
Normal file
169
src/lxc/cgroup.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* lxc: linux Container library
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2007, 2008
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Lezcano <daniel.lezcano at free.fr>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "cgroup.h"
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "start.h"
|
||||
|
||||
lxc_log_define(lxc_cgroup, lxc);
|
||||
|
||||
static struct cgroup_ops *ops = NULL;
|
||||
|
||||
extern struct cgroup_ops *cgfs_ops_init(void);
|
||||
extern struct cgroup_ops *cgm_ops_init(void);
|
||||
|
||||
__attribute__((constructor))
|
||||
void cgroup_ops_init(void)
|
||||
{
|
||||
if (ops) {
|
||||
INFO("cgroup driver %s", ops->name);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("cgroup_init");
|
||||
#if HAVE_CGMANAGER
|
||||
ops = cgm_ops_init();
|
||||
#endif
|
||||
if (!ops)
|
||||
ops = cgfs_ops_init();
|
||||
if (ops)
|
||||
INFO("Initialized cgroup driver %s", ops->name);
|
||||
}
|
||||
|
||||
bool cgroup_init(struct lxc_handler *handler)
|
||||
{
|
||||
if (handler->cgroup_data) {
|
||||
ERROR("cgroup_init called on already inited handler");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ops) {
|
||||
INFO("cgroup driver %s initing for %s", ops->name, handler->name);
|
||||
handler->cgroup_data = ops->init(handler->name);
|
||||
}
|
||||
return handler->cgroup_data != NULL;
|
||||
}
|
||||
|
||||
void cgroup_destroy(struct lxc_handler *handler)
|
||||
{
|
||||
if (ops) {
|
||||
ops->destroy(handler->cgroup_data);
|
||||
handler->cgroup_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enter the container init into its new cgroups for all
|
||||
* requested controllers
|
||||
*/
|
||||
bool cgroup_enter(struct lxc_handler *handler)
|
||||
{
|
||||
if (ops)
|
||||
return ops->enter(handler->cgroup_data, handler->pid);
|
||||
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_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->cgroup, with_devices);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cgroup_chown(struct lxc_handler *handler)
|
||||
{
|
||||
if (ops && ops->chown)
|
||||
return ops->chown(handler->cgroup_data, handler->conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
|
||||
{
|
||||
if (ops) {
|
||||
return ops->mount_cgroup(handler->cgroup_data, root, type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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->name);
|
||||
}
|
||||
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;
|
||||
}
|
207
src/lxc/cgroup.h
207
src/lxc/cgroup.h
@ -20,195 +20,39 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef _ncgroup_h
|
||||
#define _ncgroup_h
|
||||
|
||||
#ifndef __lxc_cgroup_h
|
||||
#define __lxc_cgroup_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "state.h"
|
||||
|
||||
struct cgroup_hierarchy;
|
||||
struct cgroup_meta_data;
|
||||
struct cgroup_mount_point;
|
||||
|
||||
/*
|
||||
* cgroup_meta_data: the metadata about the cgroup infrastructure on this
|
||||
* host
|
||||
*/
|
||||
struct cgroup_meta_data {
|
||||
ptrdiff_t ref; /* simple refcount */
|
||||
struct cgroup_hierarchy **hierarchies;
|
||||
struct cgroup_mount_point **mount_points;
|
||||
int maximum_hierarchy;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_hierarchy: describes a single cgroup hierarchy
|
||||
* (may have multiple mount points)
|
||||
*/
|
||||
struct cgroup_hierarchy {
|
||||
int index;
|
||||
bool used; /* false if the hierarchy should be ignored by lxc */
|
||||
char **subsystems;
|
||||
struct cgroup_mount_point *rw_absolute_mount_point;
|
||||
struct cgroup_mount_point *ro_absolute_mount_point;
|
||||
struct cgroup_mount_point **all_mount_points;
|
||||
size_t all_mount_point_capacity;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_mount_point: a mount point to where a hierarchy
|
||||
* is mounted to
|
||||
*/
|
||||
struct cgroup_mount_point {
|
||||
struct cgroup_hierarchy *hierarchy;
|
||||
char *mount_point;
|
||||
char *mount_prefix;
|
||||
bool read_only;
|
||||
bool need_cpuset_init;
|
||||
};
|
||||
|
||||
/*
|
||||
* cgroup_process_info: describes the membership of a
|
||||
* process to the different cgroup
|
||||
* hierarchies
|
||||
*
|
||||
* Note this is the per-process info tracked by the cgfs_ops.
|
||||
* This is not used with cgmanager.
|
||||
*/
|
||||
struct cgroup_process_info {
|
||||
struct cgroup_process_info *next;
|
||||
struct cgroup_meta_data *meta_ref;
|
||||
struct cgroup_hierarchy *hierarchy;
|
||||
char *cgroup_path;
|
||||
char *cgroup_path_sub;
|
||||
char **created_paths;
|
||||
size_t created_paths_capacity;
|
||||
size_t created_paths_count;
|
||||
struct cgroup_mount_point *designated_mount_point;
|
||||
};
|
||||
|
||||
/* meta data management:
|
||||
* lxc_cgroup_load_meta loads the meta data (using subsystem
|
||||
* whitelist from main lxc configuration)
|
||||
* lxc_cgroup_load_meta2 does the same, but allows one to specify
|
||||
* a custom whitelist
|
||||
* lxc_cgroup_get_meta increments the refcount of a meta data
|
||||
* object
|
||||
* lxc_cgroup_put_meta decrements the refcount of a meta data
|
||||
* object, potentially destroying it
|
||||
*/
|
||||
extern struct cgroup_meta_data *lxc_cgroup_load_meta();
|
||||
extern struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
|
||||
extern struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
|
||||
extern struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
|
||||
|
||||
/* find the hierarchy corresponding to a given subsystem */
|
||||
extern struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem);
|
||||
|
||||
/* find a mount point for a given hierarchy that has access to the cgroup in 'cgroup' and (if wanted) is writable */
|
||||
extern struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable);
|
||||
|
||||
/* all-in-one: find a mount point for a given hierarchy that has access to the cgroup and return the correct path within */
|
||||
extern char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix);
|
||||
|
||||
/* determine the cgroup membership of a given process */
|
||||
extern struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta);
|
||||
extern struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta);
|
||||
extern struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta);
|
||||
|
||||
/* create a new cgroup */
|
||||
extern struct cgroup_process_info *lxc_cgroup_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern);
|
||||
extern int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid);
|
||||
|
||||
/* get the cgroup membership of a given container */
|
||||
extern struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data);
|
||||
|
||||
/* move a processs to the cgroups specified by the membership TODO - deprecated, switch users to cgroup_enter() */
|
||||
extern int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub);
|
||||
|
||||
/* free process membership information */
|
||||
extern void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
|
||||
extern void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info);
|
||||
#include <sys/types.h>
|
||||
|
||||
struct lxc_handler;
|
||||
extern char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, const char *lxcpath);
|
||||
extern char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler);
|
||||
extern char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath);
|
||||
extern int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler);
|
||||
extern int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct lxc_handler *handler);
|
||||
|
||||
/*
|
||||
* lxc_cgroup_path_get: Get the absolute pathname for a cgroup
|
||||
* file for a running container.
|
||||
*
|
||||
* @filename : the file of interest (e.g. "freezer.state") or
|
||||
* the subsystem name (e.g. "freezer") in which case
|
||||
* the directory where the cgroup may be modified
|
||||
* will be returned
|
||||
* @name : name of container to connect to
|
||||
* @lxcpath : the lxcpath in which the container is running
|
||||
*
|
||||
* This is the exported function, which determines cgpath from the
|
||||
* lxc-start of the @name container running in @lxcpath.
|
||||
*
|
||||
* Returns path on success, NULL on error. The caller must free()
|
||||
* the returned path.
|
||||
*/
|
||||
extern char *lxc_cgroup_path_get(const char *filename, const char *name,
|
||||
const char *lxcpath);
|
||||
|
||||
struct lxc_conf;
|
||||
struct lxc_list;
|
||||
extern int lxc_setup_cgroup_without_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings);
|
||||
extern int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings);
|
||||
|
||||
extern int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler);
|
||||
|
||||
extern int do_unfreeze(int freeze, const char *name, const char *lxcpath);
|
||||
extern int freeze_unfreeze(const char *name, int freeze, const char *lxcpath);
|
||||
extern const char *lxc_state2str(lxc_state_t state);
|
||||
extern lxc_state_t freezer_state(const char *name, const char *lxcpath);
|
||||
|
||||
/*
|
||||
* cgroup-related data for backend use in start/stop of a
|
||||
* container. This is tacked to the lxc_handler.
|
||||
*/
|
||||
struct lxc_cgroup_info {
|
||||
/* handlers to actually do the cgroup stuff */
|
||||
struct cgroup_ops *ops;
|
||||
/* extra data for the cgroup_ops, i.e. mountpoints for fs backend */
|
||||
void *data;
|
||||
const char *cgroup_pattern;
|
||||
};
|
||||
|
||||
/* per-backend cgroup hooks */
|
||||
struct cgroup_ops {
|
||||
void (*destroy)(struct lxc_handler *handler);
|
||||
bool (*init)(struct lxc_handler *handler);
|
||||
bool (*create)(struct lxc_handler *handler);
|
||||
bool (*enter)(struct lxc_handler *handler);
|
||||
bool (*create_legacy)(struct lxc_handler *handler);
|
||||
char *(*get_cgroup)(struct lxc_handler *handler, const char *subsystem);
|
||||
const char *name;
|
||||
|
||||
void *(*init)(const char *name);
|
||||
void (*destroy)(void *hdata);
|
||||
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);
|
||||
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_fromhandler)(struct lxc_handler *handler);
|
||||
bool (*setup_limits)(struct lxc_handler *handler, bool with_devices);
|
||||
bool (*chown)(struct lxc_handler *handler);
|
||||
bool (*unfreeze)(void *hdata);
|
||||
bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_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)(const char *root, struct lxc_cgroup_info *info,
|
||||
int type);
|
||||
const char *name;
|
||||
bool (*mount_cgroup)(void *hdata, const char *root, int type);
|
||||
int (*nrtasks)(void *hdata);
|
||||
};
|
||||
|
||||
struct cgfs_data {
|
||||
struct cgroup_meta_data *meta;
|
||||
struct cgroup_process_info *info;
|
||||
};
|
||||
|
||||
/*
|
||||
* backend-independent cgroup handlers
|
||||
*/
|
||||
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);
|
||||
@ -217,11 +61,8 @@ 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 char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
|
||||
extern bool lxc_cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
|
||||
extern bool lxc_setup_mount_cgroup(const char *root, struct lxc_cgroup_info *cgroup_info, int type);
|
||||
extern bool lxc_unfreeze_fromhandler(struct lxc_handler *handler);
|
||||
extern int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath);
|
||||
extern int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
|
||||
extern int cgroup_nrtasks(struct lxc_handler *handler);
|
||||
extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
|
||||
extern bool cgroup_unfreeze(struct lxc_handler *handler);
|
||||
|
||||
#endif
|
||||
|
@ -430,7 +430,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
|
||||
struct lxc_handler *handler)
|
||||
{
|
||||
struct lxc_cmd_rsp rsp;
|
||||
char *path;
|
||||
const char *path;
|
||||
|
||||
if (req->datalen < 1)
|
||||
return -1;
|
||||
@ -439,7 +439,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
|
||||
if (!path)
|
||||
return -1;
|
||||
rsp.datalen = strlen(path) + 1,
|
||||
rsp.data = path;
|
||||
rsp.data = (char *)path;
|
||||
rsp.ret = 0;
|
||||
|
||||
return lxc_cmd_rsp_send(fd, &rsp);
|
||||
@ -590,7 +590,12 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
rsp.ret = kill(handler->pid, stopsignal);
|
||||
if (!rsp.ret) {
|
||||
if (lxc_unfreeze_fromhandler(handler))
|
||||
/* we can't just use lxc_unfreeze() since we are already in the
|
||||
* context of handling the STOP cmd in lxc-start, and calling
|
||||
* lxc_unfreeze() would do another cmd (GET_CGROUP) which would
|
||||
* deadlock us
|
||||
*/
|
||||
if (cgroup_unfreeze(handler))
|
||||
return 0;
|
||||
ERROR("Failed to unfreeze %s:%s", handler->lxcpath, handler->name);
|
||||
rsp.ret = -1;
|
||||
|
@ -63,7 +63,6 @@
|
||||
#include "utils.h"
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "lxc.h" /* for lxc_cgroup_set() */
|
||||
#include "caps.h" /* for lxc_caps_last_cap() */
|
||||
#include "bdev.h"
|
||||
#include "cgroup.h"
|
||||
@ -670,7 +669,7 @@ int pin_rootfs(const char *rootfs)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cgroup_info *cgroup_info)
|
||||
static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_handler *handler)
|
||||
{
|
||||
int r;
|
||||
size_t i;
|
||||
@ -744,7 +743,7 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cg
|
||||
}
|
||||
|
||||
if (flags & LXC_AUTO_CGROUP_MASK) {
|
||||
if (!lxc_setup_mount_cgroup(conf->rootfs.mount, cgroup_info,
|
||||
if (!cgroup_mount(conf->rootfs.mount, handler,
|
||||
flags & LXC_AUTO_CGROUP_MASK)) {
|
||||
SYSERROR("error mounting /sys/fs/cgroup");
|
||||
return -1;
|
||||
@ -3500,7 +3499,6 @@ int lxc_setup(struct lxc_handler *handler)
|
||||
struct lxc_conf *lxc_conf = handler->conf;
|
||||
const char *lxcpath = handler->lxcpath;
|
||||
void *data = handler->data;
|
||||
struct lxc_cgroup_info *cgroup_info = handler->cgroup_info;
|
||||
|
||||
if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
|
||||
if (setup_utsname(lxc_conf->utsname)) {
|
||||
@ -3538,7 +3536,7 @@ int lxc_setup(struct lxc_handler *handler)
|
||||
/* do automatic mounts (mainly /proc and /sys), but exclude
|
||||
* those that need to wait until other stuff has finished
|
||||
*/
|
||||
if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
|
||||
if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & ~LXC_AUTO_CGROUP_MASK, handler) < 0) {
|
||||
ERROR("failed to setup the automatic mounts for '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
@ -3557,7 +3555,7 @@ int lxc_setup(struct lxc_handler *handler)
|
||||
* before, /sys could not have been mounted
|
||||
* (is either mounted automatically or via fstab entries)
|
||||
*/
|
||||
if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, cgroup_info) < 0) {
|
||||
if (lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler) < 0) {
|
||||
ERROR("failed to setup the automatic mounts for '%s'", name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -35,18 +35,53 @@
|
||||
#include "state.h"
|
||||
#include "monitor.h"
|
||||
#include "log.h"
|
||||
#include "cgroup.h"
|
||||
#include "lxc.h"
|
||||
|
||||
lxc_log_define(lxc_freezer, lxc);
|
||||
|
||||
lxc_state_t freezer_state(const char *name, const char *lxcpath)
|
||||
{
|
||||
char v[100];
|
||||
if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0)
|
||||
return -1;
|
||||
|
||||
if (v[strlen(v)-1] == '\n')
|
||||
v[strlen(v)-1] = '\0';
|
||||
return lxc_str2state(v);
|
||||
}
|
||||
|
||||
static int do_freeze_thaw(int freeze, const char *name, const char *lxcpath)
|
||||
{
|
||||
char v[100];
|
||||
const char *state = freeze ? "FROZEN" : "THAWED";
|
||||
|
||||
if (lxc_cgroup_set("freezer.state", state, name, lxcpath) < 0) {
|
||||
ERROR("Failed to freeze %s:%s", lxcpath, name);
|
||||
return -1;
|
||||
}
|
||||
while (1) {
|
||||
if (lxc_cgroup_get("freezer.state", v, 100, name, lxcpath) < 0) {
|
||||
ERROR("Failed to get new freezer state for %s:%s", lxcpath, name);
|
||||
return -1;
|
||||
}
|
||||
if (v[strlen(v)-1] == '\n')
|
||||
v[strlen(v)-1] = '\0';
|
||||
if (strncmp(v, state, strlen(state)) == 0) {
|
||||
if (name)
|
||||
lxc_monitor_send_state(name, freeze ? FROZEN : THAWED, lxcpath);
|
||||
return 0;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
int lxc_freeze(const char *name, const char *lxcpath)
|
||||
{
|
||||
lxc_monitor_send_state(name, FREEZING, lxcpath);
|
||||
return freeze_unfreeze(name, 1, lxcpath);
|
||||
return do_freeze_thaw(1, name, lxcpath);
|
||||
}
|
||||
|
||||
int lxc_unfreeze(const char *name, const char *lxcpath)
|
||||
{
|
||||
return freeze_unfreeze(name, 0, lxcpath);
|
||||
return do_freeze_thaw(0, name, lxcpath);
|
||||
}
|
||||
|
@ -129,17 +129,6 @@ extern int lxc_unfreeze(const char *name, const char *lxcpath);
|
||||
*/
|
||||
extern lxc_state_t lxc_state(const char *name, const char *lxcpath);
|
||||
|
||||
struct lxc_handler;
|
||||
/*
|
||||
* 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
|
||||
* @handler : the lxc_handler structure of the container
|
||||
* Returns 0 on success, < 0 otherwise
|
||||
*/
|
||||
extern int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler);
|
||||
|
||||
/*
|
||||
* Set a specified value for a specified subsystem. The specified
|
||||
* subsystem must be fully specified, eg. "cpu.shares"
|
||||
|
@ -291,7 +291,7 @@ static int utmp_get_ntasks(struct lxc_handler *handler)
|
||||
{
|
||||
int ntasks;
|
||||
|
||||
ntasks = lxc_cgroup_nrtasks_handler(handler);
|
||||
ntasks = cgroup_nrtasks(handler);
|
||||
|
||||
if (ntasks < 0) {
|
||||
ERROR("failed to get the number of tasks");
|
||||
|
@ -70,7 +70,7 @@ struct lxc_handler {
|
||||
int sv[2];
|
||||
int pinfd;
|
||||
const char *lxcpath;
|
||||
struct lxc_cgroup_info *cgroup_info;
|
||||
void *cgroup_data;
|
||||
};
|
||||
|
||||
extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *, const char *);
|
||||
|
@ -69,6 +69,8 @@ lxc_state_t lxc_str2state(const char *state)
|
||||
|
||||
lxc_state_t lxc_getstate(const char *name, const char *lxcpath)
|
||||
{
|
||||
extern lxc_state_t freezer_state(const char *name, const char *lxcpath);
|
||||
|
||||
lxc_state_t state = freezer_state(name, lxcpath);
|
||||
if (state != FROZEN && state != FREEZING)
|
||||
state = lxc_cmd_get_state(name, lxcpath);
|
||||
|
@ -50,9 +50,7 @@ static int test_running_container(const char *lxcpath,
|
||||
int ret = -1;
|
||||
struct lxc_container *c = NULL;
|
||||
char *cgrelpath;
|
||||
char *cgabspath;
|
||||
char relpath[PATH_MAX+1];
|
||||
char abspath[PATH_MAX+1];
|
||||
char value[NAME_MAX], value_save[NAME_MAX];
|
||||
|
||||
sprintf(relpath, "%s/%s", group ? group : "lxc", name);
|
||||
@ -109,32 +107,8 @@ static int test_running_container(const char *lxcpath,
|
||||
goto err3;
|
||||
}
|
||||
|
||||
cgabspath = lxc_cgroup_path_get("freezer", c->name, c->config_path);
|
||||
if (!cgabspath) {
|
||||
TSTERR("lxc_cgroup_path_get returned NULL");
|
||||
goto err3;
|
||||
}
|
||||
sprintf(abspath, "%s/%s/%s", "freezer", group ? group : "lxc", c->name);
|
||||
if (!strstr(cgabspath, abspath)) {
|
||||
TSTERR("lxc_cgroup_path_get %s not in %s", abspath, cgabspath);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
free(cgabspath);
|
||||
cgabspath = lxc_cgroup_path_get("freezer.state", c->name, c->config_path);
|
||||
if (!cgabspath) {
|
||||
TSTERR("lxc_cgroup_path_get returned NULL");
|
||||
goto err3;
|
||||
}
|
||||
sprintf(abspath, "%s/%s/%s", "freezer", group ? group : "lxc", c->name);
|
||||
if (!strstr(cgabspath, abspath)) {
|
||||
TSTERR("lxc_cgroup_path_get %s not in %s", abspath, cgabspath);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err4:
|
||||
free(cgabspath);
|
||||
|
||||
err3:
|
||||
free(cgrelpath);
|
||||
err2:
|
||||
|
Loading…
Reference in New Issue
Block a user