Commit 4fb3cba5 by Dwight Engen Committed by Serge Hallyn

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: 's avatarDwight Engen <dwight.engen@oracle.com> Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent 20e2ae99
...@@ -62,7 +62,8 @@ liblxc_so_SOURCES = \ ...@@ -62,7 +62,8 @@ liblxc_so_SOURCES = \
freezer.c \ freezer.c \
error.h error.c \ error.h error.c \
parse.c parse.h \ parse.c parse.h \
cgfs.c cgroup.h \ cgfs.c \
cgroup.c cgroup.h \
lxc.h \ lxc.h \
utils.c utils.h \ utils.c utils.h \
sync.c sync.h \ sync.c sync.h \
......
...@@ -699,7 +699,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -699,7 +699,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
/* attach to cgroup, if requested */ /* attach to cgroup, if requested */
if (options->attach_flags & LXC_ATTACH_MOVE_TO_CGROUP) { 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; goto cleanup_error;
} }
......
/*
* 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;
}
...@@ -430,7 +430,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req, ...@@ -430,7 +430,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler) struct lxc_handler *handler)
{ {
struct lxc_cmd_rsp rsp; struct lxc_cmd_rsp rsp;
char *path; const char *path;
if (req->datalen < 1) if (req->datalen < 1)
return -1; return -1;
...@@ -439,7 +439,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req, ...@@ -439,7 +439,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
if (!path) if (!path)
return -1; return -1;
rsp.datalen = strlen(path) + 1, rsp.datalen = strlen(path) + 1,
rsp.data = path; rsp.data = (char *)path;
rsp.ret = 0; rsp.ret = 0;
return lxc_cmd_rsp_send(fd, &rsp); return lxc_cmd_rsp_send(fd, &rsp);
...@@ -590,7 +590,12 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req, ...@@ -590,7 +590,12 @@ static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
memset(&rsp, 0, sizeof(rsp)); memset(&rsp, 0, sizeof(rsp));
rsp.ret = kill(handler->pid, stopsignal); rsp.ret = kill(handler->pid, stopsignal);
if (!rsp.ret) { 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; return 0;
ERROR("Failed to unfreeze %s:%s", handler->lxcpath, handler->name); ERROR("Failed to unfreeze %s:%s", handler->lxcpath, handler->name);
rsp.ret = -1; rsp.ret = -1;
......
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
#include "utils.h" #include "utils.h"
#include "conf.h" #include "conf.h"
#include "log.h" #include "log.h"
#include "lxc.h" /* for lxc_cgroup_set() */
#include "caps.h" /* for lxc_caps_last_cap() */ #include "caps.h" /* for lxc_caps_last_cap() */
#include "bdev.h" #include "bdev.h"
#include "cgroup.h" #include "cgroup.h"
...@@ -670,7 +669,7 @@ int pin_rootfs(const char *rootfs) ...@@ -670,7 +669,7 @@ int pin_rootfs(const char *rootfs)
return fd; 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; int r;
size_t i; size_t i;
...@@ -744,8 +743,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cg ...@@ -744,8 +743,8 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cg
} }
if (flags & LXC_AUTO_CGROUP_MASK) { 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)) { flags & LXC_AUTO_CGROUP_MASK)) {
SYSERROR("error mounting /sys/fs/cgroup"); SYSERROR("error mounting /sys/fs/cgroup");
return -1; return -1;
} }
...@@ -3500,7 +3499,6 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3500,7 +3499,6 @@ int lxc_setup(struct lxc_handler *handler)
struct lxc_conf *lxc_conf = handler->conf; struct lxc_conf *lxc_conf = handler->conf;
const char *lxcpath = handler->lxcpath; const char *lxcpath = handler->lxcpath;
void *data = handler->data; void *data = handler->data;
struct lxc_cgroup_info *cgroup_info = handler->cgroup_info;
if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) { if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
if (setup_utsname(lxc_conf->utsname)) { if (setup_utsname(lxc_conf->utsname)) {
...@@ -3538,7 +3536,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3538,7 +3536,7 @@ int lxc_setup(struct lxc_handler *handler)
/* do automatic mounts (mainly /proc and /sys), but exclude /* do automatic mounts (mainly /proc and /sys), but exclude
* those that need to wait until other stuff has finished * 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); ERROR("failed to setup the automatic mounts for '%s'", name);
return -1; return -1;
} }
...@@ -3557,7 +3555,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3557,7 +3555,7 @@ int lxc_setup(struct lxc_handler *handler)
* before, /sys could not have been mounted * before, /sys could not have been mounted
* (is either mounted automatically or via fstab entries) * (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); ERROR("failed to setup the automatic mounts for '%s'", name);
return -1; return -1;
} }
......
...@@ -35,18 +35,53 @@ ...@@ -35,18 +35,53 @@
#include "state.h" #include "state.h"
#include "monitor.h" #include "monitor.h"
#include "log.h" #include "log.h"
#include "cgroup.h" #include "lxc.h"
lxc_log_define(lxc_freezer, lxc); 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) int lxc_freeze(const char *name, const char *lxcpath)
{ {
lxc_monitor_send_state(name, FREEZING, 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) 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); ...@@ -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); 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 * Set a specified value for a specified subsystem. The specified
* subsystem must be fully specified, eg. "cpu.shares" * subsystem must be fully specified, eg. "cpu.shares"
......
...@@ -291,7 +291,7 @@ static int utmp_get_ntasks(struct lxc_handler *handler) ...@@ -291,7 +291,7 @@ static int utmp_get_ntasks(struct lxc_handler *handler)
{ {
int ntasks; int ntasks;
ntasks = lxc_cgroup_nrtasks_handler(handler); ntasks = cgroup_nrtasks(handler);
if (ntasks < 0) { if (ntasks < 0) {
ERROR("failed to get the number of tasks"); ERROR("failed to get the number of tasks");
......
...@@ -70,7 +70,7 @@ struct lxc_handler { ...@@ -70,7 +70,7 @@ struct lxc_handler {
int sv[2]; int sv[2];
int pinfd; int pinfd;
const char *lxcpath; 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 *); 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) ...@@ -69,6 +69,8 @@ lxc_state_t lxc_str2state(const char *state)
lxc_state_t lxc_getstate(const char *name, const char *lxcpath) 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); lxc_state_t state = freezer_state(name, lxcpath);
if (state != FROZEN && state != FREEZING) if (state != FROZEN && state != FREEZING)
state = lxc_cmd_get_state(name, lxcpath); state = lxc_cmd_get_state(name, lxcpath);
......
...@@ -50,9 +50,7 @@ static int test_running_container(const char *lxcpath, ...@@ -50,9 +50,7 @@ static int test_running_container(const char *lxcpath,
int ret = -1; int ret = -1;
struct lxc_container *c = NULL; struct lxc_container *c = NULL;
char *cgrelpath; char *cgrelpath;
char *cgabspath;
char relpath[PATH_MAX+1]; char relpath[PATH_MAX+1];
char abspath[PATH_MAX+1];
char value[NAME_MAX], value_save[NAME_MAX]; char value[NAME_MAX], value_save[NAME_MAX];
sprintf(relpath, "%s/%s", group ? group : "lxc", name); sprintf(relpath, "%s/%s", group ? group : "lxc", name);
...@@ -109,32 +107,8 @@ static int test_running_container(const char *lxcpath, ...@@ -109,32 +107,8 @@ static int test_running_container(const char *lxcpath,
goto err3; 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; ret = 0;
err4:
free(cgabspath);
err3: err3:
free(cgrelpath); free(cgrelpath);
err2: err2:
......
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