Commit d703c2b1 by Robert Vogelgesang Committed by Serge Hallyn

cgroupfs: cpuset support for kernels without cgroup.clone_children

Hi, as promised last week, here's my patch for cpuset cgroup support for kernels without the cgroup.clone_children feature. My initial patch used "#include <linux/version.h>" and the macros defined there to decide if cgroup.clone_children should be used or not. After having seen Serge Hallyn's patch which he posted to the list last Wednesday, where he used stat() to check if the cgroup.clone_children file is there, I rewrote my patch to do the same. The patch is against 1.0.0.beta3, and it is tested successfully with RHEL-6's kernel version 2.6.32-431.3.1.el6, compiled without cgmanager (I've so far not tried to use cgmanager in RHEL-6). In addition to fixing the cpuset cgroup setup, this patch also fixes a wrong argument in a call to handle_cgroup_settings() in the same context. Robert Signed-off-by: 's avatarRobert Vogelgesang <vogel@users.sourceforge.net> Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent 9749441a
......@@ -74,6 +74,7 @@ static int do_setup_cgroup_limits(struct lxc_handler *h, struct lxc_list *cgroup
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;
......@@ -897,15 +898,23 @@ struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *pa
r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
if (r < 0)
goto cleanup_from_error;
if (!init_cpuset_if_needed(info_ptr->designated_mount_point, current_entire_path)) {
ERROR("Failed to initialize cpuset in new '%s'.", current_entire_path);
goto cleanup_from_error;
}
info_ptr->created_paths[info_ptr->created_paths_count++] = current_entire_path;
} else {
/* if we didn't create the cgroup, then we have to make sure that
* further cgroups will be created properly
*/
if (handle_cgroup_settings(mp, info_ptr->cgroup_path) < 0) {
if (handle_cgroup_settings(info_ptr->designated_mount_point, info_ptr->cgroup_path) < 0) {
ERROR("Could not set clone_children to 1 for cpuset hierarchy in pre-existing cgroup.");
goto cleanup_from_error;
}
if (!init_cpuset_if_needed(info_ptr->designated_mount_point, info_ptr->cgroup_path)) {
ERROR("Failed to initialize cpuset in pre-existing '%s'.", info_ptr->cgroup_path);
goto cleanup_from_error;
}
/* already existed but path component of pattern didn't contain '%n',
* so this is not an error; but then we don't need current_entire_path
......@@ -2039,8 +2048,19 @@ static int handle_cgroup_settings(struct cgroup_mount_point *mp,
*/
if (lxc_string_in_array("cpuset", (const char **)mp->hierarchy->subsystems)) {
char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/cgroup.clone_children");
struct stat sb;
if (!cc_path)
return -1;
/* cgroup.clone_children is not available when running under
* older kernel versions; in this case, we'll initialize
* cpuset.cpus and cpuset.mems later, after the new cgroup
* was created
*/
if (stat(cc_path, &sb) != 0 && errno == ENOENT) {
free(cc_path);
return 0;
}
r = lxc_read_from_file(cc_path, buf, 1);
if (r == 1 && buf[0] == '1') {
free(cc_path);
......@@ -2055,6 +2075,90 @@ static int handle_cgroup_settings(struct cgroup_mount_point *mp,
return 0;
}
static bool cgroup_read_from_file(const char *fn, char buf[], size_t bufsize)
{
int ret = lxc_read_from_file(fn, buf, bufsize);
if (ret < 0) {
SYSERROR("failed to read %s", fn);
return false;
}
if (ret == bufsize) {
ERROR("too much data in %s", fn);
return false;
}
buf[ret] = '\0';
return true;
}
static bool do_init_cpuset_file(struct cgroup_mount_point *mp,
const char *path, const char *name)
{
char value[128];
char *childfile, *parentfile, *tmp;
bool ok;
childfile = cgroup_to_absolute_path(mp, path, name);
if (!childfile)
return false;
/* don't overwrite a non-empty value in the file */
if (!cgroup_read_from_file(childfile, value, sizeof(value))) {
free(childfile);
return false;
}
if (value[0] != '\0' && value[0] != '\n') {
free(childfile);
return true;
}
/* path to the same name in the parent cgroup */
parentfile = strdup(path);
if (!parentfile)
return false;
tmp = strrchr(parentfile, '/');
if (!tmp) {
free(childfile);
free(parentfile);
return false;
}
if (tmp == parentfile)
tmp++; /* keep the '/' at the start */
*tmp = '\0';
tmp = parentfile;
parentfile = cgroup_to_absolute_path(mp, tmp, name);
free(tmp);
if (!parentfile) {
free(childfile);
return false;
}
/* copy from parent to child cgroup */
if (!cgroup_read_from_file(parentfile, value, sizeof(value))) {
free(parentfile);
free(childfile);
return false;
}
ok = (lxc_write_to_file(childfile, value, strlen(value), false) >= 0);
if (!ok)
SYSERROR("failed writing %s", childfile);
free(parentfile);
free(childfile);
return ok;
}
static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
const char *path)
{
/* the files we have to handle here are only in cpuset hierarchies */
if (!lxc_string_in_array("cpuset",
(const char **)mp->hierarchy->subsystems))
return true;
return (do_init_cpuset_file(mp, path, "/cpuset.cpus") &&
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)
......
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