[lxc-devel] [lxc/master] cgroups: handle hybrid cgroup layouts
brauner on Github
lxc-bot at linuxcontainers.org
Wed Jul 26 13:48:03 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 430 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170726/ae6f83d3/attachment.bin>
-------------- next part --------------
From 04ad7ffe2a42fb2fa2e78e694990b385fd2dd5e0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 26 Jul 2017 14:57:35 +0200
Subject: [PATCH 1/2] utils: move helpers from cgfsng.c to utils.{c,h}
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/cgroups/cgfsng.c | 53 ------------------------------------------------
src/lxc/utils.c | 47 ++++++++++++++++++++++++++++++++++++++++++
src/lxc/utils.h | 11 ++++++++++
3 files changed, 58 insertions(+), 53 deletions(-)
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 1192d575f..b3f4ca742 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -118,36 +118,12 @@ static void free_string_list(char **clist)
}
}
-/* Re-alllocate a pointer, do not fail */
-static void *must_realloc(void *orig, size_t sz)
-{
- void *ret;
-
- do {
- ret = realloc(orig, sz);
- } while (!ret);
- return ret;
-}
-
/* Allocate a pointer, do not fail */
static void *must_alloc(size_t sz)
{
return must_realloc(NULL, sz);
}
-/* return copy of string @entry; do not fail. */
-static char *must_copy_string(const char *entry)
-{
- char *ret;
-
- if (!entry)
- return NULL;
- do {
- ret = strdup(entry);
- } while (!ret);
- return ret;
-}
-
/*
* This is a special case - return a copy of @entry
* prepending 'name='. I.e. turn systemd into name=systemd.
@@ -259,8 +235,6 @@ struct hierarchy *get_hierarchy(const char *c)
return NULL;
}
-static char *must_make_path(const char *first, ...) __attribute__((sentinel));
-
#define BATCH_SIZE 50
static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
{
@@ -1187,33 +1161,6 @@ static void *cgfsng_init(const char *name)
return NULL;
}
-/*
- * Concatenate all passed-in strings into one path. Do not fail. If any piece is
- * not prefixed with '/', add a '/'.
- */
-static char *must_make_path(const char *first, ...)
-{
- va_list args;
- char *cur, *dest;
- size_t full_len = strlen(first);
-
- dest = must_copy_string(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;
-}
-
static int cgroup_rmdir(char *dirname)
{
struct dirent *direntp;
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 5b61cba00..f89c837d5 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -2337,3 +2337,50 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
return fret;
}
+
+char *must_make_path(const char *first, ...)
+{
+ va_list args;
+ char *cur, *dest;
+ size_t full_len = strlen(first);
+
+ dest = must_copy_string(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;
+
+ if (!entry)
+ return NULL;
+ do {
+ ret = strdup(entry);
+ } while (!ret);
+
+ return ret;
+}
+
+void *must_realloc(void *orig, size_t sz)
+{
+ void *ret;
+
+ do {
+ ret = realloc(orig, sz);
+ } while (!ret);
+
+ return ret;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 916ee56a6..3465e6a6f 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -375,4 +375,15 @@ int lxc_unstack_mountpoint(const char *path, bool lazy);
*/
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));
+
+/* return copy of string @entry; do not fail. */
+char *must_copy_string(const char *entry);
+
+/* Re-alllocate a pointer, do not fail */
+void *must_realloc(void *orig, size_t sz);
+
#endif /* __LXC_UTILS_H */
From 6328fd9c05d2730182eb738ffd320de716f062bb Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 26 Jul 2017 15:15:27 +0200
Subject: [PATCH 2/2] cgroups: handle hybrid cgroup layouts
Closes #1669.
Closes #1678.
Relates to https://github.com/systemd/systemd/issues/6408.
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/Makefile.am | 2 +
src/lxc/cgroups/cgfsng.c | 81 ++++++++++++++++++++++-----------------
src/lxc/cgroups/cgroup_utils.c | 86 ++++++++++++++++++++++++++++++++++++++++++
src/lxc/cgroups/cgroup_utils.h | 48 +++++++++++++++++++++++
4 files changed, 183 insertions(+), 34 deletions(-)
create mode 100644 src/lxc/cgroups/cgroup_utils.c
create mode 100644 src/lxc/cgroups/cgroup_utils.h
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index f659f3736..a55103ec5 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -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 \
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index b3f4ca742..5ad24d1e5 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -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
index 000000000..c09ba1688
--- /dev/null
+++ b/src/lxc/cgroups/cgroup_utils.c
@@ -0,0 +1,86 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn at ubuntu.com>
+ * Christian Brauner <christian.brauner at 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
index 000000000..49aae8567
--- /dev/null
+++ b/src/lxc/cgroups/cgroup_utils.h
@@ -0,0 +1,48 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn at ubuntu.com>
+ * Christian Brauner <christian.brauner at 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 */
More information about the lxc-devel
mailing list