The attempt to fix SIGILL in TEST-55-OOMD actually made the test more
flaky, as the chosen stress-ng method generates less pressure, so it
often fails.
Try a different approach: try to detect that SIGILL caused the unit
calling stress-ng to fail, and skip gracefully in that case.
This test can regress without changes on our end when
an older systemd is built against a newer glibc and
the newer glibc has an ABI break for a symbol we use
but don't dlsym(). To avoid spurious test failures for
downstream packagers, let's only run the test in developer
mode for now.
On architectures where glibc support was introduced after our baseline
(e.g. loongarch64, added in glibc 2.36), every imported symbol is
tagged with a version newer than the baseline, so the baseline check
fails spuriously. Detect this by taking the minimum version observed
across all binaries: if it exceeds the baseline, treat that minimum
as the effective baseline instead.
Follow up for d9600a2a
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
RSA PKCS#1 v1.5 is vulnerable to Bleichenbacher-style padding oracle
attacks, albeit very difficult and unlikely to actually happen in the
real world. Still for hardedning, switch new enrollments to RSA-OAEP,
with SHA-256 preferred and SHA-1 as fallback (probed at enrollment time,
since e.g. SoftHSM only accepts SHA-1, and older token might as well).
The actual padding scheme used to wrap a given key is recorded as a new
optional 'pkcs11-padding' / 'padding' field in the LUKS2 token JSON and
the homed user record. Decryption defaults to PKCS#1 v1.5 when absent so
existing enrollments keep working.
`sysupdate --json=short components` lists the components known to
sysupdate; these are the components which something like `updatectl`
will try to update.
The `default` component represents the host, and is meant to be listed
if transfer definitions exist in (for example) `/etc/sysupdate.d`
corresponding to the host OS. This then corresponds to `TARGET_HOST` in
`updatectl` and causes it to try updating that target.
The logic for working out whether the `default` component was present
essentially boiled down to “does `{/run,/etc,/usr/lib}/sysupdate.d`
exist”, and it didn’t check whether a `.transfer` or `.conf` file
actually existed in the config directory.
This is quite the corner case, but becomes more evident on systems where
sysupdate is being used to update a portable service but not the main
OS. At that point, if `/etc/sysupdate.d` exists empty (for some reason),
`updatectl` falls over because it starts trying to update the host OS
without any configuration to do so.
So, modify `sysupdate` to more fully load the available configuration
when listing components, and query it a bit more deeply to check whether
a default component exists.
If `sysupdate` is called with various command line arguments to affect
how its configuration is loaded, do *not* say that a default component
exists, as these arguments essentially anull the possibility of a
default being used in that process.
Add an integration test based on the reproducer provided by the issue
reporter. This test has been tested to fail if the changes to
`sysupdate.c` aren’t applied — if so, the second call to `sysupdate
components` would return
`{"default":true,"components":["some-component"]}`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: https://github.com/systemd/systemd/issues/41501
manager_luo_serialize_fd_stores() refuses to serialize a unit fd store
entry that holds a child LUO session named like PID 1's own ("systemd"),
to stop a service from hijacking PID 1's reserved session namespace
across kexec. That guard had no test coverage.
Add a test-luo store-hijack/check-hijack subcommand pair: on the first
boot a system service preserves a child LUO session named "systemd" in
its fd store; after kexec the test asserts the entry was not restored --
the unit's NFileDescriptorStore is 0, and check-hijack, run as the unit's
own second-boot ExecStart, confirms the hijack fd is absent from its
restored LISTEN_FDNAMES -- proving PID 1 skipped it during serialization.
The restore-side guards (corrupt mapping, reserved token 0, invalid unit
name, missing child session) are intentionally not covered: they only run
against PID 1's own "systemd" session built by luo_preserve_fd_stores(),
which a cooperating userspace helper cannot corrupt without racing or
displacing PID 1 (it single-owns /dev/liveupdate at shutdown). Triggering
them reliably would need kernel fault injection.
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
`sysupdate --json=short components` lists the components known to
sysupdate; these are the components which something like `updatectl`
will try to update.
The `default` component represents the host, and is meant to be listed
if transfer definitions exist in (for example) `/etc/sysupdate.d`
corresponding to the host OS. This then corresponds to `TARGET_HOST` in
`updatectl` and causes it to try updating that target.
The logic for working out whether the `default` component was present
essentially boiled down to “does `{/run,/etc,/usr/lib}/sysupdate.d`
exist”, and it didn’t check whether a `.transfer` or `.conf` file
actually existed in the config directory.
This is quite the corner case, but becomes more evident on systems where
sysupdate is being used to update a portable service but not the main
OS. At that point, if `/etc/sysupdate.d` exists empty (for some reason),
`updatectl` falls over because it starts trying to update the host OS
without any configuration to do so.
So, modify `sysupdate` to more fully load the available configuration
when listing components, and query it a bit more deeply to check whether
a default component exists.
If `sysupdate` is called with various command line arguments to affect
how its configuration is loaded, do *not* say that a default component
exists, as these arguments essentially anull the possibility of a
default being used in that process.
Add an integration test based on the reproducer provided by the issue
reporter. This test has been tested to fail if the changes to
`sysupdate.c` aren’t applied — if so, the second call to `sysupdate
components` would return
`{"default":true,"components":["some-component"]}`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: https://github.com/systemd/systemd/issues/41501
This irked me for a while. Let's not scan for strings stupidly, but
properly parse PE files to find the magic marker.
It's easy with our own PE APIs, hence we should do it.
This moves logging to the callers (previously, this was all mixed up).
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.
Regression coverage for the soft-reboot linger bug fixed in
9f25feb4ed ("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>
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.
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.
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 9142bd5a8e. The
change itself should be OK. So, the test case is updated.
The test case `test_ndisc_mtu` was broken when the commit
32417c1723 is merged. The commit is not
correct, as we cannot set IPv6 MTU larger than interface MTU. So, the
offending commit is reverted.
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).
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.
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.
Then, this deprecates
- BindToInterface=
- RelayTarget=
- RelayAgentCircuitId=
- RelayAgentRemoteId=
settings in [DHCPServer] section.
These are gracefully translated as new settings.
After 9142bd5a8e, 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.
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 abe3d570f8.
This commit moves the io.systemd.Unit.StartTransient tests into
the right place in TEST-74-AUX-UTILS.varlinkctl-unit.sh.
Thanks to Ivan Kruglov for suggesting this.
This commit move the erros in StartTransient from
VARLINK_ERROR_UNIT_BAD_SETTING to SD_VARLINK_ERROR_INVALID_PARAMETER
and it also ensures we have the bad field in the error.
Thanks to Ivan Kruglov for suggesting this.
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.
Add support for filtering IRQ affinity to CPUs on a specific NUMA node
via the new IRQAffinityNUMA= option in .link files. The option accepts:
- "local": use the NUMA node local to the NIC's PCIe slot
- Explicit node number (0, 1, 2, ...): use CPUs on the specified node
When both IRQAffinity= and IRQAffinityNUMA= are specified, their
intersection is used. If the intersection is empty, an error is logged
and IRQ affinity configuration is skipped.
When "local" is specified but the device's NUMA node cannot be
determined (numa_node shows -1), a warning is logged and IRQ affinity
configuration is skipped.
Add IRQAffinity= option to .link files that filters the set of CPUs
eligible for IRQ placement. This works in conjunction with
IRQAffinityPolicy= to constrain which CPUs receive network IRQs.
When specified with spread policy, only the listed CPUs are considered
for IRQ distribution. When specified with single policy, IRQs are
pinned to the first CPU in the allowed set instead of CPU 0.
Implement the spread policy for IRQ affinity distribution using a
topology-aware algorithm. The algorithm:
1. Discovers CPU topology from sysfs (NUMA node, package, die/L3, core)
2. Groups CPUs by L3 cache domain (die) with equidistant ordering
3. Round-robins across dies, spreading IRQs across the system
4. Uses first hyperthread of each core before second hyperthreads
5. Applies IRQ affinity via /proc/irq/<n>/smp_affinity
When there are more IRQs than CPUs, queues wrap around using round-robin.
Add support for configuring IRQ affinity for network interfaces via
systemd .link files. For now, the new IRQAffinityPolicy= option in the [Link]
section only accepts "single", which pins all MSI IRQs to CPU 0.
This allows declarative IRQ affinity configuration for network devices
during udev processing, which is useful for optimizing network
performance on multi-core systems.
Further commits will expand the options supported by IRQAffinityPolicy=.
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).
For every built executable, internal shared library, and plugin module,
verify two link-time properties via readelf:
1. No imported GLIBC symbol's version is newer than 2.34.
2. The dynamic section's NEEDED entries reference only glibc, the
runtime linker, our own libraries.
Methods:
- `io.systemd.Job.List` — list all queued jobs or look up by `id`/`unit`
name, with streaming support. Uses context/runtime split: `JobContext`
(Unit, JobType) and `JobRuntime` (Id, State, Result,
ActivationDetails). Follows the same SELinux and parameter-conflict
patterns as `io.systemd.Unit.List`.
- `io.systemd.Job.Cancel` — cancel a specific job by ID, with SELinux
and polkit authorization.
- `io.systemd.Job.ClearAll` — cancel all pending jobs, with SELinux and
polkit authorization.
Commit 881e4717c7 ("test: pin stress-ng --vm-method to a portable
scalar method in TEST-55-OOMD") pinned --vm-method=zero-one with the
rationale that it is "a long-standing scalar method". That rationale is
wrong: stress_vm_zero_one() in stress-ng's stress-vm.c is declared
static size_t TARGET_CLONES stress_vm_zero_one(...)
i.e. it carries the exact same TARGET_CLONES attribute as 33 of the 35
other vm methods. On x86_64 with GCC >=5, TARGET_CLONES expands (see
core-target-clones.h in stress-ng) to a target_clones attribute
including "arch=skylake-avx512", "arch=cooperlake", "arch=tigerlake",
"arch=sapphirerapids", and several other AVX-512-bearing arch variants,
plus "default". GCC generates AVX-512 clones of stress_vm_zero_one() and
the IFUNC resolver picks them on any CPU that advertises AVX-512.
The only vm methods in stress-ng's registry whose function definitions
omit TARGET_CLONES entirely (and are therefore guaranteed not to
dispatch to an AVX-512 clone) are lfsr32 (portable, always registered)
and write64ds (x86_64-only, gated on HAVE_ASM_X86_MOVDIRI, i.e. Intel
Tremont / Tiger Lake+ MOVDIRI instruction).
Switch the four stress-ng --vm invocations in TEST-55-OOMD to
--vm-method=lfsr32 so the AVX-512 SIGILL on CPUs without AVX-512 (e.g.
AMD Zen 1-3) can no longer occur regardless of compiler version,
optimization level, or stress-ng package build.
Follow-up for 881e4717c7
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
The test waited for the OnFailure= service's filesystem side effect
(`rmdir` of the directory) and then immediately invoked
`systemctl is-active`. Between `rmdir(2)` returning (which causes the
shell loop to exit) and PID1 reaping the child and transitioning the
oneshot service from `activating` to `active`, there is a small window
where `is-active` can observe `activating` and fail the test.
Wait directly on the unit state instead, matching the pattern used a
few lines above for the `is-failed` case.
[ 1880.326704] TEST-07-PID1.sh[21489]: + timeout --foreground 60 bash -c 'while [[ -d '\''/tmp/TEST-07-PID1-socket-8467/test'\'' ]]; do sleep .5; done'
[ 1880.330482] TEST-07-PID1.sh[21489]: + [[ ! -e /tmp/TEST-07-PID1-socket-8467/test ]]
[ 1880.330482] TEST-07-PID1.sh[21489]: + systemctl is-active TEST-07-PID1-socket-OnFailure.service
[ 1880.347470] TEST-07-PID1.sh[21520]: activating
[ 1880.349508] TEST-07-PID1.sh[21489]: + at_exit
[ 1880.349508] TEST-07-PID1.sh[21489]: + systemctl stop TEST-07-PID1-socket-8467.socket
[ 1880.367331] TEST-07-PID1.sh[107]: Subtest /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.socket-on-failure.sh failed
[ 1880.367331] TEST-07-PID1.sh[107]: + return 1
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>