]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
cgroups: cgfsng_create: handle unified hierarchy
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 31 Jan 2018 15:33:17 +0000 (16:33 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 31 Jan 2018 15:35:31 +0000 (16:35 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/utils.c
src/lxc/utils.h

index 4724fb5bc9e6b57545cd476b9941d59231526d6f..24a020ff37c5097cfcdb2633920b7e2abd4d82be 100644 (file)
@@ -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;
 }
 
index c7812fdac97a7e09bcc2bd2f0e38c51b6bc2a61b..a1fe7d4ec9f74c4aea35b04933d831c5a7657500 100644 (file)
@@ -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;
index 223580edcc9cb41316044b8dc395a9817d95ee15..4d129d137ff68307daac51bc1fecdf11c619f32c 100644 (file)
 #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);