We already record when shutdown.target is initiated (ShutdownStart).
This adds a few more measuring points during shutdown: when
shutdown.target completes (i.e., all units stopped), when the shutdown
binary starts executing, and immediately before it hands off to the
kernel.
Obviously these are immediately lost upon reboot. But they will later
be wired in LUO so they get preserved on kexec, and can be inspected,
which is very useful for performance measurements.
Since this was introduced I constantly find myself waiting for VMs to
shut down at the end of a test. This not only happens with mkosi
integration tests, but with other VM-based tests like for example
autopkgtest. In this example, this dracut test suite runtime is tripled
due to the artificial delay:
```
[ 5.813234] systemd-shutdown[1]: Syncing filesystems and block devices.
[ 5.814635] systemd-shutdown[1]: Delaying shutdown for 9s, in order to reach minimum uptime of 15s.
[ 8.816855] systemd-shutdown[1]: Delaying shutdown for 6s, in order to reach minimum uptime of 15s.
[ 11.819747] systemd-shutdown[1]: Delaying shutdown for 3s, in order to reach minimum uptime of 15s.
[ 14.822660] systemd-shutdown[1]: Delaying shutdown for 601ms, in order to reach minimum uptime of 15s.
[ 15.427777] systemd-shutdown[1]: Powering off.
[ 15.429681] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[ 15.433620] ACPI: PM: Preparing to enter system sleep state S5
[ 15.435148] reboot: Power down
TEST: root filesystem on a ext4 filesystem with systemd and extensions [OK]
autopkgtest [19:39:12]: test 46-systemd-sysext: -----------------------]
autopkgtest [19:39:13]: test 46-systemd-sysext: - - - - - - - - - - results - - - - - - - - - -
46-systemd-sysext PASS
```
Contrary to what the comment claimed, the scrollback of a VM is _not_
cleared, EDK2 just prints many pages, and one can just scroll up (a
lot).
Do not delay by default on VMs. Move the check so that in both
containers and VMs users can override and force a delay with the env
var.
Follow-up for 0874eea302
Switch the executable-owned call sites from the plain dlopen_<lib>()
helpers to the new DLOPEN_<LIB>() macros, so that each binary that loads
an optional library at runtime now carries its own .note.dlopen note
instead of relying solely on libsystemd-shared. Each call site passes a
priority reflecting whether it hard-depends on the library (required) or
degrades gracefully without it (recommended).
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
Since this was introduced I constantly find myself waiting for VMs to
shut down at the end of a test. This not only happens with mkosi integration
tests, but with other VM-based tests like for example autopkgtest. In this
example, this dracut test suite runtime is tripled due to the artificial delay:
[ 5.813234] systemd-shutdown[1]: Syncing filesystems and block devices.
[ 5.814635] systemd-shutdown[1]: Delaying shutdown for 9s, in order to reach minimum uptime of 15s.
[ 8.816855] systemd-shutdown[1]: Delaying shutdown for 6s, in order to reach minimum uptime of 15s.
[ 11.819747] systemd-shutdown[1]: Delaying shutdown for 3s, in order to reach minimum uptime of 15s.
[ 14.822660] systemd-shutdown[1]: Delaying shutdown for 601ms, in order to reach minimum uptime of 15s.
[ 15.427777] systemd-shutdown[1]: Powering off.
[ 15.429681] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[ 15.433620] ACPI: PM: Preparing to enter system sleep state S5
[ 15.435148] reboot: Power down
TEST: root filesystem on a ext4 filesystem with systemd and extensions [OK]
autopkgtest [19:39:12]: test 46-systemd-sysext: -----------------------]
autopkgtest [19:39:13]: test 46-systemd-sysext: - - - - - - - - - - results - - - - - - - - - -
46-systemd-sysext PASS
Contrary to what the comment claimed, the scrollback of a VM is _not_
cleared, EDK2 just prints many pages, and one can just scroll up (a lot).
Do not delay by default on VMs. Move the check so that in both containers
and VMs users can override and force a delay with the env var.
Follow-up for 0874eea302
Wires up the systemd-shutdown side of the kexec-via-LUO fd store preservation.
When rebooting via kexec, systemd builds a JSON description of the fd
stores of all loaded services and passes it to systemd-shutdown through
the SYSTEMD_LUO_SERIALIZE_FD environment variable. The FDs themselves
come in as part of the normal shutdown FDSet. systemd-shutdown's job is
then, at the very last moment before invoking the kexec syscall, to
move that state into a kernel LUO session so it survives the reboot.
Doing the LUO session creation here, rather than in PID 1, is
deliberate:
* It's the last point where we can be sure all other processes have
already been killed, so nothing else can race us into creating (or
worse, hijacking) the "systemd" session, as /dev/liveupdate is a
singleton and a session name is global.
* Any kernel-visible side effects of preserving objects (memory
pinning etc.) are delayed until the absolute last moment, minimizing
the window in which they could affect the running system
No behaviour change for shutdown paths other than kexec, or for kexec
when systemd didn't hand over a serialization fd (e.g. because no
service had any fds stored, or because LUO wasn't supported at
serialization time).
It'd be nice if we could not repeat the information about the option
list a second time. But I don't see a nice way to do this, since
(by design) with the macro approach, the macros must be intertwined
with the parse_argv() code. But that code in turn refers to a bunch
of variables, so lifting out the function is not immediately possible.
So I think it's best to keep the existing approach where we provide
a list of options, without additional context, and skip them using
a custom routine.
I am really not a fan of full code lines passed to macros as parameters.
Let's get rid of the 3rd parameter of FOREACH_OPTION() hence:
1. Let's return errors just as a regular value (though a negative one),
that can be handled via a OPTION_ERROR case statement for the switch.
This normalizes handling of the error, just like any other event
returned by the option parser.
2. In order to avoid exploding the amount of boilerplate in each use
(that just propagates the error on OPTION_ERROR), let's then
introduce an explicit FOREACH_OPTION_OR_RETURN(), that returns from
the calling function on its own (and makes that clear in the name).
Together this cleans up, normalizes the logic and shortens the code.
It was requested to make the 'c', 'opt', and 'arg' params the same, i.e.
defined through the FOREACH_OPTION macro. But we can't do that easily,
because 'c' was defined in the for loop definition, and we can only
define variables of the same type in that way. Also, in some cases we
need only 'c', in other cases with need 'c' and 'arg, in some cases 'c'
and 'opt', and in other cases all three. We'd need to either
conditionalize or mark those variables with _unused_ to deal with
compiler warnings. But a different approach works quite nicely: add
state.opt and state.arg to show the current option and it's argument.
(The short names are picked on purpose to reduce verbosity since those
are used a lot.)
Every dlopen_xxx() helper now takes an int log_level argument. It is
passed through to dlopen_many_sym_or_warn() (which in turn propagates it
to dlopen_verbose() for the library-not-installed case), and is used by
the fallback stub when support for the library is not compiled in to
emit a "<lib> support is not compiled in." message at the caller's level.
Callers pass LOG_DEBUG when gracefully degrading, or a higher level when
the failure should surface, and no longer need to log redundantly at the
call site.
As part of this, dlopen_bpf_full() (which already took a log_level) is
merged into dlopen_bpf() rather than keeping both.
The static inline fallbacks used to live in the headers, which required
pulling log.h in from every header that declared a dlopen_xxx(). Move
them into the .c files instead: the declaration is always outside the
#if HAVE_XXX block, the impl sits outside the outer #if HAVE_XXX wrap
with its own internal #if HAVE_XXX/#else/#endif, and apparmor-util.c,
idn-util.c, libmount-util.c and pam-util.c are now always compiled so
they can host their stubs.
We have this rule in systemd that unless we are sure that getenv() is
safe and there's a reason to use it we should always prefer
secure_getenv(). Follow our own rules here, as per CODING_STYLE
document.
This really doesn't matter here, all of this is highly privileged, but
hopefully Claude & Colleagues shut up about this then, and maybe detect
the pattern better.
'kexec -e' is just a small wrapper that does the xen hypercall
on xen, or otherwise just calls reboot(). Drop the dependency,
and reuse the existing xen hypercall helper.
Calling mlockall in an unprivileged process most notably had the effect
of making systemd-cryptenroll OOM while trying to open a normal-sized
argon2 keyslot due to it hitting RLIMIT_MEMLOCK.
When employing MCL_FUTURE we don't actually want it to impose
immediate population of malloc()-ed pages. Hence let's set
MCL_ONFAULT everywhere.
Additionally, specify MCL_CURRENT to ensure future memory allocations
on already mapped pages are covered too. (Addresses
https://github.com/systemd/systemd/pull/40319#discussion_r2693726196)
Note that in shutdown the mlockall() is done to avoid keeping swap space
busy, hence a dedicated call w/ MCL_CURRENT and w/o MCL_ONFAULT is made.
We drop the optimization for verify_sigchld as the
check differs based on the options passed and the
extra syscalls are certainly not going to matter
compared to the cost of forking a child process.
Fixes#40166
So far we compiled the normal and standalone versions completely
independently. Let's use the 'extract' template pattern to avoid any
additional compilation and only require an single link to produce the
.standalone variants.
Unfortunately, as designed, the 'extract' framework only allows one set of
object files to be extracted. Since we need all the files for the
.standalone version, we cannot use 'extract' for other purposes. Thus, in
the two cases where 'extract' was used for the test binaries, this is now
changed to compile the files a second time. But the number of files in that
list is small, so this seems like a better option.
(If we weren't using the template system, we could easily extract just the
objects we need. But with the current system, at the point of the
definition, the binaries are not defined yet. We'd need to handle all of
this through sets of dictionaries, and that just seems like too much
trouble to avoid double compilation of a few small files.)
If we ever want to add it back, it should be with -DSTANDALONE=0|1, so
that #if instead of #ifdef can be used. We generally converted our internal
defines to that form.
Currently, if the libmount feature is disabled, we don't build
libshared and as a result skip building every other executable as
well. Among other things, this makes our nodeps CI builds kind of
pointless since hardly any code will be compiled.
Let's improve on the situation by making libmount properly optional
in libshared. Then, we only skip building the executables that
actually need libmount.
In all cases, everything that we list in 'extract', we also list in
'sources'. We can simplify things by automatically appending the first
list to the second.
In the listings, move 'extract' key right below 'sources', since now
they are both "sources", just with slightly different meanings.
Let's not leak details from src/shared and src/libsystemd into
src/basic, even though you can't actually do anything useful with
just forward declarations from src/shared.
The sd-forward.h header is put in src/libsystemd/sd-common as we
don't have a directory for shared internal headers for libsystemd
yet.
Let's also rename forward.h to basic-forward.h to keep things
self-explanatory.
Function execute_directories logged in a way that was meaningless
without additional context:
systemd[1]: No executables found.
In execute_strv this was partially rectified by extracting the directory
name from one of the directories and using this as the identifier. But
the directory name is not always meaningful, and can also be set from
an environment variable. Let's simplify things by providing a fixed name
that can be used consistently in all log messages. In particular this will
make error messages easier to understand if users report just the error
without additional context.
Then, move syscall definitions to the wrapper, and prototypes are moved
to relevant headers.
This also adds checks for add_key() and request_key(), as one day
glibc may be going to add some of them separatedly.
The check for fspick in meson.build is dropped, as it is currently
unused in our code.
This also moves
- basic/missing_bpf.h -> include/override/linux/bpf.h,
- basic/missing_keyctl.h -> include/override/linux/keyctl.h.
git grep -l 'Failed to open /'|xargs sed -r -i 's|"Failed to open (/[^ ]+): %m"|"Failed to open %s: %m", "\1"|g'
git grep -l $'Failed to open \'/'|xargs sed -r -i $'s|"Failed to open \'(/[^ ]+)\': %m"|"Failed to open %s: %m", "\\1"|g'
git grep -l "Failed to open /"|xargs sed -r -i $'s|"Failed to open (/[^ ]+), ignoring: %m"|"Failed to open %s, ignoring: %m", "\\1"|g'
+ some manual fixups.
These are built from the same sources as the regular binaries, so we
end up with the same sources multiple times in the compilation database
but with different command line arguments, which trips up tooling that
uses the compilation database. Let's not define the standalone targets if
the option is not enabled to avoid this problem.
Also, let's deflatten the lists of sources in preparation for the
next commit at the same time.
In systemctl, we split out systemctl-main.c to make sure the definition
of main() is in a separate object which allows us to extract the systemctl.c
object and link it in the fuzzer target without getting a multiple definition
error when linking.
Currently, when we want to add unit tests for code that is compiled into
an executable, we either compile the code at least twice (once for the
executable, and once for each test that uses it) or we create a static
library which is then used by both the executable and all the tests.
Both of these options are not ideal, compiling source files more than
once slows down the build for no reason and creating the intermediate
static libraries takes a lot of boilerplate.
Instead, let's use the extract_objects() method that meson exposes on
build targets. This allows us to extract the objects corresponding to
specific source files and use them in other executables. Because we
define all executables upfront into a dictionary, we integrate this into
the dictionary approach by adding two new fields:
- 'extract' takes a list of files for which objects should be extracted.
The extracted objects are stored in a dict keyed by the executable name
from which they were extracted.
- 'objects' takes the name of an executable from which the extracted
objects should be added to the current executable.
One side effect of this approach is that we can't build test executables
anymore without building the main executable, so we stop building test
executables unless we're also building the main executable. This allows
us to switch to using subdir_done() in all of these subdirectories to skip
parsing them if the corresponding component is disabled.
These changes get me down from 2439 => 2403 ninja targets on a full rebuild
from scratch.
Now that the necessary functions from log.h have been moved to macro.h,
we can stop including log.h in macro.h. This requires modifying source
files all over the tree to include log.h instead.
Let's gracefully handle cases where a device disappears in the time we
between our discovery and when we want to detach it, due to "auto-clear"
or a similar logic.
The loopback case already handled this quite OK, do the same for MD and
swap too.
Switch to ERRNO_IS_DEVICE_ABSENT() for all checks, just in case.
Also improve debug logging for all these cases, so we know exactly what
is going on.
This is inspired by #37160, but shouldn't really fix anything there, I
am pretty sure the ENODEV seen in that output stems from the STOP_ARRAY
call, not from the open().
Note that this does not change anything for the device mapper case,
because the DM subsystem does not return useful error codes to
userspace, hence everything is a complete mess there.
This introduce LOG_ITEM() macro that checks arbitrary formats in
log_struct().
Then, drop _printf_ attribute from log_struct_internal(), as it does not
help so much, and compiler checked only the first format string.
Hopefully, this silences false-positive warnings by Coverity.
If a network mount returns EBUSY on umount, the logic introduced in
6dc68a00cf causes shutdown to hang indefinitely on
`fstatat()` (i.e., within `is_dir(m->path, true)`). Hence, skip this logic for
network mounts (following the same motivation we use to skip read-only mounts in
this kind of file systems).
Fixes 6dc68a00cf