summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Streetman <ddstreet@canonical.com>2021-10-05 08:49:21 -0400
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-10-13 12:24:33 +0900
commit22eeada9354a45c6aa0685d49016ac78a57c41ea (patch)
tree932cccfcbcbab6591d3cdbeb27654dddcc8a6f36 /src
parent0b4f8d94989dec304e70102798d5e942effe8bee (diff)
downloadsystemd-22eeada9354a45c6aa0685d49016ac78a57c41ea.tar.gz
cgroup: check if any controller is in use as v1
Check if any cgroup controller is currently being used as v1, and if so don't use cgroup unified mode. This is only checked when there is no cgroup already mounted, and is most useful when running in a container where the host is using a legacy or hybrid cgroup, since we can't (fully) use unified cgroup, as the host kernel has the cgroup controllers in use by v1. This shouldn't be needed if the container manager has pre-mounted cgroups appropriately based on the host system cgroup setup, but we can't rely on that always being the case.
Diffstat (limited to 'src')
-rw-r--r--src/shared/cgroup-setup.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c
index 7dee7e9512..aa5ee99ebf 100644
--- a/src/shared/cgroup-setup.c
+++ b/src/shared/cgroup-setup.c
@@ -17,6 +17,63 @@
#include "stdio-util.h"
#include "string-util.h"
#include "user-util.h"
+#include "virt.h"
+
+static int cg_any_controller_used_for_v1(void) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_strv_free_ char **lines = NULL;
+ char **line;
+ int r;
+
+ r = read_full_virtual_file("/proc/cgroups", &buf, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Could not read /proc/cgroups, ignoring: %m");
+
+ r = strv_split_newlines_full(&lines, buf, 0);
+ if (r < 0)
+ return r;
+
+ /* The intention of this is to check if the fully unified cgroup tree setup is possible, meaning all
+ * enabled kernel cgroup controllers are currently not in use by cgroup1. For reference:
+ * https://systemd.io/CGROUP_DELEGATION/#three-different-tree-setups-
+ *
+ * Note that this is typically only useful to check inside a container where we don't know what
+ * cgroup tree setup is in use by the host; if the host is using legacy or hybrid, we can't use
+ * unified since some or all controllers would be missing. This is not the best way to detect this,
+ * as whatever container manager created our container should have mounted /sys/fs/cgroup
+ * appropriately, but in case that wasn't done, we try to detect if it's possible for us to use
+ * unified cgroups. */
+ STRV_FOREACH(line, lines) {
+ _cleanup_free_ char *name = NULL, *hierarchy_id = NULL, *num = NULL, *enabled = NULL;
+
+ /* Skip header line */
+ if (startswith(*line, "#"))
+ continue;
+
+ const char *p = *line;
+ r = extract_many_words(&p, NULL, 0, &name, &hierarchy_id, &num, &enabled, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Error parsing /proc/cgroups line, ignoring: %m");
+ else if (r < 4) {
+ log_debug("Invalid /proc/cgroups line, ignoring.");
+ continue;
+ }
+
+ /* Ignore disabled controllers. */
+ if (streq(enabled, "0"))
+ continue;
+
+ /* Since the unified cgroup doesn't use multiple hierarchies, if any controller has a
+ * non-zero hierarchy_id that means it's in use already in a legacy (or hybrid) cgroup v1
+ * hierarchy, and can't be used in a unified cgroup. */
+ if (!streq(hierarchy_id, "0")) {
+ log_debug("Cgroup controller %s in use by legacy v1 hierarchy.", name);
+ return 1;
+ }
+ }
+
+ return 0;
+}
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
@@ -45,6 +102,10 @@ bool cg_is_unified_wanted(void) {
if (r > 0 && streq_ptr(c, "all"))
return (wanted = true);
+ /* If any controller is in use as v1, don't use unified. */
+ if (cg_any_controller_used_for_v1() > 0)
+ return (wanted = false);
+
return (wanted = is_default);
}