cgroups: cgfsng_create: handle unified hierarchy

parent d6337a5f
...@@ -1562,18 +1562,92 @@ struct cgroup_ops *cgfsng_ops_init(void) ...@@ -1562,18 +1562,92 @@ struct cgroup_ops *cgfsng_ops_init(void)
return &cgfsng_ops; 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) 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); h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
if (dir_exists(h->fullcgpath)) { /* it must not already exist */ 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; return false;
} }
if (!handle_cpuset_hierarchy(h, cgname)) { 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 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) static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
...@@ -1592,7 +1666,7 @@ static inline bool cgfsng_create(void *hdata) ...@@ -1592,7 +1666,7 @@ static inline bool cgfsng_create(void *hdata)
{ {
int i; int i;
size_t len; size_t len;
char *cgname, *offset, *tmp; char *container_cgroup, *offset, *tmp;
int idx = 0; int idx = 0;
struct cgfsng_handler_data *d = hdata; struct cgfsng_handler_data *d = hdata;
...@@ -1613,10 +1687,10 @@ static inline bool cgfsng_create(void *hdata) ...@@ -1613,10 +1687,10 @@ static inline bool cgfsng_create(void *hdata)
return false; return false;
} }
len = strlen(tmp) + 5; /* leave room for -NNN\0 */ len = strlen(tmp) + 5; /* leave room for -NNN\0 */
cgname = must_alloc(len); container_cgroup = must_alloc(len);
strcpy(cgname, tmp); strcpy(container_cgroup, tmp);
free(tmp); free(tmp);
offset = cgname + len - 5; offset = container_cgroup + len - 5;
again: again:
if (idx == 1000) { if (idx == 1000) {
...@@ -1638,23 +1712,23 @@ again: ...@@ -1638,23 +1712,23 @@ again:
} }
} }
for (i = 0; hierarchies[i]; i++) { 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; int j;
ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath); ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
free(hierarchies[i]->fullcgpath); free(hierarchies[i]->fullcgpath);
hierarchies[i]->fullcgpath = NULL; hierarchies[i]->fullcgpath = NULL;
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
remove_path_for_hierarchy(hierarchies[j], cgname); remove_path_for_hierarchy(hierarchies[j], container_cgroup);
idx++; idx++;
goto again; goto again;
} }
} }
/* Done */ /* Done */
d->container_cgroup = cgname; d->container_cgroup = container_cgroup;
return true; return true;
out_free: out_free:
free(cgname); free(container_cgroup);
return false; return false;
} }
......
...@@ -2307,6 +2307,33 @@ char *must_make_path(const char *first, ...) ...@@ -2307,6 +2307,33 @@ char *must_make_path(const char *first, ...)
return dest; 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 *must_copy_string(const char *entry)
{ {
char *ret; char *ret;
......
...@@ -86,6 +86,14 @@ ...@@ -86,6 +86,14 @@
#define CAP_SYS_ADMIN 21 #define CAP_SYS_ADMIN 21
#endif #endif
#ifndef CGROUP_SUPER_MAGIC
#define CGROUP_SUPER_MAGIC 0x27e0eb
#endif
#ifndef CGROUP2_SUPER_MAGIC
#define CGROUP2_SUPER_MAGIC 0x63677270
#endif
/* Useful macros */ /* Useful macros */
/* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */ /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
#define LXC_NUMSTRLEN64 21 #define LXC_NUMSTRLEN64 21
...@@ -529,7 +537,8 @@ extern int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), ...@@ -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 /* Concatenate all passed-in strings into one path. Do not fail. If any piece
* is not prefixed with '/', add a '/'. * 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. */ /* return copy of string @entry; do not fail. */
extern char *must_copy_string(const char *entry); 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