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: Robert Vogelgesang <vo...@users.sourceforge.net> diff -u lxc-lxc-1.0.0.beta3/src/lxc/cgroup.c.cpuset2632 lxc-lxc-1.0.0.beta3/src/lxc/cgroup.c --- lxc-lxc-1.0.0.beta3/src/lxc/cgroup.c.cpuset2632 2014-01-27 14:52:20.000000000 +0100 +++ lxc-lxc-1.0.0.beta3/src/lxc/cgroup.c 2014-01-27 16:50:11.000000000 +0100 @@ -74,6 +74,7 @@ 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 @@ 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 @@ */ 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 @@ 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) _______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel