Merge pull request #31442 from YHNdnzj/towards-cgroup-v1-deprecation
core: refuse cgroupv1 unless SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE
This commit is contained in:
@@ -7,6 +7,13 @@ CHANGES WITH 256 in spe:
|
||||
* Support for flushing of the nscd user/group database caches will be
|
||||
dropped in a future release.
|
||||
|
||||
* Support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now
|
||||
considered obsolete and systemd by default will refuse to boot under it.
|
||||
To forcibly reenable cgroup v1 support, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1
|
||||
must be set on kernel command line. The meson option 'default-hierarchy='
|
||||
is also deprecated, i.e. only cgroup v2 ('unified' hierarchy) can be
|
||||
selected as build-time default.
|
||||
|
||||
* Previously, systemd-networkd did not explicitly remove any bridge VLAN
|
||||
IDs assigned on bridge master and ports. Since v256, if a .network
|
||||
file for an interface has at least one valid settings in [BridgeVLAN]
|
||||
|
||||
-12
@@ -761,17 +761,6 @@ if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0
|
||||
endif
|
||||
conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
|
||||
|
||||
default_hierarchy = get_option('default-hierarchy')
|
||||
conf.set_quoted('DEFAULT_HIERARCHY_NAME', default_hierarchy,
|
||||
description : 'default cgroup hierarchy as string')
|
||||
if default_hierarchy == 'legacy'
|
||||
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_NONE')
|
||||
elif default_hierarchy == 'hybrid'
|
||||
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_SYSTEMD')
|
||||
else
|
||||
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_ALL')
|
||||
endif
|
||||
|
||||
extra_net_naming_schemes = []
|
||||
extra_net_naming_map = []
|
||||
foreach scheme: get_option('extra-net-naming-schemes').split(',')
|
||||
@@ -2768,7 +2757,6 @@ summary({
|
||||
'default LLMNR mode' : default_llmnr,
|
||||
'default DNS servers' : dns_servers.split(' '),
|
||||
'default NTP servers' : ntp_servers.split(' '),
|
||||
'default cgroup hierarchy' : default_hierarchy,
|
||||
'default net.naming-scheme value' : default_net_naming_scheme,
|
||||
'default KillUserProcesses value' : kill_user_processes,
|
||||
'default locale' : default_locale,
|
||||
|
||||
+2
-2
@@ -227,8 +227,8 @@ option('configfiledir', type : 'string', value : '',
|
||||
option('fallback-hostname', type : 'string', value : 'localhost',
|
||||
description : 'the hostname used if none configured')
|
||||
option('default-hierarchy', type : 'combo',
|
||||
choices : ['legacy', 'hybrid', 'unified'], value : 'unified',
|
||||
description : 'default cgroup hierarchy')
|
||||
choices : ['legacy', 'hybrid', 'unified'], deprecated : true,
|
||||
description : '''This option is deprecated and will be removed in a future release''')
|
||||
option('extra-net-naming-schemes', type : 'string',
|
||||
description : 'comma-separated list of extra net.naming-scheme= definitions')
|
||||
option('default-net-naming-scheme', type : 'string', value : 'latest',
|
||||
|
||||
@@ -244,7 +244,6 @@ const char* const systemd_features =
|
||||
" -LIBARCHIVE"
|
||||
#endif
|
||||
|
||||
" default-hierarchy=" DEFAULT_HIERARCHY_NAME
|
||||
;
|
||||
|
||||
static char *systemd_features_with_color(void) {
|
||||
|
||||
+1
-1
@@ -4783,7 +4783,7 @@ static int unit_get_io_accounting_raw(Unit *u, uint64_t ret[static _CGROUP_IO_AC
|
||||
r = cg_all_unified();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* TODO: support cgroupv1 */
|
||||
if (r == 0)
|
||||
return -ENODATA;
|
||||
|
||||
if (!FLAGS_SET(crt->cgroup_realized_mask, CGROUP_MASK_IO))
|
||||
|
||||
+19
-7
@@ -666,7 +666,7 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
|
||||
{ "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type },
|
||||
{ "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy },
|
||||
{ "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
|
||||
{ "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_LEGACY, NULL },
|
||||
{ "Manager", "RuntimeWatchdogSec", config_parse_watchdog_sec, 0, &arg_runtime_watchdog },
|
||||
{ "Manager", "RuntimeWatchdogPreSec", config_parse_watchdog_sec, 0, &arg_pretimeout_watchdog },
|
||||
{ "Manager", "RebootWatchdogSec", config_parse_watchdog_sec, 0, &arg_reboot_watchdog },
|
||||
@@ -2290,12 +2290,6 @@ static int initialize_runtime(
|
||||
install_crash_handler();
|
||||
|
||||
if (!skip_setup) {
|
||||
r = mount_cgroup_controllers();
|
||||
if (r < 0) {
|
||||
*ret_error_message = "Failed to mount cgroup hierarchies";
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Pull credentials from various sources into a common credential directory (we do
|
||||
* this here, before setting up the machine ID, so that we can use credential info
|
||||
* for setting up the machine ID) */
|
||||
@@ -3022,6 +3016,24 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!skip_setup) {
|
||||
/* Before we actually start deleting cgroup v1 code, make it harder to boot
|
||||
* in cgroupv1 mode first. See also #30852. */
|
||||
|
||||
r = mount_cgroup_legacy_controllers(loaded_policy);
|
||||
if (r < 0) {
|
||||
if (r == -ERFKILL)
|
||||
error_message = "Refusing to run under cgroup v1, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 not specified on kernel command line";
|
||||
else
|
||||
error_message = "Failed to mount cgroup v1 hierarchy";
|
||||
goto finish;
|
||||
}
|
||||
if (r > 0) {
|
||||
log_full(LOG_CRIT, "Legacy cgroup v1 support selected. This is no longer supported. Will proceed anyway after 30s.");
|
||||
(void) usleep_safe(30 * USEC_PER_SEC);
|
||||
}
|
||||
}
|
||||
|
||||
/* The efivarfs is now mounted, let's lock down the system token. */
|
||||
lock_down_efi_variables();
|
||||
|
||||
|
||||
+29
-16
@@ -81,9 +81,6 @@ static int cg_any_controller_used_for_v1(void) {
|
||||
|
||||
bool cg_is_unified_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
bool b;
|
||||
const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
|
||||
_cleanup_free_ char *c = NULL;
|
||||
int r;
|
||||
|
||||
/* If we have a cached value, return that. */
|
||||
@@ -96,21 +93,20 @@ bool cg_is_unified_wanted(void) {
|
||||
return (wanted = r >= CGROUP_UNIFIED_ALL);
|
||||
|
||||
/* If we were explicitly passed systemd.unified_cgroup_hierarchy, respect that. */
|
||||
bool b;
|
||||
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", /* flags = */ 0, &b);
|
||||
if (r > 0)
|
||||
return (wanted = b);
|
||||
|
||||
/* 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 = is_default);
|
||||
return (wanted = cg_any_controller_used_for_v1() <= 0);
|
||||
}
|
||||
|
||||
bool cg_is_legacy_wanted(void) {
|
||||
@@ -132,10 +128,6 @@ bool cg_is_legacy_wanted(void) {
|
||||
bool cg_is_hybrid_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
int r;
|
||||
bool b;
|
||||
const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
|
||||
/* We default to true if the default is "hybrid", obviously, but also when the default is "unified",
|
||||
* because if we get called, it means that unified hierarchy was not mounted. */
|
||||
|
||||
/* If we have a cached value, return that. */
|
||||
if (wanted >= 0)
|
||||
@@ -146,12 +138,33 @@ bool cg_is_hybrid_wanted(void) {
|
||||
return (wanted = false);
|
||||
|
||||
/* Otherwise, let's see what the kernel command line has to say. Since checking is expensive, cache
|
||||
* a non-error result. */
|
||||
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", /* flags = */ 0, &b);
|
||||
|
||||
/* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
|
||||
* a non-error result.
|
||||
* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
|
||||
* negation. */
|
||||
return (wanted = r > 0 ? !b : is_default);
|
||||
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_force_enabled(void) {
|
||||
bool force;
|
||||
|
||||
if (!cg_is_legacy_wanted())
|
||||
return false;
|
||||
|
||||
/* If in container, we have to follow host's cgroup hierarchy. */
|
||||
if (detect_container() > 0)
|
||||
return true;
|
||||
|
||||
if (proc_cmdline_get_bool("SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE", /* flags = */ 0, &force) < 0)
|
||||
return false;
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
int cg_weight_parse(const char *s, uint64_t *ret) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
bool cg_is_unified_wanted(void);
|
||||
bool cg_is_legacy_wanted(void);
|
||||
bool cg_is_hybrid_wanted(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);
|
||||
|
||||
+140
-132
@@ -107,16 +107,6 @@ static const MountPoint mount_table[] = {
|
||||
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 },
|
||||
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
|
||||
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_legacy_wanted, MNT_IN_CONTAINER },
|
||||
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
#if ENABLE_PSTORE
|
||||
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
NULL, MNT_NONE },
|
||||
@@ -167,8 +157,11 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
int r, priority;
|
||||
|
||||
assert(p);
|
||||
assert(p->what);
|
||||
assert(p->where);
|
||||
assert(p->type);
|
||||
|
||||
priority = (p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
|
||||
priority = FLAGS_SET(p->mode, MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
|
||||
|
||||
if (p->condition_fn && !p->condition_fn())
|
||||
return 0;
|
||||
@@ -180,13 +173,13 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
r = path_is_mount_point_full(p->where, /* root = */ NULL, AT_SYMLINK_FOLLOW);
|
||||
if (r < 0 && r != -ENOENT) {
|
||||
log_full_errno(priority, r, "Failed to determine whether %s is a mount point: %m", p->where);
|
||||
return (p->mode & MNT_FATAL) ? r : 0;
|
||||
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
|
||||
}
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
/* Skip securityfs in a container */
|
||||
if (!(p->mode & MNT_IN_CONTAINER) && detect_container() > 0)
|
||||
if (!FLAGS_SET(p->mode, MNT_IN_CONTAINER) && detect_container() > 0)
|
||||
return 0;
|
||||
|
||||
/* The access mode here doesn't really matter too much, since
|
||||
@@ -207,39 +200,35 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
else
|
||||
r = mount_nofollow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
|
||||
if (r < 0)
|
||||
return (p->mode & MNT_FATAL) ? r : 0;
|
||||
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
|
||||
|
||||
/* Relabel again, since we now mounted something fresh here */
|
||||
if (relabel)
|
||||
(void) label_fix(p->where, 0);
|
||||
|
||||
if (p->mode & MNT_CHECK_WRITABLE) {
|
||||
if (FLAGS_SET(p->mode, MNT_CHECK_WRITABLE))
|
||||
if (access(p->where, W_OK) < 0) {
|
||||
r = -errno;
|
||||
|
||||
(void) umount2(p->where, UMOUNT_NOFOLLOW);
|
||||
(void) rmdir(p->where);
|
||||
|
||||
log_full_errno(priority, r, "Mount point %s not writable after mounting, undoing: %m", p->where);
|
||||
return (p->mode & MNT_FATAL) ? r : 0;
|
||||
log_full_errno(priority, r, "Mount point '%s' not writable after mounting, undoing: %m", p->where);
|
||||
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mount_points_setup(size_t n, bool loaded_policy) {
|
||||
int ret = 0, r;
|
||||
int r = 0;
|
||||
|
||||
assert(n <= ELEMENTSOF(mount_table));
|
||||
|
||||
FOREACH_ARRAY(mp, mount_table, n) {
|
||||
r = mount_one(mp, loaded_policy);
|
||||
if (r != 0 && ret >= 0)
|
||||
ret = r;
|
||||
}
|
||||
FOREACH_ARRAY(mp, mount_table, n)
|
||||
RET_GATHER(r, mount_one(mp, loaded_policy));
|
||||
|
||||
return ret;
|
||||
return r;
|
||||
}
|
||||
|
||||
int mount_setup_early(void) {
|
||||
@@ -297,81 +286,6 @@ static int symlink_controller(const char *target, const char *alias) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mount_cgroup_controllers(void) {
|
||||
_cleanup_set_free_ Set *controllers = NULL;
|
||||
int r;
|
||||
|
||||
if (!cg_is_legacy_wanted())
|
||||
return 0;
|
||||
|
||||
/* Mount all available cgroup controllers that are built into the kernel. */
|
||||
r = cg_kernel_controllers(&controllers);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
|
||||
const char *other_controller;
|
||||
MountPoint p = {
|
||||
.what = "cgroup",
|
||||
.type = "cgroup",
|
||||
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
.mode = MNT_IN_CONTAINER,
|
||||
};
|
||||
|
||||
controller = set_steal_first(controllers);
|
||||
if (!controller)
|
||||
break;
|
||||
|
||||
/* Check if we shall mount this together with another controller */
|
||||
other_controller = join_with(controller);
|
||||
if (other_controller) {
|
||||
_cleanup_free_ char *c = NULL;
|
||||
|
||||
/* Check if the other controller is actually available in the kernel too */
|
||||
c = set_remove(controllers, other_controller);
|
||||
if (c) {
|
||||
|
||||
/* Join the two controllers into one string, and maintain a stable ordering */
|
||||
if (strcmp(controller, other_controller) < 0)
|
||||
options = strjoin(controller, ",", other_controller);
|
||||
else
|
||||
options = strjoin(other_controller, ",", controller);
|
||||
if (!options)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
/* The simple case, where there's only one controller to mount together */
|
||||
if (!options)
|
||||
options = TAKE_PTR(controller);
|
||||
|
||||
where = path_join("/sys/fs/cgroup", options);
|
||||
if (!where)
|
||||
return log_oom();
|
||||
|
||||
p.where = where;
|
||||
p.options = options;
|
||||
|
||||
r = mount_one(&p, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Create symlinks from the individual controller names, in case we have a joined mount */
|
||||
if (controller)
|
||||
(void) symlink_controller(options, controller);
|
||||
if (other_controller)
|
||||
(void) symlink_controller(options, other_controller);
|
||||
}
|
||||
|
||||
/* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
|
||||
(void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
|
||||
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
|
||||
"mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_SELINUX || ENABLE_SMACK
|
||||
static int relabel_cb(
|
||||
RecurseDirEvent event,
|
||||
@@ -415,34 +329,6 @@ static int relabel_tree(const char *path) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int relabel_cgroup_filesystems(void) {
|
||||
int r;
|
||||
struct statfs st;
|
||||
|
||||
r = cg_all_unified();
|
||||
if (r == 0) {
|
||||
/* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
|
||||
only when the filesystem has been already populated by a previous instance of systemd
|
||||
running from initrd. Otherwise don't remount anything and leave the filesystem read-write
|
||||
for the cgroup filesystems to be mounted inside. */
|
||||
if (statfs("/sys/fs/cgroup", &st) < 0)
|
||||
return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
|
||||
|
||||
(void) label_fix("/sys/fs/cgroup", 0);
|
||||
(void) relabel_tree("/sys/fs/cgroup");
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
|
||||
|
||||
} else if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int relabel_extra(void) {
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
int r, c = 0;
|
||||
@@ -533,14 +419,12 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
|
||||
FOREACH_STRING(i, "/dev", "/dev/shm", "/run")
|
||||
(void) relabel_tree(i);
|
||||
|
||||
(void) relabel_cgroup_filesystems();
|
||||
|
||||
n_extra = relabel_extra();
|
||||
|
||||
after_relabel = now(CLOCK_MONOTONIC);
|
||||
|
||||
log_info("Relabeled /dev, /dev/shm, /run, /sys/fs/cgroup%s in %s.",
|
||||
n_extra > 0 ? ", additional files" : "",
|
||||
log_info("Relabeled /dev/, /dev/shm/, /run/%s in %s.",
|
||||
n_extra > 0 ? ", and additional files" : "",
|
||||
FORMAT_TIMESPAN(after_relabel - before_relabel, 0));
|
||||
}
|
||||
#endif
|
||||
@@ -589,3 +473,127 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const MountPoint cgroupv1_mount_table[] = {
|
||||
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
|
||||
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
|
||||
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_legacy_wanted, MNT_IN_CONTAINER },
|
||||
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
};
|
||||
|
||||
static void relabel_cgroup_legacy_hierarchy(void) {
|
||||
#if HAVE_SELINUX || ENABLE_SMACK
|
||||
struct statfs st;
|
||||
|
||||
assert(cg_is_legacy_wanted());
|
||||
|
||||
/* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
|
||||
only when the filesystem has been already populated by a previous instance of systemd
|
||||
running from initrd. Otherwise don't remount anything and leave the filesystem read-write
|
||||
for the cgroup filesystems to be mounted inside. */
|
||||
if (statfs("/sys/fs/cgroup", &st) < 0)
|
||||
return (void) log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup/: %m");
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
|
||||
|
||||
(void) label_fix("/sys/fs/cgroup", 0);
|
||||
(void) relabel_tree("/sys/fs/cgroup");
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
int mount_cgroup_legacy_controllers(bool loaded_policy) {
|
||||
_cleanup_set_free_ Set *controllers = NULL;
|
||||
int r;
|
||||
|
||||
if (!cg_is_legacy_wanted())
|
||||
return 0;
|
||||
|
||||
if (!cg_is_legacy_force_enabled())
|
||||
return -ERFKILL;
|
||||
|
||||
FOREACH_ARRAY(mp, cgroupv1_mount_table, ELEMENTSOF(cgroupv1_mount_table)) {
|
||||
r = mount_one(mp, loaded_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (loaded_policy)
|
||||
relabel_cgroup_legacy_hierarchy();
|
||||
|
||||
/* Mount all available cgroup controllers that are built into the kernel. */
|
||||
r = cg_kernel_controllers(&controllers);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
|
||||
const char *other_controller;
|
||||
MountPoint p = {
|
||||
.what = "cgroup",
|
||||
.type = "cgroup",
|
||||
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
.mode = MNT_IN_CONTAINER,
|
||||
};
|
||||
|
||||
controller = set_steal_first(controllers);
|
||||
if (!controller)
|
||||
break;
|
||||
|
||||
/* Check if we shall mount this together with another controller */
|
||||
other_controller = join_with(controller);
|
||||
if (other_controller) {
|
||||
_cleanup_free_ char *c = NULL;
|
||||
|
||||
/* Check if the other controller is actually available in the kernel too */
|
||||
c = set_remove(controllers, other_controller);
|
||||
if (c) {
|
||||
|
||||
/* Join the two controllers into one string, and maintain a stable ordering */
|
||||
if (strcmp(controller, other_controller) < 0)
|
||||
options = strjoin(controller, ",", other_controller);
|
||||
else
|
||||
options = strjoin(other_controller, ",", controller);
|
||||
if (!options)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
/* The simple case, where there's only one controller to mount together */
|
||||
if (!options)
|
||||
options = TAKE_PTR(controller);
|
||||
|
||||
where = path_join("/sys/fs/cgroup", options);
|
||||
if (!where)
|
||||
return log_oom();
|
||||
|
||||
p.where = where;
|
||||
p.options = options;
|
||||
|
||||
r = mount_one(&p, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Create symlinks from the individual controller names, in case we have a joined mount */
|
||||
if (controller)
|
||||
(void) symlink_controller(options, controller);
|
||||
if (other_controller)
|
||||
(void) symlink_controller(options, other_controller);
|
||||
}
|
||||
|
||||
/* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
|
||||
(void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
|
||||
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
|
||||
"mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool mount_point_is_api(const char *path);
|
||||
bool mount_point_ignore(const char *path);
|
||||
|
||||
int mount_setup_early(void);
|
||||
int mount_setup(bool loaded_policy, bool leave_propagation);
|
||||
|
||||
int mount_cgroup_controllers(void);
|
||||
|
||||
bool mount_point_is_api(const char *path);
|
||||
bool mount_point_ignore(const char *path);
|
||||
int mount_cgroup_legacy_controllers(bool loaded_policy);
|
||||
|
||||
@@ -16,10 +16,8 @@ static void test_is_wanted_print_one(bool header) {
|
||||
log_info("-- %s --", __func__);
|
||||
assert_se(proc_cmdline(&cmdline) >= 0);
|
||||
log_info("cmdline: %s", cmdline);
|
||||
if (header) {
|
||||
log_info("default-hierarchy=" DEFAULT_HIERARCHY_NAME);
|
||||
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()));
|
||||
|
||||
Reference in New Issue
Block a user