diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index b21f8575a03..23aedc8d8dc 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.
@@ -1194,10 +1194,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.
@@ -1254,11 +1254,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.
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);
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=