summaryrefslogtreecommitdiff
path: root/src/shared/cgroup-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/cgroup-setup.c')
-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);
}