]> git.proxmox.com Git - mirror_lxc.git/commitdiff
cgroups: handle hybrid cgroup layouts
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 26 Jul 2017 13:15:27 +0000 (15:15 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 26 Jul 2017 13:20:01 +0000 (15:20 +0200)
Closes #1669.
Closes #1678.
Relates to https://github.com/systemd/systemd/issues/6408.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/Makefile.am
src/lxc/cgroups/cgfsng.c
src/lxc/cgroups/cgroup_utils.c [new file with mode: 0644]
src/lxc/cgroups/cgroup_utils.h [new file with mode: 0644]

index f659f3736dae998e09436754be503b8ba2a3d3f9..a55103ec5b61b713db808de0c14f916d4c84c33a 100644 (file)
@@ -19,6 +19,7 @@ noinst_HEADERS = \
        bdev/lxczfs.h \
        bdev/storage_utils.h \
        cgroups/cgroup.h \
+       cgroups/cgroup_utils.h \
        caps.h \
        conf.h \
        confile.h \
@@ -90,6 +91,7 @@ liblxc_la_SOURCES = \
        bdev/storage_utils.c bdev/storage_utils.h \
        cgroups/cgfs.c \
        cgroups/cgfsng.c \
+       cgroups/cgroup_utils.c cgroups/cgroup_utils.h \
        cgroups/cgroup.c cgroups/cgroup.h \
        commands.c commands.h \
        commands_utils.c commands_utils.h \
index b3f4ca742f5bf4083db7b0890e4315f9fceceb00..5ad24d1e5c8cface17ab434d508d06738981f9ad 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "bdev.h"
 #include "cgroup.h"
+#include "cgroup_utils.h"
 #include "commands.h"
 #include "log.h"
 #include "utils.h"
@@ -72,6 +73,7 @@ struct hierarchy {
        char *mountpoint;
        char *base_cgroup;
        char *fullcgpath;
+       bool is_cgroup_v2;
 };
 
 /*
@@ -600,7 +602,8 @@ static bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
        }
 
        clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
-       if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
+       /* unified hierarchy doesn't have clone_children */
+       if (!file_exists(clonechildrenpath)) {
                free(clonechildrenpath);
                free(cgpath);
                return true;
@@ -742,10 +745,14 @@ static bool is_lxcfs(const char *line)
  */
 static char **get_controllers(char **klist, char **nlist, char *line)
 {
-       // the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
+       /* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
        int i;
        char *p = line, *p2, *tok, *saveptr = NULL;
        char **aret = NULL;
+       bool is_cgroup_v2;
+
+       /* handle cgroup v2 */
+       is_cgroup_v2 = is_cgroupfs_v2(line);
 
        for (i = 0; i < 4; i++) {
                p = strchr(p, ' ');
@@ -768,6 +775,13 @@ static char **get_controllers(char **klist, char **nlist, char *line)
                return NULL;
        }
        *p2 = '\0';
+
+       /* cgroup v2 does not have separate mountpoints for controllers */
+       if (is_cgroup_v2) {
+               must_append_controller(klist, nlist, &aret, "cgroup2");
+               return aret;
+       }
+
        for (tok = strtok_r(p, ",", &saveptr); tok;
                        tok = strtok_r(NULL, ",", &saveptr)) {
                must_append_controller(klist, nlist, &aret, tok);
@@ -776,15 +790,6 @@ static char **get_controllers(char **klist, char **nlist, char *line)
        return aret;
 }
 
-/* return true if the fstype is cgroup */
-static bool is_cgroupfs(char *line)
-{
-       char *p = strstr(line, " - ");
-       if (!p)
-               return false;
-       return strncmp(p, " - cgroup ", 10) == 0;
-}
-
 /* Add a controller to our list of hierarchies */
 static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
 {
@@ -797,6 +802,12 @@ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
        new->base_cgroup = base_cgroup;
        new->fullcgpath = NULL;
 
+       /* record if this is the cgroup v2 hierarchy */
+       if (!strcmp(base_cgroup, "cgroup2"))
+               new->is_cgroup_v2 = true;
+       else
+               new->is_cgroup_v2 = false;
+
        newentry = append_null_to_list((void ***)&hierarchies);
        hierarchies[newentry] = new;
 }
@@ -878,13 +889,21 @@ static bool controller_in_clist(char *cgline, char *c)
 static char *get_current_cgroup(char *basecginfo, char *controller)
 {
        char *p = basecginfo;
+       bool is_cgroup_v2;
+       bool is_cgroup_v2_base_cgroup;
+
+       is_cgroup_v2 = !strcmp(controller, "cgroup2");
+       while (true) {
+               is_cgroup_v2_base_cgroup = false;
+               /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
+               if (is_cgroup_v2 && (*p == '0'))
+                       is_cgroup_v2_base_cgroup = true;
 
-       while (1) {
                p = strchr(p, ':');
                if (!p)
                        return NULL;
                p++;
-               if (controller_in_clist(p, controller)) {
+               if (is_cgroup_v2_base_cgroup || controller_in_clist(p, controller)) {
                        p = strchr(p, ':');
                        if (!p)
                                return NULL;
@@ -899,20 +918,6 @@ static char *get_current_cgroup(char *basecginfo, char *controller)
        }
 }
 
-/*
- * Given a hierarchy @mountpoint and base @path, verify that we can create
- * directories underneath it.
- */
-static bool test_writeable(char *mountpoint, char *path)
-{
-       char *fullpath = must_make_path(mountpoint, path, NULL);
-       int ret;
-
-       ret = access(fullpath, W_OK);
-       free(fullpath);
-       return ret == 0;
-}
-
 static void must_append_string(char ***list, char *entry)
 {
        int newentry = append_null_to_list((void ***)list);
@@ -941,16 +946,17 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
                        continue;
                *p2 = '\0';
 
-               /* If we have a mixture between cgroup v1 and cgroup v2
-                * hierarchies, then /proc/self/cgroup contains entries of the
-                * form:
+               /* If the kernel has cgroup v2 support, then /proc/self/cgroup
+                * contains an entry of the form:
                 *
                 *      0::/some/path
                 *
-                * We need to skip those.
+                * In this case we use "cgroup2" as controller name.
                 */
-               if ((p2 - p) == 0)
+               if ((p2 - p) == 0) {
+                       must_append_string(klist, "cgroup2");
                        continue;
+               }
 
                for (tok = strtok_r(p, ",", &saveptr); tok;
                                tok = strtok_r(NULL, ",", &saveptr)) {
@@ -1058,8 +1064,10 @@ static bool parse_hierarchies(void)
        while (getline(&line, &len, f) != -1) {
                char **controller_list = NULL;
                char *mountpoint, *base_cgroup;
+               bool is_cgroup_v2, writeable;
 
-               if (!is_lxcfs(line) && !is_cgroupfs(line))
+               is_cgroup_v2 = is_cgroupfs_v2(line);
+               if (!is_lxcfs(line) && !is_cgroupfs_v1(line) && !is_cgroup_v2)
                        continue;
 
                controller_list = get_controllers(klist, nlist, line);
@@ -1085,9 +1093,14 @@ static bool parse_hierarchies(void)
                        free(mountpoint);
                        continue;
                }
+
                trim(base_cgroup);
                prune_init_scope(base_cgroup);
-               if (!test_writeable(mountpoint, base_cgroup)) {
+               if (is_cgroup_v2)
+                       writeable = test_writeable_v2(mountpoint, base_cgroup);
+               else
+                       writeable = test_writeable_v1(mountpoint, base_cgroup);
+               if (!writeable) {
                        free_string_list(controller_list);
                        free(mountpoint);
                        free(base_cgroup);
diff --git a/src/lxc/cgroups/cgroup_utils.c b/src/lxc/cgroups/cgroup_utils.c
new file mode 100644 (file)
index 0000000..c09ba16
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@ubuntu.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cgroup_utils.h"
+#include "utils.h"
+
+bool is_cgroupfs_v1(char *line)
+{
+       char *p = strstr(line, " - ");
+       if (!p)
+               return false;
+       return strncmp(p, " - cgroup ", 10) == 0;
+}
+
+bool is_cgroupfs_v2(char *line)
+{
+       char *p = strstr(line, " - ");
+       if (!p)
+               return false;
+
+       return strncmp(p, " - cgroup2 ", 11) == 0;
+}
+
+bool test_writeable_v1(char *mountpoint, char *path)
+{
+       char *fullpath = must_make_path(mountpoint, path, NULL);
+       int ret;
+
+       ret = access(fullpath, W_OK);
+       free(fullpath);
+       return ret == 0;
+}
+
+bool test_writeable_v2(char *mountpoint, char *path)
+{
+       /* In order to move ourselves into an appropriate sub-cgroup we need to
+        * have write access to the parent cgroup's "cgroup.procs" file, i.e. we
+        * need to have write access to the our current cgroups's "cgroup.procs"
+        * file.
+        */
+       int ret;
+       char *cgroup_path, *cgroup_procs_file;
+
+       cgroup_path = must_make_path(mountpoint, path, NULL);
+       cgroup_procs_file = must_make_path(cgroup_path, "cgroup.procs", NULL);
+
+       ret = access(cgroup_path, W_OK);
+       free(cgroup_path);
+       if (ret < 0) {
+               free(cgroup_procs_file);
+               return false;
+       }
+
+       ret = access(cgroup_procs_file, W_OK);
+       free(cgroup_procs_file);
+
+       return ret == 0;
+}
diff --git a/src/lxc/cgroups/cgroup_utils.h b/src/lxc/cgroups/cgroup_utils.h
new file mode 100644 (file)
index 0000000..49aae85
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@ubuntu.com>
+ * Christian Brauner <christian.brauner@ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_CGROUP_UTILS_H
+#define __LXC_CGROUP_UTILS_H
+
+#include <stdbool.h>
+#include <stdio.h>
+
+/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v1 mount. */
+extern bool is_cgroupfs_v1(char *line);
+
+/* Check if given entry from /proc/<pid>/mountinfo is a cgroupfs v2 mount. */
+extern bool is_cgroupfs_v2(char *line);
+
+/* Given a v1 hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it.
+ */
+extern bool test_writeable_v1(char *mountpoint, char *path);
+
+/* Given a v2 hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it and that we have write access to the cgroup's
+ * "cgroup.procs" file.
+ */
+extern bool test_writeable_v2(char *mountpoint, char *path);
+
+#endif /* __LXC_CGROUP_UTILS_H */