cgroups: cgfsng_create: handle unified hierarchy

parent d6337a5f
......@@ -1562,18 +1562,92 @@ struct cgroup_ops *cgfsng_ops_init(void)
return &cgfsng_ops;
}
static bool handle_unified_hierarchy(struct hierarchy *h, char *cgname)
{
char **it;
size_t i, parts_len;
size_t full_len = 0;
char *add_controllers = NULL, *cgroup = NULL;
char **parts = NULL;
bool bret = false;
if (h->version != CGROUP2_SUPER_MAGIC)
return true;
if (!h->controllers)
return true;
/* For now we simply enable all controllers that we have detected by
* creating a string like "+memory +pids +cpu +io".
* TODO: In the near future we might want to support "-<controller>"
* etc. but whether supporting semantics like this make sense will need
* some thinking.
*/
for (it = h->controllers; it && *it; it++) {
full_len += strlen(*it) + 2;
add_controllers = must_realloc(add_controllers, full_len + 1);
if (h->controllers[0] == *it)
add_controllers[0] = '\0';
strcat(add_controllers, "+");
strcat(add_controllers, *it);
if ((it + 1) && *(it + 1))
strcat(add_controllers, " ");
}
parts = lxc_string_split(cgname, '/');
if (!parts)
goto on_error;
parts_len = lxc_array_len((void **)parts);
if (parts_len > 0)
parts_len--;
cgroup = must_make_path(h->mountpoint, h->base_cgroup, NULL);
for (i = 0; i < parts_len; i++) {
int ret;
char *target;
cgroup = must_append_path(cgroup, parts[i], NULL);
target = must_make_path(cgroup, "cgroup.subtree_control", NULL);
ret = lxc_write_to_file(target, add_controllers, full_len, false);
free(target);
if (ret < 0) {
SYSERROR("Could not enable \"%s\" controllers in the "
"unified cgroup \"%s\"", add_controllers, cgroup);
goto on_error;
}
}
bret = true;
on_error:
lxc_free_array((void **)parts, free);
free(add_controllers);
free(cgroup);
return bret;
}
static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
{
int ret;
h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
if (dir_exists(h->fullcgpath)) { /* it must not already exist */
ERROR("Path \"%s\" already existed.", h->fullcgpath);
ERROR("cgroup \"%s\" already existed", h->fullcgpath);
return false;
}
if (!handle_cpuset_hierarchy(h, cgname)) {
ERROR("Failed to handle cgroupfs v1 cpuset controller.");
ERROR("Failed to handle cgroupfs v1 cpuset controller");
return false;
}
return mkdir_p(h->fullcgpath, 0755) == 0;
ret = mkdir_p(h->fullcgpath, 0755);
if (ret < 0) {
ERROR("Failed to create cgroup \"%s\"", h->fullcgpath);
return false;
}
return handle_unified_hierarchy(h, cgname);
}
static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
......@@ -1592,7 +1666,7 @@ static inline bool cgfsng_create(void *hdata)
{
int i;
size_t len;
char *cgname, *offset, *tmp;
char *container_cgroup, *offset, *tmp;
int idx = 0;
struct cgfsng_handler_data *d = hdata;
......@@ -1613,10 +1687,10 @@ static inline bool cgfsng_create(void *hdata)
return false;
}
len = strlen(tmp) + 5; /* leave room for -NNN\0 */
cgname = must_alloc(len);
strcpy(cgname, tmp);
container_cgroup = must_alloc(len);
strcpy(container_cgroup, tmp);
free(tmp);
offset = cgname + len - 5;
offset = container_cgroup + len - 5;
again:
if (idx == 1000) {
......@@ -1638,23 +1712,23 @@ again:
}
}
for (i = 0; hierarchies[i]; i++) {
if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
if (!create_path_for_hierarchy(hierarchies[i], container_cgroup)) {
int j;
ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
free(hierarchies[i]->fullcgpath);
hierarchies[i]->fullcgpath = NULL;
for (j = 0; j < i; j++)
remove_path_for_hierarchy(hierarchies[j], cgname);
remove_path_for_hierarchy(hierarchies[j], container_cgroup);
idx++;
goto again;
}
}
/* Done */
d->container_cgroup = cgname;
d->container_cgroup = container_cgroup;
return true;
out_free:
free(cgname);
free(container_cgroup);
return false;
}
......
......@@ -2307,6 +2307,33 @@ char *must_make_path(const char *first, ...)
return dest;
}
char *must_append_path(char *first, ...)
{
char *cur;
size_t full_len;
va_list args;
char *dest = first;
full_len = strlen(first);
va_start(args, first);
while ((cur = va_arg(args, char *)) != NULL) {
full_len += strlen(cur);
if (cur[0] != '/')
full_len++;
dest = must_realloc(dest, full_len + 1);
if (cur[0] != '/')
strcat(dest, "/");
strcat(dest, cur);
}
va_end(args);
return dest;
}
char *must_copy_string(const char *entry)
{
char *ret;
......
......@@ -86,6 +86,14 @@
#define CAP_SYS_ADMIN 21
#endif
#ifndef CGROUP_SUPER_MAGIC
#define CGROUP_SUPER_MAGIC 0x27e0eb
#endif
#ifndef CGROUP2_SUPER_MAGIC
#define CGROUP2_SUPER_MAGIC 0x63677270
#endif
/* Useful macros */
/* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
#define LXC_NUMSTRLEN64 21
......@@ -529,7 +537,8 @@ extern int run_command(char *buf, size_t buf_size, int (*child_fn)(void *),
/* Concatenate all passed-in strings into one path. Do not fail. If any piece
* is not prefixed with '/', add a '/'.
*/
extern char *must_make_path(const char *first, ...) __attribute__((sentinel));
__attribute__((sentinel)) extern char *must_make_path(const char *first, ...);
__attribute__((sentinel)) extern char *must_append_path(char *first, ...);
/* return copy of string @entry; do not fail. */
extern char *must_copy_string(const char *entry);
......
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