]> 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, 7 Feb 2018 10:59:26 +0000 (11:59 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/utils.c
src/lxc/utils.h

index c490255552fcbe4e354729cc4e1c484129cbfebf..5138b10b27b6f1b189ff82fcfd40e3744b849121 100644 (file)
@@ -1544,18 +1544,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)
@@ -1574,7 +1648,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;
 
@@ -1592,10 +1666,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) {
@@ -1617,23 +1691,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 b59caad01a6f7c347dd87244325179f90a7defd9..a9c73f24ed4de558686243bb0a73a9877ab00c0c 100644 (file)
@@ -2236,6 +2236,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 87c5152961481f36d1647abae568e9b4a814b43b..9c01c5d3a429d7f0f0db85f7c778cb2da4bff07f 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
@@ -518,13 +526,14 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
 /* Concatenate all passed-in strings into one path. Do not fail. If any piece
  * is not prefixed with '/', add a '/'.
  */
-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. */
-char *must_copy_string(const char *entry);
+extern char *must_copy_string(const char *entry);
 
 /* Re-alllocate a pointer, do not fail */
-void *must_realloc(void *orig, size_t sz);
+extern void *must_realloc(void *orig, size_t sz);
 
 /* __typeof__ should be safe to use with all compilers. */
 typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;