Compare commits

...

10 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek ca121e20c4 meson: use "_" as separator in test names
":" is prettier, but meson 0.56+ doesn't like it:
src/systemd/meson.build:73: DEPRECATION: ":" is not allowed in test name "cc-sd-bus.h:c", it has been replaced with "_"
src/systemd/meson.build:73: DEPRECATION: ":" is not allowed in test name "cc-sd-bus.h:c-ansi", it has been replaced with "_"
...

Fixes #17568.
2020-11-11 16:58:05 +01:00
Lennart Poettering 23dce98e89
Merge pull request #16603 from benzea/benzea/special-app-slice
Use app.slice by default in user manager (and define special user slices)
2020-11-11 14:11:02 +01:00
Zbigniew Jędrzejewski-Szmek b5e798de20 NEWS,man: tweak the description of FixedRandomDelay=
Explain why this is useful, but don't describe the implementation exactly,
since we're likely to want to change details in the future.
2020-11-11 19:10:34 +09:00
Zbigniew Jędrzejewski-Szmek 5ee24fa0a0 user: move "extrinsic" units to their root slice
With the grandparent change to move most units to app.slice,
those units would be ordered After=app.slice which doesn't make any sense.
Actually they appear earlier, before the manager is even started, and
conceputally it doesn't seem useful to put them under any slice.
2020-11-10 17:33:32 +01:00
Zbigniew Jędrzejewski-Szmek 39c79477ac pid1: expose "extrinsic" status of swaps and mounts
The only visible change from this is that we show Extrinsic: yes/no
in dumps for swap units (this was already done for mount units).
2020-11-10 14:42:42 +01:00
Benjamin Berg 1c2fd33d84 units: Move user tmpfiles clean service into background.slice 2020-10-23 10:32:02 +02:00
Benjamin Berg 0f7793bebd man: Document app, session and background special user slice units
Add documentation for the special slice user slice units.
2020-10-23 10:32:02 +02:00
Benjamin Berg 7f3b86a497 core: Move user units into app.slice by default
This changes the default from putting all units into the root slice to
placing them into the app slice in the user manager. The advantage is
that we get the right behaviour in most cases, and we'll need special
case handling in all other cases anyway.

Note that we have currently defined that applications *should* start
their unit names with app-, so we could also move only these by creating
a drop-in for app-.scope and app-.service.
However, that would not answer the question on how we should manage
session.slice. And we would end up placing anything that does not fit
the system (e.g. anything started by dbus-broker currently) into the
root slice.
2020-10-23 09:58:41 +02:00
Benjamin Berg 0b432bdc2e basic: Define macros for special user slices 2020-10-23 09:58:41 +02:00
Benjamin Berg a3081a7a89 units: Add special Desktop Environment user related units
This adds app.slice, session.slice and background.slice.
2020-10-23 09:58:41 +02:00
15 changed files with 200 additions and 77 deletions

8
NEWS
View File

@ -159,11 +159,9 @@ CHANGES WITH 247 in spe:
to the service. to the service.
* Timer units gained a new FixedRandomDelay= boolean setting. If * Timer units gained a new FixedRandomDelay= boolean setting. If
enabled the random delay configured with RandomizedDelaySec= is enabled, the random delay configured with RandomizedDelaySec= is
hashed from the unit name, system identity, and execution context, so selected in a way that is stable on a given system (though still
that always the same offset is used for the same unit on the same different for different units).
system run in the same context, in a way that is stable across system
reboots.
* Socket units gained a new setting Timestamping= that takes "us", "ns" * Socket units gained a new setting Timestamping= that takes "us", "ns"
or "off". This controls the SO_TIMESTAMP/SO_TIMESTAMPNS socket or "off". This controls the SO_TIMESTAMP/SO_TIMESTAMPNS socket

View File

@ -1179,6 +1179,60 @@
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</refsect2> </refsect2>
<refsect2>
<title>Special User Slice Units</title>
<para>There are four <literal>.slice</literal> units which form the basis of the user hierarchy for
assignment of resources for user applications and services. See
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details about slice units and the documentation about
<ulink url="https://systemd.io/DESKTOP_ENVIRONMENTS">Desktop Environments</ulink>
for further information.</para>
<variablelist>
<varlistentry>
<term><filename>-.slice</filename></term>
<listitem>
<para>The root slice is the root of the user's slice hierarchy.
It usually does not contain units directly, but may be used to set defaults for the whole tree.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>app.slice</filename></term>
<listitem>
<para>By default, all user services and applications managed by
<command>systemd</command> are found in this slice.
All interactively launched applications like web browsers and text editors
as well as non-critical services should be placed into this slice.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>session.slice</filename></term>
<listitem>
<para>All essential services and applications required for the
session should use this slice.
These are services that either cannot be restarted easily
or where latency issues may affect the interactivity of the system and applications.
This includes the display server, screen readers and other services such as DBus or XDG portals.
Such services should be configured to be part of this slice by
adding <varname>Slice=session.slice</varname> to their unit files.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>background.slice</filename></term>
<listitem>
<para>All services running low-priority background tasks should use this slice.
This permits resources to be preferentially assigned to the other slices.
Examples include non-interactive tasks like file indexing or backup operations
where latency is not important.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -240,44 +240,41 @@
<varlistentry> <varlistentry>
<term><varname>RandomizedDelaySec=</varname></term> <term><varname>RandomizedDelaySec=</varname></term>
<listitem><para>Delay the timer by a randomly selected, evenly <listitem><para>Delay the timer by a randomly selected, evenly distributed amount of time between 0
distributed amount of time between 0 and the specified time and the specified time value. Defaults to 0, indicating that no randomized delay shall be applied.
value. Defaults to 0, indicating that no randomized delay Each timer unit will determine this delay randomly before each iteration, and the delay will simply
shall be applied. Each timer unit will determine this delay be added on top of the next determined elapsing time, unless modified with
randomly before each iteration, and the delay will simply be <varname>FixedRandomDelay=</varname>, see below.</para>
added on top of the next determined elapsing time. This is
useful to stretch dispatching of similarly configured timer <para>This setting is useful to stretch dispatching of similarly configured timer events over a
events over a certain amount time, to avoid that they all fire certain time interval, to prevent them from firing all at the same time, possibly resulting in
at the same time, possibly resulting in resource resource congestion.</para>
congestion. Note the relation to
<varname>AccuracySec=</varname> above: the latter allows the <para>Note the relation to <varname>AccuracySec=</varname> above: the latter allows the service
service manager to coalesce timer events within a specified manager to coalesce timer events within a specified time range in order to minimize wakeups, while
time range in order to minimize wakeups, the former does the this setting does the opposite: it stretches timer events over an interval, to make it unlikely that
opposite: it stretches timer events over a time range, to make they fire simultaneously. If <varname>RandomizedDelaySec=</varname> and
it unlikely that they fire simultaneously. If <varname>AccuracySec=</varname> are used in conjunction, first the randomized delay is added, and
<varname>RandomizedDelaySec=</varname> and then the result is possibly further shifted to coalesce it with other timer events happening on the
<varname>AccuracySec=</varname> are used in conjunction, first system. As mentioned above <varname>AccuracySec=</varname> defaults to 1 minute and
the randomized delay is added, and then the result is <varname>RandomizedDelaySec=</varname> to 0, thus encouraging coalescing of timer events. In order to
possibly further shifted to coalesce it with other timer optimally stretch timer events over a certain range of time, set
events happening on the system. As mentioned above <varname>AccuracySec=1us</varname> and <varname>RandomizedDelaySec=</varname> to some higher value.
<varname>AccuracySec=</varname> defaults to 1min and </para></listitem>
<varname>RandomizedDelaySec=</varname> to 0, thus encouraging
coalescing of timer events. In order to optimally stretch
timer events over a certain range of time, make sure to set
<varname>RandomizedDelaySec=</varname> to a higher value, and
<varname>AccuracySec=1us</varname>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><varname>FixedRandomDelay=</varname></term> <term><varname>FixedRandomDelay=</varname></term>
<listitem><para>Takes a boolean argument. If true, some amount of time between 0 and <listitem><para>Takes a boolean argument. When enabled, the randomized offset specified by
<varname>RandomizedDelaySec=</varname> is chosen and added as the delay for each timer iteration. As this <varname>RandomizedDelaySec=</varname> is reused for all firings of the same timer. For a given timer
delay will not be recalculated on each run, this effectively creates a fixed offset for each iteration. unit, the offset depends on the machine ID, user identifier and timer name, which means that it is
The distribution between 0 and <varname>RandomizedDelaySec=</varname> is deterministic and based on stable between restarts of the manager. This effectively creates a fixed offset for an individual
a combination of the machine ID, whether the timer is run by the user/system manager, the service manager's timer, reducing the jitter in firings of this timer, while still avoiding firing at the same time as
user ID, and the timer's unit name. Has no effect if other similarly configured timers.</para>
<varname>RandomizedDelaySec=</varname> is set to 0. Defaults to <option>false</option>.</para></listitem>
<para>This setting has no effect if <varname>RandomizedDelaySec=</varname> is set to 0. Defaults to
<option>false</option>.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -107,3 +107,8 @@
/* The root directory. */ /* The root directory. */
#define SPECIAL_ROOT_MOUNT "-.mount" #define SPECIAL_ROOT_MOUNT "-.mount"
/* Special slices valid for the user instance */
#define SPECIAL_SESSION_SLICE "session.slice"
#define SPECIAL_APP_SLICE "app.slice"
#define SPECIAL_BACKGROUND_SLICE "background.slice"

View File

@ -412,8 +412,9 @@ static int mount_add_quota_dependencies(Mount *m) {
return 0; return 0;
} }
static bool mount_is_extrinsic(Mount *m) { static bool mount_is_extrinsic(Unit *u) {
MountParameters *p; MountParameters *p;
Mount *m = MOUNT(u);
assert(m); assert(m);
/* Returns true for all units that are "magic" and should be excluded from the usual /* Returns true for all units that are "magic" and should be excluded from the usual
@ -422,10 +423,7 @@ static bool mount_is_extrinsic(Mount *m) {
* ourselves but it's fine if the user operates on them with us. */ * ourselves but it's fine if the user operates on them with us. */
/* We only automatically manage mounts if we are in system mode */ /* We only automatically manage mounts if we are in system mode */
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) if (MANAGER_IS_USER(u->manager))
return true;
if (UNIT(m)->perpetual) /* All perpetual units never change state */
return true; return true;
p = get_mount_parameters(m); p = get_mount_parameters(m);
@ -493,7 +491,7 @@ static int mount_add_default_dependencies(Mount *m) {
* guaranteed to stay mounted the whole time, since our system is on it. Also, don't * guaranteed to stay mounted the whole time, since our system is on it. Also, don't
* bother with anything mounted below virtual file systems, it's also going to be virtual, * bother with anything mounted below virtual file systems, it's also going to be virtual,
* and hence not worth the effort. */ * and hence not worth the effort. */
if (mount_is_extrinsic(m)) if (mount_is_extrinsic(UNIT(m)))
return 0; return 0;
p = get_mount_parameters(m); p = get_mount_parameters(m);
@ -790,7 +788,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
prefix, p ? strna(p->options) : "n/a", prefix, p ? strna(p->options) : "n/a",
prefix, yes_no(m->from_proc_self_mountinfo), prefix, yes_no(m->from_proc_self_mountinfo),
prefix, yes_no(m->from_fragment), prefix, yes_no(m->from_fragment),
prefix, yes_no(mount_is_extrinsic(m)), prefix, yes_no(mount_is_extrinsic(u)),
prefix, m->directory_mode, prefix, m->directory_mode,
prefix, yes_no(m->sloppy_options), prefix, yes_no(m->sloppy_options),
prefix, yes_no(m->lazy_unmount), prefix, yes_no(m->lazy_unmount),
@ -2161,6 +2159,7 @@ const UnitVTable mount_vtable = {
.will_restart = unit_will_restart_default, .will_restart = unit_will_restart_default,
.may_gc = mount_may_gc, .may_gc = mount_may_gc,
.is_extrinsic = mount_is_extrinsic,
.sigchld_event = mount_sigchld_event, .sigchld_event = mount_sigchld_event,

View File

@ -56,6 +56,35 @@ static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
SWAP_CLEANING); SWAP_CLEANING);
} }
_pure_ static UnitActiveState swap_active_state(Unit *u) {
assert(u);
return state_translation_table[SWAP(u)->state];
}
_pure_ static const char *swap_sub_state_to_string(Unit *u) {
assert(u);
return swap_state_to_string(SWAP(u)->state);
}
_pure_ static bool swap_may_gc(Unit *u) {
Swap *s = SWAP(u);
assert(s);
if (s->from_proc_swaps)
return false;
return true;
}
_pure_ static bool swap_is_extrinsic(Unit *u) {
assert(SWAP(u));
return MANAGER_IS_USER(u->manager);
}
static void swap_unset_proc_swaps(Swap *s) { static void swap_unset_proc_swaps(Swap *s) {
assert(s); assert(s);
@ -610,13 +639,15 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
"%sClean Result: %s\n" "%sClean Result: %s\n"
"%sWhat: %s\n" "%sWhat: %s\n"
"%sFrom /proc/swaps: %s\n" "%sFrom /proc/swaps: %s\n"
"%sFrom fragment: %s\n", "%sFrom fragment: %s\n"
"%sExtrinsic: %s\n",
prefix, swap_state_to_string(s->state), prefix, swap_state_to_string(s->state),
prefix, swap_result_to_string(s->result), prefix, swap_result_to_string(s->result),
prefix, swap_result_to_string(s->clean_result), prefix, swap_result_to_string(s->clean_result),
prefix, s->what, prefix, s->what,
prefix, yes_no(s->from_proc_swaps), prefix, yes_no(s->from_proc_swaps),
prefix, yes_no(s->from_fragment)); prefix, yes_no(s->from_fragment),
prefix, yes_no(swap_is_extrinsic(u)));
if (s->devnode) if (s->devnode)
fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode); fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
@ -1028,29 +1059,6 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
return 0; return 0;
} }
_pure_ static UnitActiveState swap_active_state(Unit *u) {
assert(u);
return state_translation_table[SWAP(u)->state];
}
_pure_ static const char *swap_sub_state_to_string(Unit *u) {
assert(u);
return swap_state_to_string(SWAP(u)->state);
}
_pure_ static bool swap_may_gc(Unit *u) {
Swap *s = SWAP(u);
assert(s);
if (s->from_proc_swaps)
return false;
return true;
}
static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
Swap *s = SWAP(u); Swap *s = SWAP(u);
SwapResult f; SwapResult f;
@ -1649,6 +1657,7 @@ const UnitVTable swap_vtable = {
.will_restart = unit_will_restart_default, .will_restart = unit_will_restart_default,
.may_gc = swap_may_gc, .may_gc = swap_may_gc,
.is_extrinsic = swap_is_extrinsic,
.sigchld_event = swap_sigchld_event, .sigchld_event = swap_sigchld_event,

View File

@ -1988,6 +1988,10 @@ int unit_stop(Unit *u) {
bool unit_can_stop(Unit *u) { bool unit_can_stop(Unit *u) {
assert(u); assert(u);
/* Note: if we return true here, it does not mean that the unit may be successfully stopped.
* Extrinsic units follow external state and they may stop following external state changes
* (hence we return true here), but an attempt to do this through the manager will fail. */
if (!unit_type_supported(u->type)) if (!unit_type_supported(u->type))
return false; return false;
@ -3345,12 +3349,17 @@ int unit_set_default_slice(Unit *u) {
if (MANAGER_IS_SYSTEM(u->manager)) if (MANAGER_IS_SYSTEM(u->manager))
slice_name = strjoina("system-", escaped, ".slice"); slice_name = strjoina("system-", escaped, ".slice");
else else
slice_name = strjoina(escaped, ".slice"); slice_name = strjoina("app-", escaped, ".slice");
} else
slice_name = } else if (unit_is_extrinsic(u))
MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE) /* Keep all extrinsic units (e.g. perpetual units and swap and mount units in user mode) in
? SPECIAL_SYSTEM_SLICE * the root slice. They don't really belong in one of the subslices. */
: SPECIAL_ROOT_SLICE; slice_name = SPECIAL_ROOT_SLICE;
else if (MANAGER_IS_SYSTEM(u->manager))
slice_name = SPECIAL_SYSTEM_SLICE;
else
slice_name = SPECIAL_APP_SLICE;
r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice); r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
if (r < 0) if (r < 0)

View File

@ -531,6 +531,9 @@ typedef struct UnitVTable {
* even though nothing references it and it isn't active in any way. */ * even though nothing references it and it isn't active in any way. */
bool (*may_gc)(Unit *u); bool (*may_gc)(Unit *u);
/* Return true when the unit is not controlled by the manager (e.g. extrinsic mounts). */
bool (*is_extrinsic)(Unit *u);
/* When the unit is not running and no job for it queued we shall release its runtime resources */ /* When the unit is not running and no job for it queued we shall release its runtime resources */
void (*release_resources)(Unit *u); void (*release_resources)(Unit *u);
@ -684,6 +687,11 @@ int unit_set_description(Unit *u, const char *description);
bool unit_may_gc(Unit *u); bool unit_may_gc(Unit *u);
static inline bool unit_is_extrinsic(Unit *u) {
return u->perpetual ||
(UNIT_VTABLE(u)->is_extrinsic && UNIT_VTABLE(u)->is_extrinsic(u));
}
void unit_add_to_load_queue(Unit *u); void unit_add_to_load_queue(Unit *u);
void unit_add_to_dbus_queue(Unit *u); void unit_add_to_dbus_queue(Unit *u);
void unit_add_to_cleanup_queue(Unit *u); void unit_add_to_cleanup_queue(Unit *u);

View File

@ -68,7 +68,7 @@ endif
foreach header : _systemd_headers + _not_installed_headers + ['../libudev/libudev.h'] foreach header : _systemd_headers + _not_installed_headers + ['../libudev/libudev.h']
foreach opt : opts foreach opt : opts
name = ''.join(['cc-', header.split('/')[-1], ':'] + opt) name = ''.join(['cc-', header.split('/')[-1], '_'] + opt)
if want_tests != 'false' if want_tests != 'false'
test(name, test(name,
check_compilation_sh, check_compilation_sh,

12
units/user/app.slice Normal file
View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Application Slice
Documentation=man:systemd.special(7)

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Background Tasks Slice
Documentation=man:systemd.special(7)

View File

@ -1,6 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
units = [ units = [
'app.slice',
'background.slice',
'basic.target', 'basic.target',
'bluetooth.target', 'bluetooth.target',
'default.target', 'default.target',
@ -9,6 +11,7 @@ units = [
'graphical-session.target', 'graphical-session.target',
'paths.target', 'paths.target',
'printer.target', 'printer.target',
'session.slice',
'shutdown.target', 'shutdown.target',
'smartcard.target', 'smartcard.target',
'sockets.target', 'sockets.target',

12
units/user/session.slice Normal file
View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Core Session Slice
Documentation=man:systemd.special(7)

View File

@ -14,3 +14,7 @@ DefaultDependencies=no
Requires=shutdown.target Requires=shutdown.target
After=shutdown.target After=shutdown.target
SuccessAction=exit-force SuccessAction=exit-force
[Service]
# Place into the root slice to not keep another slice unit alive
Slice=-.slice

View File

@ -19,3 +19,4 @@ Type=oneshot
ExecStart=systemd-tmpfiles --user --clean ExecStart=systemd-tmpfiles --user --clean
SuccessExitStatus=DATAERR SuccessExitStatus=DATAERR
IOSchedulingClass=idle IOSchedulingClass=idle
Slice=background.slice