From 9dfb6a3a8e1183a7988691377fe7bf747ff38bc0 Mon Sep 17 00:00:00 2001 From: Peter Morrow Date: Thu, 16 Sep 2021 12:21:20 +0100 Subject: [PATCH 1/3] cgroup: re-evaluate startup units during shutdown as well Apply startup cgroup configuration options to the shutdown phase as well. I.e. all directives prefixed with Startup are applied during boot and shutdown. For example: StartupAllowedCPU= applies during boot and shutdown. AllowedCPUs= applies during normal runtime. --- src/core/cgroup.c | 33 ++++++++++++++++++++++++++------- src/core/cgroup.h | 2 ++ src/core/job.c | 2 ++ src/core/unit.c | 10 +--------- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 17e93d7af17..c19454e8bdd 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -68,6 +68,25 @@ bool manager_owns_host_root_cgroup(Manager *m) { return empty_or_root(m->cgroup_root); } +bool unit_has_startup_cgroup_constraints(Unit *u) { + assert(u); + + /* Returns true if this unit has any directives which apply during + * startup/shutdown phases. */ + + CGroupContext *c; + + c = unit_get_cgroup_context(u); + if (!c) + return false; + + return c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID || + c->startup_io_weight != CGROUP_WEIGHT_INVALID || + c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || + c->startup_cpuset_cpus.set || + c->startup_cpuset_mems.set; +} + bool unit_has_host_root_cgroup(Unit *u) { assert(u); @@ -844,7 +863,7 @@ static bool cgroup_context_has_allowed_mems(CGroupContext *c) { } static uint64_t cgroup_context_cpu_weight(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_cpu_weight != CGROUP_WEIGHT_INVALID) return c->startup_cpu_weight; else if (c->cpu_weight != CGROUP_WEIGHT_INVALID) @@ -854,7 +873,7 @@ static uint64_t cgroup_context_cpu_weight(CGroupContext *c, ManagerState state) } static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID) return c->startup_cpu_shares; else if (c->cpu_shares != CGROUP_CPU_SHARES_INVALID) @@ -864,7 +883,7 @@ static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state) } static CPUSet *cgroup_context_allowed_cpus(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_cpuset_cpus.set) return &c->startup_cpuset_cpus; else @@ -872,7 +891,7 @@ static CPUSet *cgroup_context_allowed_cpus(CGroupContext *c, ManagerState state) } static CPUSet *cgroup_context_allowed_mems(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_cpuset_mems.set) return &c->startup_cpuset_mems; else @@ -993,7 +1012,7 @@ static bool cgroup_context_has_blockio_config(CGroupContext *c) { } static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_io_weight != CGROUP_WEIGHT_INVALID) return c->startup_io_weight; else if (c->io_weight != CGROUP_WEIGHT_INVALID) @@ -1003,7 +1022,7 @@ static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) { } static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) { - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) return c->startup_blockio_weight; else if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) @@ -3971,7 +3990,7 @@ void manager_invalidate_startup_units(Manager *m) { assert(m); SET_FOREACH(u, m->startup_units) - unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO); + unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO|CGROUP_MASK_CPUSET); } static int unit_get_nice(Unit *u) { diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 951ddda525a..8795f2724eb 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -311,6 +311,8 @@ int unit_reset_accounting(Unit *u); bool manager_owns_host_root_cgroup(Manager *m); bool unit_has_host_root_cgroup(Unit *u); +bool unit_has_startup_cgroup_constraints(Unit *u); + int manager_notify_cgroup_empty(Manager *m, const char *group); void unit_invalidate_cgroup(Unit *u, CGroupMask m); diff --git a/src/core/job.c b/src/core/job.c index 6eb135785b1..6dd01a6f49d 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1335,6 +1335,8 @@ void job_shutdown_magic(Job *j) { /* In case messages on console has been disabled on boot */ j->unit->manager->no_console_output = false; + manager_invalidate_startup_units(j->unit->manager); + if (detect_container() > 0) return; diff --git a/src/core/unit.c b/src/core/unit.c index 1a76abf8a16..4fd499a4f1d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1557,15 +1557,7 @@ static int unit_add_oomd_dependencies(Unit *u) { } static int unit_add_startup_units(Unit *u) { - CGroupContext *c; - - c = unit_get_cgroup_context(u); - if (!c) - return 0; - - if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID && - c->startup_io_weight == CGROUP_WEIGHT_INVALID && - c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID) + if (!unit_has_startup_cgroup_constraints(u)) return 0; return set_ensure_put(&u->manager->startup_units, NULL, u); From 1b75e5f343db3d938e37a79c06d83b528b10c8fa Mon Sep 17 00:00:00 2001 From: Peter Morrow Date: Thu, 16 Sep 2021 12:33:16 +0100 Subject: [PATCH 2/3] fuzz: list directives in alphabetical order --- test/fuzz/fuzz-unit-file/directives.mount | 4 ++-- test/fuzz/fuzz-unit-file/directives.scope | 4 ++-- test/fuzz/fuzz-unit-file/directives.service | 4 ++-- test/fuzz/fuzz-unit-file/directives.slice | 4 ++-- test/fuzz/fuzz-unit-file/directives.socket | 4 ++-- test/fuzz/fuzz-unit-file/directives.swap | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount index da33c99de35..33c44c79c5d 100644 --- a/test/fuzz/fuzz-unit-file/directives.mount +++ b/test/fuzz/fuzz-unit-file/directives.mount @@ -1,9 +1,7 @@ mount [Mount] AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= AmbientCapabilities= AppArmorProfile= BPFProgram= @@ -174,6 +172,8 @@ StandardInput= StandardInputData= StandardInputText= StandardOutput= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope index d8ea9fcfb54..aa91ebbf588 100644 --- a/test/fuzz/fuzz-unit-file/directives.scope +++ b/test/fuzz/fuzz-unit-file/directives.scope @@ -1,9 +1,7 @@ scope [Scope] AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= BPFProgram= BlockIOAccounting= BlockIODeviceWeight= @@ -57,6 +55,8 @@ SendSIGKILL= Slice= SocketBindAllow= SocketBindDeny= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service index 7318c5f9d69..d92d90e1181 100644 --- a/test/fuzz/fuzz-unit-file/directives.service +++ b/test/fuzz/fuzz-unit-file/directives.service @@ -115,9 +115,7 @@ RequiredBy= WantedBy= [Service] AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= AmbientCapabilities= AppArmorProfile= BindPaths= @@ -308,6 +306,8 @@ StandardOutput= StartLimitAction= StartLimitBurst= StartLimitInterval= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice index 1a209876987..ab77070c5ea 100644 --- a/test/fuzz/fuzz-unit-file/directives.slice +++ b/test/fuzz/fuzz-unit-file/directives.slice @@ -1,9 +1,7 @@ slice [Slice] AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= BPFProgram= BlockIOAccounting= BlockIODeviceWeight= @@ -50,6 +48,8 @@ RestrictNetworkInterfaces= Slice= SocketBindAllow= SocketBindDeny= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket index 02b909f00d2..fa28ff10421 100644 --- a/test/fuzz/fuzz-unit-file/directives.socket +++ b/test/fuzz/fuzz-unit-file/directives.socket @@ -2,9 +2,7 @@ socket [Socket] Accept= AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= AmbientCapabilities= AppArmorProfile= BPFProgram= @@ -220,6 +218,8 @@ StandardInput= StandardInputData= StandardInputText= StandardOutput= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap index b7598fdf06f..abb3cd54e71 100644 --- a/test/fuzz/fuzz-unit-file/directives.swap +++ b/test/fuzz/fuzz-unit-file/directives.swap @@ -1,9 +1,7 @@ swap [Swap] AllowedCPUs= -StartupAllowedCPUs= AllowedMemoryNodes= -StartupAllowedMemoryNodes= AmbientCapabilities= AppArmorProfile= BPFProgram= @@ -170,6 +168,8 @@ StandardInput= StandardInputData= StandardInputText= StandardOutput= +StartupAllowedCPUs= +StartupAllowedMemoryNodes= StartupBlockIOWeight= StartupCPUShares= StartupCPUWeight= From 058a2d8f1376199861555c94b1915af0a6d7c925 Mon Sep 17 00:00:00 2001 From: Peter Morrow Date: Fri, 17 Sep 2021 11:13:39 +0100 Subject: [PATCH 3/3] man: Startup* updates for systemd.resource-control All Startup*= directives now also apply to the shutdown phase as well as boot phase. --- man/systemd.resource-control.xml | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index ea728dff338..f0b355d46ad 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -189,10 +189,10 @@ Scheduler. The available CPU time is split up among all units within one slice relative to their CPU time weight. A higher weight means more CPU time, a lower weight means less. - While StartupCPUWeight= only applies to the startup phase of the system, + While StartupCPUWeight= applies to the startup and shutdown phases of the system, CPUWeight= applies to normal runtime of the system, and if the former is not set also to - the startup phase. Using StartupCPUWeight= allows prioritizing specific services at - boot-up differently than during normal runtime. + the startup and shutdown phases. Using StartupCPUWeight= allows prioritizing specific services at + boot-up and shutdown differently than during normal runtime. These settings replace CPUShares= and StartupCPUShares=. @@ -247,10 +247,10 @@ of the CPUs will be used by the processes as it may be limited by parent units. The effective configuration is reported as EffectiveCPUs=. - While StartupAllowedCPUs= only applies to the startup phase of the system, + While StartupAllowedCPUs= applies to the startup and shutdown phases of the system, AllowedCPUs= applies to normal runtime of the system, and if the former is not set also to - the startup phase. Using StartupAllowedCPUs= allows prioritizing specific services at - boot-up differently than during normal runtime. + the startup and shutdown phases. Using StartupAllowedCPUs= allows prioritizing specific services at + boot-up and shutdown differently than during normal runtime. This setting is supported only with the unified control group hierarchy. @@ -269,10 +269,10 @@ guarantee that all of the memory NUMA nodes will be used by the processes as it may be limited by parent units. The effective configuration is reported as EffectiveMemoryNodes=. - While StartupAllowedMemoryNodes= only applies to the startup phase of the system, + While StartupAllowedMemoryNodes= applies to the startup and shutdown phases of the system, AllowedMemoryNodes= applies to normal runtime of the system, and if the former is not set also to - the startup phase. Using StartupAllowedMemoryNodes= allows prioritizing specific services at - boot-up differently than during normal runtime. + the startup and shutdown phases. Using StartupAllowedMemoryNodes= allows prioritizing specific services at + boot-up and shutdown differently than during normal runtime. This setting is supported only with the unified control group hierarchy. @@ -458,12 +458,12 @@ relative to their block I/O weight. A higher weight means more I/O bandwidth, a lower weight means less. - While StartupIOWeight= only applies - to the startup phase of the system, + While StartupIOWeight= applies + to the startup and shutdown phases of the system, IOWeight= applies to the later runtime of the system, and if the former is not set also to the startup - phase. This allows prioritizing specific services at boot-up - differently than during runtime. + and shutdown phases. This allows prioritizing specific services at boot-up + and shutdown differently than during runtime. These settings replace BlockIOWeight= and StartupBlockIOWeight= and disable settings prefixed with BlockIO or StartupBlockIO. @@ -1189,10 +1189,10 @@ DeviceAllow=/dev/loop-control The available CPU time is split up among all units within one slice relative to their CPU time share weight. - While StartupCPUShares= only applies to the startup phase of the system, + While StartupCPUShares= applies to the startup and shutdown phases of the system, CPUShares= applies to normal runtime of the system, and if the former is not set also to - the startup phase. Using StartupCPUShares= allows prioritizing specific services at - boot-up differently than during normal runtime. + the startup and shutdown phases. Using StartupCPUShares= allows prioritizing specific services at + boot-up and shutdown differently than during normal runtime. Implies CPUAccounting=yes. @@ -1249,11 +1249,11 @@ DeviceAllow=/dev/loop-control weight. While StartupBlockIOWeight= only - applies to the startup phase of the system, + applies to the startup and shutdown phases of the system, BlockIOWeight= applies to the later runtime of the system, and if the former is not set also to the - startup phase. This allows prioritizing specific services at - boot-up differently than during runtime. + startup and shutdown phases. This allows prioritizing specific services at + boot-up and shutdown differently than during runtime. Implies BlockIOAccounting=yes.