]> git.ipfire.org Git - thirdparty/systemd.git/log
thirdparty/systemd.git
8 days agobootctl: remove fallback EFI Boot#### variable on uninstall 41650/head
Clayton Craft [Thu, 30 Apr 2026 03:32:19 +0000 (20:32 -0700)] 
bootctl: remove fallback EFI Boot#### variable on uninstall

This cleans up the fallback Boot#### entry that was registered on
install. The logic cleaning up variables was moved from verb_remove into
a new remove_variables function, which mirrors the install side.

8 days agobootctl: register fallback EFI Boot#### entry on install
Clayton Craft [Thu, 30 Apr 2026 01:46:13 +0000 (18:46 -0700)] 
bootctl: register fallback EFI Boot#### entry on install

This adds a second install_boot_option call to register a Boot#### entry
pointing at systemd-boot-fallback{arch}.efi, and place it immediately
after the primary entry in BootOrder.

The fallback file does not exist on the ESP on first install and is
only created on first update when the existing primary binary is
rotated to the fallback path. We register the variable anyway, so
that the entry exists in the BootOrder once the fallback file shows up.
Until then, firmware that reaches the fallback entry will fail to
load it and fall through to the next entry in BootOrder, which is
fine. install_boot_option gains a require_existing parameter so the
existing early return on a missing ESP path can be skipped for the
fallback, where a missing path is expected.

This also does a bit of refactoring by splitting the bottom part of
run_install() into a new install_variables() function that handles
registering both the primary and fallback entries.

8 days agobootctl: back up sd-boot binary to fallback path on update
Clayton Craft [Thu, 30 Apr 2026 01:24:21 +0000 (18:24 -0700)] 
bootctl: back up sd-boot binary to fallback path on update

When a primary sd-boot binary already exists on the ESP and is being
updated, it is copied to systemd-boot-fallback{arch}.efi before installing
the new version. This gives firmware a fallback Boot#### entry pointing
to the previous binary in case the new one fails to load.

The fallback is preserved (not overwritten) when its product and version
match the currently booted bootloader (read from the LoaderInfo EFI
variable), since that means it already holds the known good binary that
booted this session. In all other cases it is overwritten with the current
primary, when no fallback exists yet, when LoaderInfo is unavailable, or
when the fallback's product or version differs from what booted.

This also moves the version_check() call up so its result determines
both the rotation decision and the main copy, and avoids a duplicate
check (and duplicate "Skipping..." log) when the binary is already
current.

8 days agobootctl: add after_slot parameter to insert_into_order()
Clayton Craft [Thu, 30 Apr 2026 00:35:05 +0000 (17:35 -0700)] 
bootctl: add after_slot parameter to insert_into_order()

This adds an after_slot parameter that, when not set to UINT16_MAX,
requests that the new slot be placed immediately after the given slot in
BootOrder. When after_slot is set and the new slot already exists in
BootOrder, it will leave its position alone. This is so that if a user
reorders it, we don't stomp on their changes.

8 days agobootctl: add description and ret_slot parameters to install_boot_option()
Clayton Craft [Thu, 30 Apr 2026 00:10:05 +0000 (17:10 -0700)] 
bootctl: add description and ret_slot parameters to install_boot_option()

This moves creation of the EFI boot option description out of
install_boot_option and into the caller, and adds a ret_slot output
parameter for capturing the assigned BootOrder slot. This allows reusing
the function for installing variables with different descriptions.

8 days agobootctl: rename install_variables/remove_variables to install/remove_boot_option
Clayton Craft [Tue, 12 May 2026 17:47:17 +0000 (10:47 -0700)] 
bootctl: rename install_variables/remove_variables to install/remove_boot_option

These functions install or remove a single EFI Boot#### entry, not
"all variables," so this renames them to better reflect what they do.

8 days agobootctl: fix removing variables on uninstall
Clayton Craft [Thu, 30 Apr 2026 02:33:58 +0000 (19:33 -0700)] 
bootctl: fix removing variables on uninstall

remove_variables looks up the EFI boot entry by matching both the path
and the partition UUID and it wasn't actually removing any entries
because verb_remove was passing SD_ID128_NULL, so the lookup never
matched and Boot#### entries were left behind on uninstall.

Fixes 38433a6

8 days agosystemctl: also attempt kexec image extraction on EINVAL
Rocker Zhang [Thu, 21 May 2026 15:47:48 +0000 (23:47 +0800)] 
systemctl: also attempt kexec image extraction on EINVAL

load_kexec_kernel() retries kexec_file_load() with an extracted kernel
(decompressed Image / ZBOOT PE / UKI) when the kernel rejects the image,
but it only does so when kexec_file_load() failed with ENOEXEC. On arm64
that retry never happens: arm64's image_probe()
(arch/arm64/kernel/kexec_image.c) returns -EINVAL on an ARM64_IMAGE_MAGIC
mismatch, whereas x86's bzImage64_probe() and the generic
kexec_image_probe_default() return -ENOEXEC. So `systemctl kexec` of a
UKI on arm64 skips the extraction path and falls back to the
/usr/sbin/kexec binary, which is no longer a dependency since e107c7ead0
("systemctl: replace kexec-tools dependency with direct kexec_file_load()
syscall") -- leaving kexec broken.

Accept EINVAL in addition to ENOEXEC. This is safe: the extraction in
kexec_maybe_decompress_kernel() re-gates on the actual file magic (MZ /
compression headers) and is a no-op returning 0 for anything else, so an
EINVAL that is not a format mismatch just falls through to the existing
fallback as before.

Fixing this in systemd (rather than only in the kernel) is appropriate:
systemd must keep working with already-shipped arm64 kernels whose
kexec_file_load() returns EINVAL for an unrecognized image magic.

Relates to: https://github.com/systemd/systemd/issues/28538

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
8 days agotpm2: add nvpcr allocation priorities (#42227)
Lennart Poettering [Thu, 21 May 2026 16:19:39 +0000 (18:19 +0200)] 
tpm2: add nvpcr allocation priorities (#42227)

nvindex space is very scarce, let's hence introduce "priorities" on
nvpcrs, so that if we haven't got enough space for all we have some
control which ones get dropped and which ones kept.

8 days agocore: introduce ConditionFraction= that is true on a certain percantage of the fleet
Lennart Poettering [Thu, 21 May 2026 13:32:24 +0000 (15:32 +0200)] 
core: introduce ConditionFraction= that is true on a certain percantage of the fleet

8 days agoTEST-08-INITRD: Set up exitrd on boot rather than including in image
Daan De Meyer [Thu, 21 May 2026 10:25:03 +0000 (10:25 +0000)] 
TEST-08-INITRD: Set up exitrd on boot rather than including in image

Just copy the initramfs from the VM rather than doing it during
the image build.

8 days agoTranslations update from Fedora Weblate (#42231)
Luca Boccassi [Thu, 21 May 2026 15:16:33 +0000 (16:16 +0100)] 
Translations update from Fedora Weblate (#42231)

Translations update from [Fedora
Weblate](https://translate.fedoraproject.org) for
[systemd/main](https://translate.fedoraproject.org/projects/systemd/main/).

Current translation status:

![Weblate translation
status](https://translate.fedoraproject.org/widget/systemd/main/horizontal-auto.svg)

8 days agopo: Translated using Weblate (Arabic) 42231/head
joo es [Thu, 21 May 2026 15:01:53 +0000 (15:01 +0000)] 
po: Translated using Weblate (Arabic)

Currently translated at 100.0% (270 of 270 strings)

Co-authored-by: joo es <jonnyse@users.noreply.translate.fedoraproject.org>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/ar/
Translation: systemd/main

8 days agopo: Translated using Weblate (Korean)
김인수 [Thu, 21 May 2026 15:01:50 +0000 (15:01 +0000)] 
po: Translated using Weblate (Korean)

Currently translated at 100.0% (270 of 270 strings)

Co-authored-by: 김인수 <simmon@nplob.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/ko/
Translation: systemd/main

8 days agoUpdate NEWS
Luca Boccassi [Thu, 21 May 2026 15:05:52 +0000 (16:05 +0100)] 
Update NEWS

8 days agotest: cover lingering users surviving a soft-reboot in TEST-82
Rocker Zhang [Thu, 21 May 2026 10:29:24 +0000 (18:29 +0800)] 
test: cover lingering users surviving a soft-reboot in TEST-82

Regression coverage for the soft-reboot linger bug fixed in
9f25feb4ed18 ("logind: keep lingering users at startup-time GC", #41789):
a lingering user's user@.service was started after a hardware reboot but
not after `systemctl soft-reboot`, because logind GC'd the user at
startup before user_start() ran.

On the first boot, enable lingering for the pre-existing testuser and
wait for its user@UID.service to come up. After the first soft-reboot
(which keeps the same persistent rootfs), assert the service is active
again — this is the regression check. Disable lingering again before the
nextroot switch in the second boot so the lingering user doesn't leak
into the later boots' minimal overlay rootfs.

Verified locally in a qemu/KVM VM: passes with the fix present, and with
the fix reverted the second-boot assertion times out (the lingering user
is GC'd in logind startup and user@UID.service never comes back),
confirming the test exercises the bug.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
8 days agoci: add a CI test for nvpcr priorization 42227/head
Lennart Poettering [Thu, 21 May 2026 12:22:29 +0000 (14:22 +0200)] 
ci: add a CI test for nvpcr priorization

8 days agodocs: document the .nvpcr file format superficially
Lennart Poettering [Thu, 21 May 2026 12:22:03 +0000 (14:22 +0200)] 
docs: document the .nvpcr file format superficially

8 days agotpm2-util: be more graceful with nvindex space exhaustion issues
Lennart Poettering [Thu, 21 May 2026 12:21:28 +0000 (14:21 +0200)] 
tpm2-util: be more graceful with nvindex space exhaustion issues

Let's tone down the language, and say how many we skipped.

8 days agosd-dhcp-relay: reimplement DHCP relay agent and drop legacy DHCP relay mode from...
Daan De Meyer [Thu, 21 May 2026 14:23:44 +0000 (16:23 +0200)] 
sd-dhcp-relay: reimplement DHCP relay agent and drop legacy DHCP relay mode from sd-dhcp-server (#42130)

8 days agoIntroduce support for running code in fibers (#39771)
Daan De Meyer [Thu, 21 May 2026 14:21:13 +0000 (16:21 +0200)] 
Introduce support for running code in fibers (#39771)

Traditionally, asynchronous programming in systemd has been achieved
using
sd-event along with the asynchronous interfaces of sd-bus and
sd-varlink.
This works well when the system is reacting to events and all code
triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback
can
use the stack as usual, declaring local state and ensuring proper
cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block
execution
within the callback, we can't directly invoke a long-running operation
and
wait for its result without introducing complexities. Instead, we need
to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along
as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope
may
be prematurely cleaned up. Therefore, the struct must store copies of
the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a
loop,
the complexity grows further. We must introduce additional shared state
to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must
track
the lifecycle of each long-running operation in the global Manager
struct,
ensuring proper cleanup even when stack unwinding can no longer manage
the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s
running
synchronously, but with the ability to yield control at predefined
points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while
waiting
for the long-running operation to finish and then "resume" the operation
once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in
a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve
the
handling of complex workflows, making the code easier to write and
maintain.

The implementation is based on ucontext.h's makecontext() (with a
fallback
to the venerable sigaltstack() approach on musl),
sigsetjmp()/siglongjmp()
and sd-event. ucontext.h provides us with alternate stacks that we can
switch
between. We use sigsetjmp()/siglongjmp() instead of swapcontext()
because the
latter forcibly saves/restores a per context signal mask every time it
is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and
maintain
a per thread signal mask, which makes much more sense than having a per
fiber
signal mask.

The default stack size is the same as a regular thread. Because we
use mmap() to allocate the stack, the memory won't actually be used
until it
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a
deferred
event source which resumes the fiber when enabled. The deferred event
source
is oneshot by default so the fiber will run immediately until it yields
or
suspends. If it yields, the deferred event source is enabled again
(oneshot)
immediately. If it suspends, before it suspends, one or more event
sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for
completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or
any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is
cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the
fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup
to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them
behind
a generic futures interface to represent long-running operations,
regardless of
whether those operations are running on a fiber or not. Aside from
fibers, the
futures library (sd-future) will for example allow waiting for sd-event
sources
and doing sd-bus calls in the background as well. Fibers can suspend
until a
future is ready with sd_fiber_await() or by having the future wake up
the fiber
explicitly in its callback. A future always defaults to waking up the
current
fiber.

Each future kind plugs into the library by providing an sd_future_ops
vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it
via
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to
that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from
a
fiber via sd_fiber_await() (synchronous-looking fiber code).
sd_fiber_await()
is itself built on a "wait future" that resolves when its target
resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber
callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future
impl's
cancel callback, which is responsible for tearing down its work and
ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from
sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new()

take a self-reference on their future so they outlive the caller's
scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds
would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal
sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an
unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the
following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of
it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.

8 days agonvpcr: define some reasonable priorities for the nvpcrs we already defined
Lennart Poettering [Thu, 21 May 2026 12:21:02 +0000 (14:21 +0200)] 
nvpcr: define some reasonable priorities for the nvpcrs we already defined

8 days agoanalyze: show priority in 'nvpcrs' output
Lennart Poettering [Thu, 21 May 2026 12:20:37 +0000 (14:20 +0200)] 
analyze: show priority in 'nvpcrs' output

8 days agotpm2-setup: introduce a 'priority' concept for NvPCRs
Lennart Poettering [Thu, 21 May 2026 12:19:42 +0000 (14:19 +0200)] 
tpm2-setup: introduce a 'priority' concept for NvPCRs

8 days agoupdatectl: Apply --no-ask-password argument to polkit agent
Philip Withnall [Thu, 21 May 2026 10:40:19 +0000 (11:40 +0100)] 
updatectl: Apply --no-ask-password argument to polkit agent

Accidentally missed out of commit
8c0f9073c7da808461acfc016cc291e4aba9c1a2.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: 8c0f9073c7da808461acfc016cc291e4aba9c1a2
8 days agoinclude/uapi: add linux/openat2.h (#42220)
Zbigniew Jędrzejewski-Szmek [Thu, 21 May 2026 11:29:28 +0000 (13:29 +0200)] 
include/uapi: add linux/openat2.h (#42220)

We include the header through src/include/override/fcntl.h, hence we should
have the latest copy of the header.

(E.g. compilation fails with musl-libc-1.2.5-6.fc44.x86_64 and older kernel
headers.)

8 days agocore: add FileDescriptorStorePreserve=on-success option (#42160)
Luca Boccassi [Thu, 21 May 2026 11:08:33 +0000 (12:08 +0100)] 
core: add FileDescriptorStorePreserve=on-success option (#42160)

Currently with FileDescriptorStorePreserve=yes the FD store is kept
around
regardless of what happens to a unit, which is useful in many cases. But
in
some cases, for example when complex services crash horribly, it's hard
to
reason about what was in the intermediate state, and it's better to
start
fresh.

Add a new 'on-success' option for the FileDescriptorStorePreserve=
setting
that keeps it around only for as long as the unit doesn't go to a
persistently
failed state.

This is especially useful in combination with LUO, where we don't want
to
keep around LUO sessions created by units that then proceeded to crash
and
burn, and might be in a bad state afterwards.

8 days agotest-btrfs: skip info test when GET_SUBVOL_INFO ioctl is unsupported
Daan De Meyer [Wed, 20 May 2026 20:46:40 +0000 (20:46 +0000)] 
test-btrfs: skip info test when GET_SUBVOL_INFO ioctl is unsupported

On 32-bit userspace running against a 64-bit kernel
BTRFS_IOC_GET_SUBVOL_INFO returns -ENOTTY: struct
btrfs_ioctl_get_subvol_info_args embeds four btrfs_ioctl_timespec
values, and that timespec struct (__u64 sec; __u32 nsec) packs to 12
bytes on i386 but 16 on x86_64 due to differing __u64 alignment.
sizeof(struct) is part of the ioctl cmd number via _IOR(), so the cmd
emitted by 32-bit userspace doesn't match the case label compiled by
the 64-bit kernel and the switch falls through to -ENOTTY.

btrfs already handles this exact class of bug for
BTRFS_IOC_SET_RECEIVED_SUBVOL via a btrfs_ioctl_timespec_32 struct
plus a _32 cmd alias in fs/btrfs/ioctl.c, but GET_SUBVOL_INFO (added
in 2018, four years after that fix) didn't get the same treatment.
Until a kernel patch lands the test can't exercise the ioctl on
32-bit, so convert TEST(info) to TEST_RET(info) and return
EXIT_TEST_SKIP with a clear message when -ENOTTY comes back. The
other tests in the file use ioctls that already have working compat
paths and remain unaffected.

8 days agonetwork: several fixlets for NDisc (#42218)
Luca Boccassi [Thu, 21 May 2026 11:05:34 +0000 (12:05 +0100)] 
network: several fixlets for NDisc (#42218)

Unfortunately, previously the path to test-ndisc-send has been wrong, so
some test cases have not been checked in our mkosi CIs. And two test
cases have been broken.

The test case `test_ndisc_redirect` was not updated when the logic in
networkd was changed by 9142bd5a8e9ed94ecbb1e335305e24760b90ad2a. The
change itself should be OK. So, the test case is updated.

The test case `test_ndisc_mtu` was broken when the commit
32417c172383847ec78b672c537594e3efe8f0e0 is merged. The commit is not
correct, as we cannot set IPv6 MTU larger than interface MTU. So, the
offending commit is reverted.

8 days agocore: better errors and more fields for io.systemd.Unit.StartTransient (#42161)
Daan De Meyer [Thu, 21 May 2026 11:03:29 +0000 (13:03 +0200)] 
core: better errors and more fields for io.systemd.Unit.StartTransient (#42161)

core: add User,Group,SupplementaryGroups,Nice to varlink
 Unit.StartTransient

This commit adds more writable fields to the
io.systemd.Unit.StartTransient
varlink method. With this its possible to set:
User,Group,SupplementaryGroups,Nice values.

Plus tests for them.

---

core: report unsupported service fields in varlink calls

Just like for the unsupported/bad exec_fields we should show
a message about what field is bad for service parameters. This
commit adds it using the same pattern. The JSON parser works in
fail-fast mode so we only display the first bad field (and
it depends on the parser what it finds first).

8 days agomath-util: round to declared FP precision consistently across architectures
Daan De Meyer [Wed, 20 May 2026 12:37:15 +0000 (12:37 +0000)] 
math-util: round to declared FP precision consistently across architectures

Add -fexcess-precision=standard so gcc inserts ISO C99 conformant
rounding at assignments, casts, and returns — without it, double values
on x87 happily stay at 80-bit extended precision across operations and
diverge from the SSE/x86_64 behavior, making strict equality comparisons
architecture-dependent.

The flag doesn't fully cover x87: per gcc PR#323
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323), a function return
value carried in ST(0) can arrive at the caller still at 80-bit, so a
double that ought to compare equal to a same-magnitude literal picks up
extra mantissa bits and doesn't. Wrap fp_equal in volatile-double
temporaries to force a memory roundtrip — the only operation that
reliably truncates on x87 — so its callers get consistent results
regardless of how the operands were produced.

Add a TEST(fp_equal) case that exercises the previously-broken pattern:
a runtime 1.0/10.0 computed inside a noinline helper, returned across
the function ABI boundary, then compared against the literal 0.1.
Without the volatile truncation this assertion fails on 32-bit gcc.

8 days agotest-qmp-client: run mock QMP servers as fibers on the shared event loop 39771/head
Daan De Meyer [Fri, 24 Apr 2026 09:49:10 +0000 (09:49 +0000)] 
test-qmp-client: run mock QMP servers as fibers on the shared event loop

The mock servers used to be driven out-of-band: each test created a
socketpair, forked a child, ran a hand-coded request/response script
against the raw fd, and sent SIGTERM to tear it down. That worked but
required pidref/process-util/signal plumbing in every test, two
distinct execution contexts that couldn't share state, and a JsonStream
attached to the mock side that pretended to be event-loop-driven while
actually being driven manually via blocking reads.

Now that JsonStream suspends when on a fiber, the mocks can live
inside the same process and event loop as the client. Each mock is
rewritten as an sd-fiber that runs alongside the client fiber: so the
mock fiber yields on I/O and the event loop schedules the client in the
meantime. Both sides progress cooperatively, no fork/SIGTERM/PID tracking,
no manual phase tracking.

Two cleanups fall out of the rewrite:

- A QMP_TEST(name, mock_fn) { ... } macro encapsulates the per-test
  scaffolding (event loop, socketpair, mock fiber spawn, exit-on-idle
  shim) and injects an already-connected QmpClient *client into the
  test body. Each test now reads as a flat sequence of
  qmp_client_call() invocations against that client.

- Repeated mock command/reply scripting is factored into
  mock_qmp_expect(), mock_qmp_reply(), mock_qmp_expect_and_reply(),
  mock_qmp_handshake(), and mock_qmp_query_status_running(). The
  greeting JSON is built with sd_json_buildo() instead of being parsed
  from a literal.

The file shrinks from 756 to 494 lines, mostly through deletions.

8 days agoqmp-client: add fiber-aware call paths
Daan De Meyer [Fri, 24 Apr 2026 09:49:02 +0000 (09:49 +0000)] 
qmp-client: add fiber-aware call paths

The synchronous qmp_client_call() pumps the event loop until its reply
arrives, pinning the parsed reply on c->current so it can hand out
borrowed pointers to the caller. That model only fits one in-flight
sync call: a second qmp_client_call() on the same client clears
c->current before issuing its own send, invalidating the first
caller's borrowed pointers. On a single-threaded event loop that was
fine, but with fibers two concurrent calls on the same client can
interleave through the pump (json_stream_wait() suspends the running
fiber) and trample each other.

To fix this, make qmp_client_call() detect when it's running on a fiber
whose event loop matches the client and transparently delegate to
qmp_client_call_suspend(), which makes use of a new QmpFuture to allow
multiple concurrent calls to qmp_client_call().

To make this work concurrently, we also change qmp_client_call() to
hand out references and copies of errors so that we don't have to store
the borrowed pointers we hand out in the QmpClient struct.

8 days agosd-varlink: make sd-varlink fiber-aware
Daan De Meyer [Tue, 14 Apr 2026 08:54:49 +0000 (08:54 +0000)] 
sd-varlink: make sd-varlink fiber-aware

Add varlink_server_bind_fiber() and varlink_server_bind_fiber_many()
in varlink-util.{c,h} for registering a method handler that should
run on a dedicated fiber per dispatch. The fiber-bound methods live
in a separate s->fiber_methods map alongside the regular s->methods;
bind_internal()/bind_many_internal() are factored out so the regular
and fiber bind variants share their parsing/insertion code.
Registering the same method in both maps is rejected because the
dispatcher consults the regular map first and would otherwise
silently shadow the fiber binding.

varlink_dispatch_fiber() builds a VarlinkFiberData (refs to the
connection, parameters, and method name), spawns a fiber via
sd_fiber_new(), and makes the future floating so the fiber
self-manages its lifetime — neither the dispatcher nor the
connection has to track it. The fiber's priority is set to one
below the connection's quit event source so that on graceful
shutdown the fiber's exit handler fires (and runs its cleanup)
before varlink's quit_callback() closes the connection underneath
it; this is what lets a fiber-bound handler reply or flush its
sentinel on a still-open connection during shutdown.

The connection state transitions are reordered so they happen before
the fiber spawn rather than after the synchronous callback returns:
the fiber runs after dispatch has already moved past PROCESSING, which
matches the behaviour expected for a deferred reply (the fiber may
either reply immediately, or stash the connection and reply later, in
which case the post-callback logic treats it as a PENDING_METHOD).

Note that all the synchronous varlink APIs (sd_varlink_call() and friends)
already behave properly when on a fiber because they call json_stream_wait()
which calls ppoll_usec() which we already fixed to suspend when called from
a fiber.

The client/server varlink tests are migrated to fibers (threads → mock
server fibers on the same event loop) to exercise the new paths.

8 days agosd-bus: make sd-bus fiber-aware
Daan De Meyer [Mon, 11 May 2026 14:27:34 +0000 (16:27 +0200)] 
sd-bus: make sd-bus fiber-aware

Two changes to teach sd-bus how to behave when called from a fiber, in
order of increasing depth:

2. sd_bus_call() now redirects to a new bus_call_suspend() helper when
   the caller is a fiber whose event loop is the same one the bus is
   attached to. The plain bus_poll() path serializes all bus traffic on
   the slot's reply (only one method call can be in flight per
   sd_bus*), which would defeat the point of running multiple fibers
   against one bus. bus_call_suspend() builds on the async sd-bus API:
   it wraps the call in a new BusFuture (sd-bus/bus-future.{c,h}) that
   resolves when the reply or method-error arrives, lets the fiber
   await that future, and surfaces the reply to the caller via
   future_get_bus_reply(). Because the futures live on the event loop
   rather than a per-bus slot, multiple fibers can drive concurrent
   method calls against the same bus.

3. A new private SD_BUS_VTABLE_METHOD_FIBER flag dispatches a vtable
   method handler on its own fiber, so handlers are free to use
   sd_bus_call() against the same bus, sd_fiber_sleep(), loop_read(),
   etc. without stalling the event loop for other connections or
   handlers. The flag stays out of sd-bus-vtable.h (its bit value is
   reserved there to prevent collisions) — the fiber runtime is a
   systemd-internal implementation detail.

Lifecycle of fiber-dispatched handlers is tracked on the bus itself: a
new bus->fiber_futures set holds a ref to each in-flight handler.
bus_enter_closing() cancels every entry and process_closing() returns
with the bus still in CLOSING state until the set drains, so we can be
sure no fiber handler outlives the bus. bus_fiber_resolved() removes
the entry on completion. bus_free()'s assert(set_isempty()) makes the
invariant load-bearing.

Note that plain sd_bus_call() already works correctly on a fiber as it
calls ppoll_usec() which has already been modified to suspend when
running on a fiber.

To exercise these changes the existing thread-based client/server
sd-bus tests (test-bus-chat, test-bus-objects, test-bus-peersockaddr,
test-bus-server, test-bus-watch-bind) are migrated to fibers, and a
new test-bus-fiber is added that covers SD_BUS_VTABLE_METHOD_FIBER —
including handlers that issue nested sd_bus_call() on the same bus, the
cancel-on-close path, and concurrent dispatches across multiple fibers.

8 days agosd-event: suspend instead of blocking when sd_event_run() runs on a fiber
Daan De Meyer [Mon, 23 Mar 2026 09:15:27 +0000 (10:15 +0100)] 
sd-event: suspend instead of blocking when sd_event_run() runs on a fiber

sd_event_run() blocks the calling thread on the event loop's epoll fd
until something happens. When the caller is a fiber, that's the wrong
behaviour: blocking the thread also stalls every other fiber and the
outer event loop driving them. The most common way to hit this is a
fiber that creates its own inner event loop (e.g. a server-style fiber
that wants to dispatch its own sources independently of whatever loop
the test or supervising fiber is running on) — with the existing
implementation the inner sd_event_run() would hold the thread while the
outer scheduler should be free to advance other fibers.

Add an event_run_suspend() variant in sd-event/event-future.c that
performs the same prepare/wait/dispatch dance, but when the fast path
finds nothing ready it (a) creates an IO future watching the inner
event loop's epoll fd on the *outer* event loop, (b) optionally creates
a time future for the timeout, and (c) suspends the fiber. When either
future fires the fiber is resumed and the prepare/wait/dispatch sequence
runs once more to actually dispatch what's pending. sd_event_run()
checks sd_fiber_is_running() and delegates to this variant when on a
fiber; profile_delays accounting is intentionally skipped on that path
since the underlying prepare/wait/dispatch primitives already account
for themselves.

8 days agosd-future: make src/basic blocking helpers fiber-aware
Daan De Meyer [Sat, 25 Apr 2026 20:06:54 +0000 (22:06 +0200)] 
sd-future: make src/basic blocking helpers fiber-aware

Some helpers in src/basic — ppoll_usec_full() (used by fd_wait_for_event()),
loop_read(), loop_read_exact(), loop_write_full() and
pidref_wait_for_terminate_full() — block the calling thread. That's the
right behaviour outside a fiber but not inside one, where blocking the
thread also stalls every other fiber running on the same event loop.
Rewriting every caller to pick a fiber or non-fiber variant explicitly
would be a lot of churn and would split otherwise-shared code paths in
two.

Instead, the helpers detect at runtime whether they're running on a fiber
and dispatch to a suspending variant when they are. FiberOps in
fiber-ops.h holds five function pointers (ppoll, read, write, timeout,
cancel_wait_unref); a fiber_ops global constant is populated whenever we
enter a fiber with functions that delegate to suspending variants of common
syscalls. With this approach, the variants themselves stay in libsystemd
which is required because they make use of sd-event.

- loop_read()/loop_read_exact() take the fiber read hook on a fiber
  unless the caller asked for a non-blocking attempt (do_poll=false) and
  the fd is already non-blocking — in that case we fall through to read()
  to preserve the existing return-EAGAIN-immediately semantic. The hook
  itself suspends on EAGAIN until data is available, so neither the
  do_poll knob nor the explicit fd_wait_for_event() retry loop are
  needed on the fiber path.

- loop_write_full() likewise takes the fiber write hook on a fiber,
  except when timeout=0 with an already-non-blocking fd (preserving the
  fast-return-EAGAIN semantic). The fiber path runs inside a
  FIBER_OPS_TIMEOUT() scope so the caller's timeout is honoured via a
  deadline future, mirroring SD_FIBER_TIMEOUT() but reachable from
  src/basic without pulling in sd-future.h.

- pidref_wait_for_terminate_full() polls the pidfd via fd_wait_for_event()
  before each waitid() when either a finite timeout is set or we're on a
  fiber, and requires pidref->fd >= 0 in those cases (returning
  -ENOMEDIUM otherwise — extending the rule that already applied to
  finite timeouts). The poll suspends the fiber via the ppoll hook above;
  the subsequent waitid() doesn't block because the pidfd is already
  signalled.

8 days agosd-future: add fiber-aware non-blocking I/O wrappers
Daan De Meyer [Sat, 25 Apr 2026 20:31:58 +0000 (22:31 +0200)] 
sd-future: add fiber-aware non-blocking I/O wrappers

Add a family of sd_fiber_*() I/O wrappers that, when called from a
fiber, behave like blocking I/O from the caller's perspective but
yield to the event loop instead of blocking the thread:

  sd_fiber_read / sd_fiber_write
  sd_fiber_readv / sd_fiber_writev
  sd_fiber_recv / sd_fiber_send
  sd_fiber_connect
  sd_fiber_recvmsg / sd_fiber_sendmsg
  sd_fiber_recvfrom / sd_fiber_sendto
  sd_fiber_accept
  sd_fiber_ppoll

Most of them share a single helper, fiber_io_operation(), which when
invoked outside a fiber falls through to the underlying syscall
directly, preserving the regular blocking behaviour. Inside a fiber
the helper flips the fd to non-blocking (restoring its original mode
on return), tries the syscall once on the fast path, and on EAGAIN/
EWOULDBLOCK creates an sd-event-backed IO future via future_new_io(),
suspends the fiber, and retries the syscall once the event source
fires.

future_new_io() itself is added to sd-event/event-future.{c,h} as a
new IoFuture kind. It wraps sd_event_add_io() into an sd_future:
oneshot enable, EPOLLERR translated via SO_ERROR (suppressed for
non-sockets), and the fd duplicated with F_DUPFD_CLOEXEC to avoid
EEXIST when multiple sources watch the same descriptor.

Together these let fiber-using code write straight-line socket and
pipe I/O without bundling state into callbacks.

8 days agoIntroduce support for running code in fibers
Daan De Meyer [Wed, 12 Nov 2025 16:53:47 +0000 (17:53 +0100)] 
Introduce support for running code in fibers

Traditionally, asynchronous programming in systemd has been achieved using
sd-event along with the asynchronous interfaces of sd-bus and sd-varlink.
This works well when the system is reacting to events and all code triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback can
use the stack as usual, declaring local state and ensuring proper cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block execution
within the callback, we can't directly invoke a long-running operation and
wait for its result without introducing complexities. Instead, we need to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope may
be prematurely cleaned up. Therefore, the struct must store copies of the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a loop,
the complexity grows further. We must introduce additional shared state to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must track
the lifecycle of each long-running operation in the global Manager struct,
ensuring proper cleanup even when stack unwinding can no longer manage the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s running
synchronously, but with the ability to yield control at predefined points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while waiting
for the long-running operation to finish and then "resume" the operation once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve the
handling of complex workflows, making the code easier to write and maintain.

The implementation is based on ucontext.h's makecontext() (with a fallback
to the venerable sigaltstack() approach on musl), sigsetjmp()/siglongjmp()
and sd-event. ucontext.h provides us with alternate stacks that we can switch
between. We use sigsetjmp()/siglongjmp() instead of swapcontext() because the
latter forcibly saves/restores a per context signal mask every time it is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and maintain
a per thread signal mask, which makes much more sense than having a per fiber
signal mask.

The default stack size is the same as a regular thread. Because we
use mmap() to allocate the stack, the memory won't actually be used until it
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a deferred
event source which resumes the fiber when enabled. The deferred event source
is oneshot by default so the fiber will run immediately until it yields or
suspends. If it yields, the deferred event source is enabled again (oneshot)
immediately. If it suspends, before it suspends, one or more event sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them behind
a generic futures interface to represent long-running operations, regardless of
whether those operations are running on a fiber or not. Aside from fibers, the
futures library (sd-future) will for example allow waiting for sd-event sources
and doing sd-bus calls in the background as well. Fibers can suspend until a
future is ready with sd_fiber_await() or by having the future wake up the fiber
explicitly in its callback. A future always defaults to waking up the current
fiber.

Each future kind plugs into the library by providing an sd_future_ops vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it via
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from a
fiber via sd_fiber_await() (synchronous-looking fiber code). sd_fiber_await()
is itself built on a "wait future" that resolves when its target resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future impl's
cancel callback, which is responsible for tearing down its work and ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new() —
take a self-reference on their future so they outlive the caller's scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.

8 days agodocs: extend credentials docs with notes about imds
Lennart Poettering [Thu, 21 May 2026 08:11:53 +0000 (10:11 +0200)] 
docs: extend credentials docs with notes about imds

8 days agocore: add FileDescriptorStorePreserve=on-success option 42160/head
Luca Boccassi [Mon, 18 May 2026 14:47:32 +0000 (15:47 +0100)] 
core: add FileDescriptorStorePreserve=on-success option

Currently with FileDescriptorStorePreserve=yes the FD store is kept around
regardless of what happens to a unit, which is useful in many cases. But in
some cases, for example when complex services crash horribly, it's hard to
reason about what was in the intermediate state, and it's better to start
fresh.

Add a new 'on-success' option for the FileDescriptorStorePreserve= setting
that keeps it around only for as long as the unit doesn't go to a persistently
failed state.

This is especially useful in combination with LUO, where we don't want to
keep around LUO sessions created by units that then proceeded to crash and
burn, and might be in a bad state afterwards.

8 days agotest: avoid test-fdstore failing units when exiting
Luca Boccassi [Mon, 18 May 2026 14:49:23 +0000 (15:49 +0100)] 
test: avoid test-fdstore failing units when exiting

This is used as payload, so ensure the wrapping unit/container
doesn't register a failure when this exits

Follow-up for 9de91f0f4c715b278637af8b73cabac892d7e000

8 days agocleanup: VLAN Id -> VLAN ID
Sebastian Bernardt [Sat, 18 Apr 2026 11:31:04 +0000 (21:31 +1000)] 
cleanup: VLAN Id -> VLAN ID

"VLAN ID" is used throughout the documentation and codebase, but appears
(when present) in `networkctl status` tables as `VLan Id`.

8 days agonetwork: restart DHCPv6, NDisc, and RADV when tracked IPv6LL is dropped
Aritra Basu [Tue, 21 Apr 2026 23:09:20 +0000 (19:09 -0400)] 
network: restart DHCPv6, NDisc, and RADV when tracked IPv6LL is dropped

When the tracked IPv6 link-local address is removed, networkd clears
link->ipv6ll_address, but keeps DHCPv6, NDisc, and RADV running. These
engines keep using a stale source identity which affects the following:
- DHCPv6 client continues to send Solicit/Renew/Rebind from a nonexistent
  source address.
- NDisc continues to send Router Solicitations from a nonexistent source
  address. Router Advertisements cannot be received properly.
- RADV continues to advertise with a stale source address. This can lead
  to downstream hosts configuring invalid routes.
- DHCP-PD prefixes remain configured without a valid upstream DHCPv6 path.

Added link_ipv6ll_lost() to stop IPv6 dynamic engines and related states:
- sd_dhcp6_client_stop()
- ndisc_stop() + ndisc_flush()
- sd_radv_stop()

This is called from address_drop() when the dropped address matches the
tracked IPv6LL. After clearing the tracked address, it scans for another
ready link-local address on the interface. If found, this is set as
link->ipv6ll_address and link_ipv6ll_gained() is called to restart the
engines with the new source identity.

This resolves the FIXME in address_drop().

Signed-off-by: Aritra Basu <aritrbas+gh@cisco.com>
8 days agoNEWS: mention new DHCP relay agent 42130/head
Yu Watanabe [Tue, 12 May 2026 06:15:08 +0000 (15:15 +0900)] 
NEWS: mention new DHCP relay agent

8 days agosd-dhcp-server: drop legacy DHCP relay mode
Yu Watanabe [Sun, 3 May 2026 23:43:41 +0000 (08:43 +0900)] 
sd-dhcp-server: drop legacy DHCP relay mode

8 days agonetwork: drop use of legacy DHCP relay agent in sd-dhcp-server
Yu Watanabe [Sun, 3 May 2026 23:29:51 +0000 (08:29 +0900)] 
network: drop use of legacy DHCP relay agent in sd-dhcp-server

Then, this deprecates
- BindToInterface=
- RelayTarget=
- RelayAgentCircuitId=
- RelayAgentRemoteId=
settings in [DHCPServer] section.
These are gracefully translated as new settings.

8 days agoman: document DHCP relay configuration
Yu Watanabe [Sun, 10 May 2026 23:56:40 +0000 (08:56 +0900)] 
man: document DHCP relay configuration

8 days agotest-network: add test case for DHCP relay
Yu Watanabe [Sun, 10 May 2026 22:48:27 +0000 (07:48 +0900)] 
test-network: add test case for DHCP relay

8 days agonetwork: re-implement DHCP relay support with new sd-dhcp-relay
Yu Watanabe [Sun, 3 May 2026 00:56:45 +0000 (09:56 +0900)] 
network: re-implement DHCP relay support with new sd-dhcp-relay

8 days agofuzz: introduce fuzzer for DHCP relay agent
Yu Watanabe [Sat, 2 May 2026 14:32:33 +0000 (23:32 +0900)] 
fuzz: introduce fuzzer for DHCP relay agent

8 days agotest: add unit test for DHCP relay agent
Yu Watanabe [Sat, 2 May 2026 14:18:32 +0000 (23:18 +0900)] 
test: add unit test for DHCP relay agent

8 days agosd-dhcp-relay: introduce new DHCP relay agent
Yu Watanabe [Tue, 28 Apr 2026 04:27:43 +0000 (13:27 +0900)] 
sd-dhcp-relay: introduce new DHCP relay agent

Previously, sd-dhcp-server can be run as a DHCP relay agent.
But, DHCP server and DHCP relay agent behave completely differently,
hence there is almost no code that can be shared between the two modes.
Let's split out the DHCP relay agent feature from sd-dhcp-server.

The new DHCP relay agent supports:
- multiple upstream and downstream interfaces,
- gateway address (giaddr field in DHCP message header) is configurable,
- supports more DHCP relay agent information sub-options,
- each interface has their own socket fd, and each socket is bound to
  the interface, so that we can enable/disable each interface
  safely without affecting other interfaces, and we can filter out any
  unexpected packets from unmanaged interfaces,

networkd integration and test cases will be added later.

8 days agologind: keep lingering users at startup-time GC
Rocker Zhang [Sat, 16 May 2026 05:07:56 +0000 (13:07 +0800)] 
logind: keep lingering users at startup-time GC

manager_startup() runs manager_gc(m, /* drop_not_started= */ false)
before the user_start() loop. user_may_gc()'s linger guard requires
user_unit_active() to be true to keep a user, but at this point the
per-user units have not been started yet, so for any lingering user
that ended up in the user_gc_queue the guard falls through and
manager_gc frees the User struct before user_start() ever runs.

This only manifests after `systemctl soft-reboot`, because /run is
tmpfs and survives soft-reboot: /run/systemd/users/UID files persist,
and manager_enumerate_users() in src/login/logind.c explicitly calls
user_add_to_gc_queue() for every UID it loads from there. Cold boot is
unaffected because /run is empty, so the linger users that come in via
manager_enumerate_linger_users() never enter the GC queue at all and
reach user_start() directly.

Special-case the startup-time GC: if a linger file exists, keep the
user regardless of unit state — user_start() is about to run and will
queue the appropriate jobs. Steady-state GC (drop_not_started=true, in
the event loop) still requires user_unit_active() so we don't hold on
to records for lingering users whose units genuinely died.

Fixes: https://github.com/systemd/systemd/issues/41789
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
8 days agovmspawn: add shell completion for --coco
Paul Meyer [Thu, 21 May 2026 06:07:51 +0000 (08:07 +0200)] 
vmspawn: add shell completion for --coco

Fixes 4f8215add24ac9018fb68399f0b957cf0eb3b0c6.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
8 days agotree-wide: standardize header names across src/fundamental, src/basic and src/shared
Daan De Meyer [Mon, 18 May 2026 20:29:04 +0000 (20:29 +0000)] 
tree-wide: standardize header names across src/fundamental, src/basic and src/shared

Drop the -fundamental suffix from src/fundamental/ headers in favor of names
that match their src/basic/ or src/shared/ counterparts (e.g.
macro-fundamental.h -> macro.h, assert-fundamental.h -> assert-util.h,
cleanup-fundamental.h -> cleanup-util.h). Rename src/basic/{btrfs,label}.{c,h}
to use the -util suffix to match the existing shared/btrfs-util and
shared/label-util siblings. Rename src/shared/mkdir-label.{c,h} to mkdir.{c,h}
and src/shared/tmpfile-util-label.{c,h} to tmpfile-util.{c,h} to match the
corresponding src/basic names.

This saves us from having to come up with separate names for files that do
the same thing across tiers, and it makes it easier to move stuff between
src/fundamental, src/basic and src/shared: consumers just #include "foo.h"
and pick up whichever tier their -I path resolves to first, so call sites
don't need to be updated when an API moves between layers.

Where a higher-tier wrapper exists (e.g. src/basic/macro.h wrapping
src/fundamental/macro.h), the wrapper uses an explicit "../fundamental/foo.h"
or "../basic/foo.h" relative include for the lower-tier header. We can't use
GCC's #include_next directive for this — when the wrapper is reachable both
via same-dir-as-source lookup and via -I (e.g. -Isrc/shared) for the
directory it lives in, #include_next advances by exactly one slot in libcpp's
internal directory chain and lands on the same physical directory it was
already in, never reaching the lower-tier sibling (see make_cpp_dir() in
gcc/libcpp/files.cc:1986).

To make sure the right headers are always picked up, the include directories
are reordered so that e.g. src/shared always takes priority over src/basic and
similar for the other directories.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
8 days agotest-network: follow-up for modem manager test and add test case for networkctl dhcp...
Yu Watanabe [Thu, 21 May 2026 00:10:30 +0000 (09:10 +0900)] 
test-network: follow-up for modem manager test and add test case for networkctl dhcp-lease (#42203)

8 days agofirstboot: make clear where the full screen console wizards end
Lennart Poettering [Wed, 20 May 2026 21:17:11 +0000 (23:17 +0200)] 
firstboot: make clear where the full screen console wizards end

The three first boot screens are visually separated from the console
output before them via the "chome" and welcome strings and sufficient
whitespace. But so far they weren't from the output after them. This is
sometimes a big confusing. Let's add a bit of a separator between the
end and what comes next, too.

Just cosmetics, nothing else.

8 days agovmspawn: rearrange --help and man page a bit (#42200)
Yu Watanabe [Thu, 21 May 2026 00:07:34 +0000 (09:07 +0900)] 
vmspawn: rearrange --help and man page a bit (#42200)

This does not change man page or --help contents at all, but it does
introduce new sections, and moves some knobs between sections. It also
reorders things in the man page so that man page and --help show items
in the same order again.

8 days agoreport: use new --help formatting calls
Lennart Poettering [Wed, 20 May 2026 13:45:30 +0000 (15:45 +0200)] 
report: use new --help formatting calls

8 days agotest-network: fix path to test-ndisc-send 42218/head
Yu Watanabe [Wed, 20 May 2026 14:44:49 +0000 (23:44 +0900)] 
test-network: fix path to test-ndisc-send

Follow-up for 9dcdf16b25545d942b872cc0abdbb7c9a6b5f9f1.

Previously, test cases that use test-ndisc-send executable did not
tested in our mkosi CIs...

8 days agoRevert "network: fix max MTU check for IPv6 MTU adjustments"
Yu Watanabe [Wed, 20 May 2026 22:47:37 +0000 (07:47 +0900)] 
Revert "network: fix max MTU check for IPv6 MTU adjustments"

This reverts commit 32417c172383847ec78b672c537594e3efe8f0e0.

IPv6 MTU cannot be larger than the current interface MTU.
The previous behavior is correct.

8 days agotest-network: fix test case for Neighbor Announcement message handling
Yu Watanabe [Wed, 20 May 2026 22:34:43 +0000 (07:34 +0900)] 
test-network: fix test case for Neighbor Announcement message handling

After 9142bd5a8e9ed94ecbb1e335305e24760b90ad2a, when NA without router
flag is received, the corresponding redirect route and the default route
is removed, but the other routes are kept.

The corresponding test case was not updated by the commit, and the test
case has been unfortunately skipped...

This fixes the test case, and added more checks.

8 days agotest-network: add test cases for 'networkctl dhcp-lease' command 42203/head
Yu Watanabe [Wed, 20 May 2026 15:28:38 +0000 (00:28 +0900)] 
test-network: add test cases for 'networkctl dhcp-lease' command

Addresses the request:
https://github.com/systemd/systemd/pull/42137#pullrequestreview-4305664376

8 days agotest-network: try to stop test-modem-manager-mock.service only when necessary
Yu Watanabe [Wed, 20 May 2026 14:40:51 +0000 (23:40 +0900)] 
test-network: try to stop test-modem-manager-mock.service only when necessary

Otherwise, all test cases that does not create/start the service emits
the following error:
```
Failed to stop test-modem-manager-mock.service: Unit test-modem-manager-mock.service not loaded.
```

Moreover, without this change, extra 'systemctl daemon-reload' is triggered after
all test cases. That's super heavy, especially when the test is running on
sanitizers.

Follow-up for abe3d570f8006fca5138b2d5cfb4e8b530be02e5.

8 days agoinclude: update kernel headers from v7.1-rc4
Yu Watanabe [Wed, 20 May 2026 19:57:21 +0000 (04:57 +0900)] 
include: update kernel headers from v7.1-rc4

It seems there is no notable changes to us.

8 days agotest-network: use networkctl_status() helper function at one more place
Yu Watanabe [Wed, 20 May 2026 19:33:01 +0000 (04:33 +0900)] 
test-network: use networkctl_status() helper function at one more place

8 days agoBump minimum required version of musl to 1.2.6 (#42208)
Yu Watanabe [Wed, 20 May 2026 22:04:12 +0000 (07:04 +0900)] 
Bump minimum required version of musl to 1.2.6 (#42208)

musl v1.2.6 has been released on 2026-03-20, and alpine-edge already has it:
https://pkgs.alpinelinux.org/package/edge/main/x86_64/musl

8 days agomkosi: update debian commit reference to 3e1930512d1efee7e11b619a5f493b3229594a51
Luca Boccassi [Wed, 20 May 2026 20:18:35 +0000 (21:18 +0100)] 
mkosi: update debian commit reference to 3e1930512d1efee7e11b619a5f493b3229594a51

3e1930512d Downgrade dependency on dbus to recommends in sd-container
61d6ecf0a0 Conflict with sysuser-helper
fbc4646437 autopkgtest: add dependency on procps

8 days agoman: order --secure-boot= to the same location in man page as in --help for vmspawn 42200/head
Lennart Poettering [Wed, 20 May 2026 14:23:36 +0000 (16:23 +0200)] 
man: order --secure-boot= to the same location in man page as in --help for vmspawn

8 days agovmspawn: move --kernel=/--initrd= under the "Execution" section
Lennart Poettering [Wed, 20 May 2026 13:52:57 +0000 (15:52 +0200)] 
vmspawn: move --kernel=/--initrd= under the "Execution" section

This has little to do with host configuration (where it was so far), and
a lot with what being executed, let's move it over.

Note that --help and man page so far differed here quite a bit: the
former had the "Execution" section, the latter didn't. This creates it
in the man page, to bring the two back in sync.

8 days agovmspawn: split out networking related options into its own "Networking" section in...
Lennart Poettering [Wed, 20 May 2026 13:50:32 +0000 (15:50 +0200)] 
vmspawn: split out networking related options into its own "Networking" section in --help

8 days agovmspawn: split 'Integration' section into 'Logging' and 'SSH'
Lennart Poettering [Wed, 20 May 2026 13:48:44 +0000 (15:48 +0200)] 
vmspawn: split 'Integration' section into 'Logging' and 'SSH'

Each of the two has multiple options, hence let's split them out.

8 days agovmspawn: move image related knobs close to --image=
Lennart Poettering [Wed, 20 May 2026 13:45:57 +0000 (15:45 +0200)] 
vmspawn: move image related knobs close to --image=

(Also, arrange the order if the image options group in the man page to
the same as in the --help text)

9 days agoNEWS: mention bump of musl requirement 42208/head
Yu Watanabe [Wed, 20 May 2026 19:07:36 +0000 (04:07 +0900)] 
NEWS: mention bump of musl requirement

9 days agomusl: drop several statx definitions
Yu Watanabe [Wed, 20 May 2026 16:14:59 +0000 (01:14 +0900)] 
musl: drop several statx definitions

Those dropped definitions have been provided since musl v1.2.6.

9 days agomusl: drop renameat2() wrapper
Yu Watanabe [Wed, 20 May 2026 16:08:24 +0000 (01:08 +0900)] 
musl: drop renameat2() wrapper

musl provides renameat2() since v1.2.6:
https://git.musl-libc.org/cgit/musl/commit/?id=05ce67fea99ca09cd4b6625cff7aec9cc222dd5a

9 days agoREADME: bump required minimum version of musl to 1.2.6
Yu Watanabe [Wed, 20 May 2026 16:30:43 +0000 (01:30 +0900)] 
README: bump required minimum version of musl to 1.2.6

musl v1.2.6 has been released on 2026-03-20:
https://git.musl-libc.org/cgit/musl/commit/?id=9fa28ece75d8a2191de7c5bb53bed224c5947417

alpine/postmarketos already have musl v1.2.6 in the edge repository:
https://pkgs.alpinelinux.org/package/edge/main/x86_64/musl

Also, Yocto Project 6.0 (wrynose) already has v1.2.6.

Let's bump the requirement now.

9 days agoupdatectl: Add a --no-ask-password argument
Philip Withnall [Wed, 20 May 2026 16:15:00 +0000 (17:15 +0100)] 
updatectl: Add a --no-ask-password argument

While commit 83c1e8ff5f9 added support for interactive polkit
authentication in `updatectl`, some users might want to disable that for
some use cases; so add the standard `--no-ask-password` argument.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: https://github.com/systemd/systemd/issues/37412

9 days agoCouple of rearragements for src/core/meson.build (#42207)
Yu Watanabe [Wed, 20 May 2026 19:18:14 +0000 (04:18 +0900)] 
Couple of rearragements for src/core/meson.build (#42207)

Net result is `import-creds.c` moving from libcore to systemd

9 days agoci: run the musl build & test under mkosi with a postmarketOS tools tree (#42171)
Daan De Meyer [Wed, 20 May 2026 19:03:14 +0000 (21:03 +0200)] 
ci: run the musl build & test under mkosi with a postmarketOS tools tree (#42171)

9 days agoinclude: move several missing definitions to musl
Yu Watanabe [Wed, 20 May 2026 15:54:26 +0000 (00:54 +0900)] 
include: move several missing definitions to musl

Those moved ones have been defined in glibc <= 2.34, and only
necessary when built with musl.

Follow-up for c8c1bcf1941047d1fe43d9827ad4826b4620297a.

9 days agofirstboot: auto-fill keymap/locale questions with data from firmware, if available...
Yu Watanabe [Wed, 20 May 2026 18:50:43 +0000 (03:50 +0900)] 
firstboot: auto-fill keymap/locale questions with data from firmware, if available (#42177)

Let's make the installer experience a tiny bit nicer, and prefill
everything with the data the firmware gives us.

9 days agodns-packet: bail out early if the packet is too short (#42189)
Yu Watanabe [Wed, 20 May 2026 18:43:18 +0000 (03:43 +0900)] 
dns-packet: bail out early if the packet is too short (#42189)

This should address the nit from Claude in
https://github.com/systemd/systemd/pull/42178#pullrequestreview-4320763076.

9 days agoci: run the musl build & test under mkosi with a postmarketOS tools tree 42171/head
Daan De Meyer [Tue, 19 May 2026 10:36:01 +0000 (10:36 +0000)] 
ci: run the musl build & test under mkosi with a postmarketOS tools tree

Drop the standalone Unit-tests (musl) workflow that ran on an Alpine sandbox
spun up by jirutka/setup-alpine, and merge it into unit-tests.yml as a new
build-musl job that provisions a postmarketOS tools tree via mkosi and runs
the meson build + test suite through 'mkosi box'. postmarketOS is musl-native,
so the musl-gcc / -idirafter /usr/include wrappers the Fedora tools tree
needed are gone; the linter.yml's own musl build step also goes away since
the unit-tests workflow now covers it (and tests it).

postmarketOS doesn't ship a downstream systemd packaging spec, so the new
tools tree config in mkosi.tools.conf/mkosi.conf.d/postmarketos.conf does not
set PrepareScripts and lists build deps manually. mkosi.sync now early-exits
when PKG_SUBDIR is unset so the missing pkgenv entry doesn't trip set -u.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
9 days agotest-path: Skip test when we can't create a cgroup
Daan De Meyer [Wed, 20 May 2026 17:21:13 +0000 (17:21 +0000)] 
test-path: Skip test when we can't create a cgroup

Instead of having CI runner specific checks, let's just
skip the test if we get EXIT_CGROUP which is what we get
when we can't create a cgroup. This makes the check work
independently of CI runner, and specifically also on github
actions.

9 days agomeson: move one source file from libcore to systemd array 42207/head
Luca Boccassi [Wed, 20 May 2026 17:15:52 +0000 (18:15 +0100)] 
meson: move one source file from libcore to systemd array

9 days agomeson: reorder core sources alphabetically
Luca Boccassi [Wed, 20 May 2026 16:32:08 +0000 (17:32 +0100)] 
meson: reorder core sources alphabetically

9 days agomeson: reorder core sources array
Luca Boccassi [Wed, 20 May 2026 16:30:31 +0000 (17:30 +0100)] 
meson: reorder core sources array

To hint that sources should be added to the lowest common denominator
first

9 days agotest-path: Migrate to test framework and macros
Daan De Meyer [Wed, 20 May 2026 13:30:28 +0000 (13:30 +0000)] 
test-path: Migrate to test framework and macros

- Also clean up the logging in check_states() to
  only log on state changes so it's less noisy.

9 days agotest-path: Fail earlier on start-limit-hit
Daan De Meyer [Wed, 20 May 2026 08:52:21 +0000 (08:52 +0000)] 
test-path: Fail earlier on start-limit-hit

9 days agomeson: Skip coccinelle suite by default
Daan De Meyer [Wed, 20 May 2026 07:18:41 +0000 (07:18 +0000)] 
meson: Skip coccinelle suite by default

It's not fully passing yet so disable it by default until it is.
clang-tidy follows the same model.

9 days agotest-ukify: Skip kernel images we can't access
Daan De Meyer [Wed, 20 May 2026 08:51:56 +0000 (08:51 +0000)] 
test-ukify: Skip kernel images we can't access

9 days agomkosi: update mkosi ref to be746d51bc90568b196951a60095ba87bf51ca8b
Daan De Meyer [Tue, 19 May 2026 21:07:10 +0000 (21:07 +0000)] 
mkosi: update mkosi ref to be746d51bc90568b196951a60095ba87bf51ca8b

be746d51bc Make full $PATH available when building tools tree

9 days agoptyfwd: Imply PTY_FORWARD_READ_ONLY if stdin isn't readable
Daan De Meyer [Wed, 20 May 2026 12:14:52 +0000 (12:14 +0000)] 
ptyfwd: Imply PTY_FORWARD_READ_ONLY if stdin isn't readable

if stdin is connected to a closed pipe or similar, imply
PTY_FORWARD_READ_ONLY so we don't even try to read from it
in the first place. Otherwise we'll immediately get a hangup
which will cause the forwarder to call sd_event_exit() and
shut down the event loop.

Debugged-by: Christian Brauner <brauner@kernel.org>
9 days agovmspawn: initial support for SEV-SNP guests (#42193)
Lennart Poettering [Wed, 20 May 2026 15:42:26 +0000 (17:42 +0200)] 
vmspawn: initial support for SEV-SNP guests  (#42193)

9 days agosystemd-udevd: configure NIC IRQs CPU affinity (#40304)
Yu Watanabe [Wed, 20 May 2026 15:39:47 +0000 (00:39 +0900)] 
systemd-udevd: configure NIC IRQs CPU affinity (#40304)

# Context

#40195 defines the initial proposal and the motivation behind this PR.

This PR introduces 3 new options for `.link` files `[Link]` section:
- `IRQAffinityPolicy=`
- `IRQAffinity=`
- `IRQAffinityNUMA=`

The purpose is to allow `systemd-udevd` to configure a NIC's IRQs
affinity to specific CPU(s).

`IRQAffinityPolicy=` supports two policies:
- `single`: assign all the NIC IRQs to CPU 0, or the first CPU in the
CPU set resulting from the union of `IRQAffinity=` and
`IRQAffinityNUMA=`.
- `spread`: assign all the NIC IRQs to all the CPUs (or the union of
`IRQAffinity=` and `IRQAffinityNUMA=` if defined) in a round-robin
fashion while optimizing for cache locally while spreading apart queues
on CPUs as much as possible.

Both `IRQAffinity=` and `IRQAffinityNUMA=` behaves as filters to reduce
the CPU set to assign IRQs to, and are only valid if
`IRQAffinityPolicy=` is defined.

# Spreading IRQs

This section describes the algorithm responsible for spreading IRQs over
different CPUs to maximize performance.

## 1. Discover CPU topology

Read from `/sys/devices/system/cpu/cpu*/topology` to identify:
- L3 cache domains (dies)
- Physical cores VS hyperthreads
- NUMA nodes
- Core ordering within each die

```
Example: Dual-socket server with 2 dies per socket, 4 cores per die

      ┌─────────────────────────────────────────────────────────────────┐
      │                         NUMA Node 0                             │
      │   ┌─────────────────────────┐   ┌─────────────────────────┐     │
      │   │   Die 0 (L3 Cache)      │   │   Die 1 (L3 Cache)      │     │
      │   │  ┌────┐┌────┐┌────┐┌────│   │  ┌────┐┌────┐┌────┐┌────│     │
      │   │  │ C0 ││ C1 ││ C2 ││ C3 │   │  │ C4 ││ C5 ││ C6 ││ C7 │     │
      │   │  │0,16││1,17││2,18││3,19│   │  │4,20││5,21││6,22││7,23│     │
      │   │  └────┘└────┘└────┘└────│   │  └────┘└────┘└────┘└────│     │
      │   └─────────────────────────┘   └─────────────────────────┘     │
      └─────────────────────────────────────────────────────────────────┘
      ┌─────────────────────────────────────────────────────────────────┐
      │                         NUMA Node 1                             │
      │   ┌─────────────────────────┐   ┌─────────────────────────┐     │
      │   │   Die 2 (L3 Cache)      │   │   Die 3 (L3 Cache)      │     │
      │   │  ┌────┐┌────┐┌────┐┌────│   │  ┌────┐┌────┐┌────┐┌────│     │
      │   │  │ C8 ││ C9 ││C10 ││C11 │   │  │C12 ││C13 ││C14 ││C15 │     │
      │   │  │8,24││9,25││10,2││11,2│   │  │12,2││13,2││14,3││15,3│     │
      │   │  └────┘└────┘└────┘└────│   │  └────┘└────┘└────┘└────│     │
      │   └─────────────────────────┘   └─────────────────────────┘     │
      └─────────────────────────────────────────────────────────────────┘
                  (Numbers show CPU IDs: first HT, second HT)
```

## 2. Filter the first hyperthread only

Use only the first hyperthread of each physical core to avoid SMT
contention. Two IRQs on sibling HTs contend for ALU/cache without cache
benefit.

```
      Before: CPUs 0-31 (16 cores × 2 HTs)
      After:  CPUs 0-15 (first HT of each core)
```

## 3. Equidistant permutations

Reorder dies and CPUs so consecutive selections are maximally spread
apart.

```
        Original order:  [0, 1, 2, 3]          (adjacent dies/CPUs)
                            |
                            v
        Equidistant:     [0, 2, 1, 3]          (spread apart)
```

This ensures that even if only 2 IRQs are assigned, they land on dies 0
and 2 (not 0 and 1), maximizing physical distance. The permutation is
also applied within each die:

```
        Die permutation:   Die0 -> Die2 -> Die1 -> Die3

        Within each die:
        ┌───────────────────────────────────────────────┐
        │ Die 0: [C0,C1,C2,C3]     -> [C0,C2,C1,C3]     │
        │ Die 1: [C4,C5,C6,C7]     -> [C4,C6,C5,C7]     │
        │ Die 2: [C8,C9,C10,C11]   -> [C8,C10,C9,C11]   │
        │ Die 3: [C12,C13,C14,C15] -> [C12,C14,C13,C15] │
        └───────────────────────────────────────────────┘
```

## 4. Round-robin selection across dies

Pick one CPU from each die in rotation, following permuted order.

```

      Round 1:     Die0->C0   Die2->C8   Die1->C4   Die3->C12
                      |          |          |          |
                      v          v          v          v
      IRQs:         [IRQ0]     [IRQ1]     [IRQ2]     [IRQ3]

      Round 2:     Die0->C2   Die2->C10  Die1->C6   Die3->C14
                      |          |          |          |
                      v          v          v          v
      IRQs:         [IRQ4]     [IRQ5]     [IRQ6]     [IRQ7]
```

If there are more IRQs than physical cores, this logic wraps around and
reuse CPUs. Only the first hyperthread of each core is used to avoid
cache line contention between queues.

Closes #40195.

9 days agoRevert "meson: shrink developer-mode build artifacts"
Luca Boccassi [Wed, 20 May 2026 14:51:17 +0000 (15:51 +0100)] 
Revert "meson: shrink developer-mode build artifacts"

This reverts commit 68910161491cdd161bff29a32032e52301831164.

9 days agoupdate TODO 42177/head
Lennart Poettering [Tue, 19 May 2026 13:54:48 +0000 (15:54 +0200)] 
update TODO

9 days agofirstboot: port help() to help-util.[ch] APIs
Lennart Poettering [Wed, 20 May 2026 14:34:13 +0000 (16:34 +0200)] 
firstboot: port help() to help-util.[ch] APIs