return NULL;
}
+static char *must_make_path(const char *first, ...) __attribute__((sentinel));
+
+/* Copy contents of parent(@path)/@file to @path/@file */
+static bool copy_parent_file(char *path, char *file)
+{
+ char *lastslash, *value = NULL, *fpath, oldv;
+ int len = 0;
+ int ret;
+
+ lastslash = strrchr(path, '/');
+ if (!lastslash) { // bug... this shouldn't be possible
+ ERROR("cgfsng:copy_parent_file: bad path %s", path);
+ return false;
+ }
+ oldv = *lastslash;
+ *lastslash = '\0';
+ fpath = must_make_path(path, file, NULL);
+ len = lxc_read_from_file(fpath, NULL, 0);
+ if (len <= 0)
+ goto bad;
+ value = must_alloc(len + 1);
+ if (lxc_read_from_file(fpath, value, len) != len)
+ goto bad;
+ free(fpath);
+ *lastslash = oldv;
+ fpath = must_make_path(path, file, NULL);
+ ret = lxc_write_to_file(fpath, value, len, false);
+ if (ret < 0)
+ SYSERROR("Unable to write %s to %s", value, fpath);
+ free(fpath);
+ free(value);
+ return ret >= 0;
+
+bad:
+ SYSERROR("Error reading '%s'", fpath);
+ free(fpath);
+ free(value);
+ return false;
+}
+
+/*
+ * Initialize the cpuset hierarchy in first directory of @gname and
+ * set cgroup.clone_children so that children inherit settings.
+ * Since the h->base_path is populated by init or ourselves, we know
+ * it is already initialized.
+ */
+bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
+{
+ char *cgpath, *clonechildrenpath, v, *slash;
+
+ if (!string_in_list(h->controllers, "cpuset"))
+ return true;
+
+ if (*cgname == '/')
+ cgname++;
+ slash = strchr(cgname, '/');
+ if (slash)
+ *slash = '\0';
+
+ cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+ if (slash)
+ *slash = '/';
+ if (mkdir(cgpath, 0755) < 0 && errno != EEXIST) {
+ SYSERROR("Failed to create '%s'", cgpath);
+ free(cgpath);
+ return false;
+ }
+ clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
+ if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
+ free(clonechildrenpath);
+ free(cgpath);
+ return true;
+ }
+ if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
+ SYSERROR("Failed to read '%s'", clonechildrenpath);
+ free(clonechildrenpath);
+ free(cgpath);
+ return false;
+ }
+
+ if (v == '1') { /* already set for us by someone else */
+ free(clonechildrenpath);
+ free(cgpath);
+ return true;
+ }
+
+ /* copy parent's settings */
+ if (!copy_parent_file(cgpath, "cpuset.cpus") ||
+ !copy_parent_file(cgpath, "cpuset.mems")) {
+ free(cgpath);
+ free(clonechildrenpath);
+ return false;
+ }
+ free(cgpath);
+
+ if (lxc_write_to_file(clonechildrenpath, "1", 1, false) < 0) {
+ /* Set clone_children so children inherit our settings */
+ SYSERROR("Failed to write 1 to %s", clonechildrenpath);
+ free(clonechildrenpath);
+ return false;
+ }
+ free(clonechildrenpath);
+ return true;
+}
+
/*
* Given two null-terminated lists of strings, return true if any string
* is in both.
return buf;
}
-static char *must_make_path(const char *first, ...) __attribute__((sentinel));
-
/*
* Given a hierarchy @mountpoint and base @path, verify that we can create
* directories underneath it.
static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
{
- char *fullpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
- int ret;
-
- ret = mkdir_p(fullpath, 0755);
- h->fullcgpath = fullpath;
- return ret == 0;
+ h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+ if (!handle_cpuset_hierarchy(h, cgname))
+ return false;
+ return mkdir_p(h->fullcgpath, 0755) == 0;
}
static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)