mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
cgroup-setup: drop hierarchy detection, always use v2
This commit is contained in:
parent
3fcb4e51a3
commit
a822bad9f4
@ -1,6 +1,5 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <threads.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cgroup-setup.h"
|
||||
@ -12,168 +11,11 @@
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "process-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#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;
|
||||
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);
|
||||
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;
|
||||
|
||||
/* Ignore controllers we don't care about. */
|
||||
if (cgroup_controller_from_string(name) < 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;
|
||||
int r;
|
||||
|
||||
/* If we have a cached value, return that. */
|
||||
if (wanted >= 0)
|
||||
return wanted;
|
||||
|
||||
/* If the hierarchy is already mounted, then follow whatever was chosen for it. */
|
||||
r = cg_unified_cached(true);
|
||||
if (r >= 0)
|
||||
return (wanted = r >= CGROUP_UNIFIED_ALL);
|
||||
|
||||
/* If we have explicit configuration for v1 or v2, respect that. */
|
||||
if (cg_is_legacy_force_enabled())
|
||||
return (wanted = false);
|
||||
|
||||
bool b;
|
||||
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", /* flags = */ 0, &b);
|
||||
if (r > 0 && b)
|
||||
return (wanted = true);
|
||||
|
||||
/* If we passed cgroup_no_v1=all with no other instructions, it seems highly unlikely that we want to
|
||||
* use hybrid or legacy hierarchy. */
|
||||
_cleanup_free_ char *c = NULL;
|
||||
r = proc_cmdline_get_key("cgroup_no_v1", 0, &c);
|
||||
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 = true);
|
||||
}
|
||||
|
||||
bool cg_is_legacy_wanted(void) {
|
||||
/* Check if we have cgroup v2 already mounted. */
|
||||
if (cg_unified_cached(true) == CGROUP_UNIFIED_ALL)
|
||||
return false;
|
||||
|
||||
/* Otherwise, assume that at least partial legacy is wanted,
|
||||
* since cgroup v2 should already be mounted at this point. */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cg_is_hybrid_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
int r;
|
||||
|
||||
/* If we have a cached value, return that. */
|
||||
if (wanted >= 0)
|
||||
return wanted;
|
||||
|
||||
/* If the hierarchy is already mounted, then follow whatever was chosen for it. */
|
||||
if (cg_unified_cached(true) == CGROUP_UNIFIED_ALL)
|
||||
return (wanted = false);
|
||||
|
||||
/* Otherwise, let's see what the kernel command line has to say. Since checking is expensive, cache
|
||||
* a non-error result.
|
||||
* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
|
||||
* negation. */
|
||||
bool b;
|
||||
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", /* flags = */ 0, &b);
|
||||
if (r > 0)
|
||||
return (wanted = !b);
|
||||
|
||||
/* The default hierarchy is "unified". But if this is reached, it means that unified hierarchy was
|
||||
* not mounted, so return true too. */
|
||||
return (wanted = true);
|
||||
}
|
||||
|
||||
bool cg_is_legacy_enabled(void) {
|
||||
int r;
|
||||
bool b;
|
||||
|
||||
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", /* flags = */ 0, &b);
|
||||
return r > 0 && !b;
|
||||
}
|
||||
|
||||
bool cg_is_legacy_force_enabled(void) {
|
||||
int r;
|
||||
bool b;
|
||||
|
||||
/* Require both systemd.unified_cgroup_hierarchy=0 and SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1. */
|
||||
|
||||
if (!cg_is_legacy_enabled())
|
||||
return false;
|
||||
|
||||
r = proc_cmdline_get_bool("SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE", /* flags = */ 0, &b);
|
||||
if (r <= 0 || !b)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cg_weight_parse(const char *s, uint64_t *ret) {
|
||||
uint64_t u;
|
||||
|
@ -7,12 +7,6 @@
|
||||
|
||||
#include "cgroup-util.h"
|
||||
|
||||
bool cg_is_unified_wanted(void);
|
||||
bool cg_is_legacy_wanted(void);
|
||||
bool cg_is_hybrid_wanted(void);
|
||||
bool cg_is_legacy_enabled(void);
|
||||
bool cg_is_legacy_force_enabled(void);
|
||||
|
||||
int cg_weight_parse(const char *s, uint64_t *ret);
|
||||
int cg_cpu_weight_parse(const char *s, uint64_t *ret);
|
||||
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
|
||||
|
@ -55,9 +55,6 @@ typedef struct MountPoint {
|
||||
bool cgroupfs_recursiveprot_supported(void) {
|
||||
int r;
|
||||
|
||||
if (!cg_is_unified_wanted())
|
||||
return false;
|
||||
|
||||
/* Added in kernel 5.7 */
|
||||
|
||||
r = mount_option_supported("cgroup2", "memory_recursiveprot", /* value = */ NULL);
|
||||
@ -95,11 +92,9 @@ static const MountPoint mount_table[] = {
|
||||
{ "tmpfs", "/run", "tmpfs", "mode=0755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
NULL, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate,memory_recursiveprot", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cgroupfs_recursiveprot_supported, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
cgroupfs_recursiveprot_supported, MNT_FATAL|MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
NULL, MNT_FATAL|MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
#if ENABLE_PSTORE
|
||||
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
NULL, MNT_NONE },
|
||||
|
@ -55,7 +55,6 @@ simple_tests += files(
|
||||
'test-build-path.c',
|
||||
'test-bus-util.c',
|
||||
'test-calendarspec.c',
|
||||
'test-cgroup-setup.c',
|
||||
'test-cgroup-util.c',
|
||||
'test-cgroup.c',
|
||||
'test-chase.c',
|
||||
|
@ -1,71 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "cgroup-setup.h"
|
||||
#include "errno-util.h"
|
||||
#include "log.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static void test_is_wanted_print_one(bool header) {
|
||||
_cleanup_free_ char *cmdline = NULL;
|
||||
|
||||
log_info("-- %s --", __func__);
|
||||
ASSERT_OK(proc_cmdline(&cmdline));
|
||||
log_info("cmdline: %s", cmdline);
|
||||
if (header)
|
||||
(void) system("findmnt -n /sys/fs/cgroup");
|
||||
|
||||
log_info("is_unified_wanted() → %s", yes_no(cg_is_unified_wanted()));
|
||||
log_info("is_hybrid_wanted() → %s", yes_no(cg_is_hybrid_wanted()));
|
||||
log_info("is_legacy_wanted() → %s", yes_no(cg_is_legacy_wanted()));
|
||||
log_info(" ");
|
||||
}
|
||||
|
||||
TEST(is_wanted_print) {
|
||||
test_is_wanted_print_one(true);
|
||||
test_is_wanted_print_one(false); /* run twice to test caching */
|
||||
}
|
||||
|
||||
TEST(is_wanted) {
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"systemd.unified_cgroup_hierarchy", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"systemd.unified_cgroup_hierarchy=0", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"systemd.unified_cgroup_hierarchy=0 "
|
||||
"systemd.legacy_systemd_cgroup_controller", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"systemd.unified_cgroup_hierarchy=0 "
|
||||
"systemd.legacy_systemd_cgroup_controller=0", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
|
||||
/* cgroup_no_v1=all implies unified cgroup hierarchy, unless otherwise
|
||||
* explicitly specified. */
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"cgroup_no_v1=all", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_PROC_CMDLINE",
|
||||
"cgroup_no_v1=all "
|
||||
"systemd.unified_cgroup_hierarchy=0", 1));
|
||||
test_is_wanted_print_one(false);
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
|
||||
return log_tests_skipped("can't read /proc/cmdline");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);
|
Loading…
x
Reference in New Issue
Block a user