Commit Graph
91834 Commits
Author SHA1 Message Date
Chris Down bceb7741b5 test: Cover BPF link replacement when re-realising cgroups
(cherry picked from commit 09d08b879986e9b55a4d1ed767d1e6b40ca82e39)
2026-10-16 17:24:50 +01:00
Chris Down 8ac16654bc core: Don't leak BPF links when realizing a cgroup again
cgroup_context_apply() attaches the BPF programs again whenever the
cgroup is realised again, for example, if someone does set-property or
daemon-relaod.

As it is now, their installers overwrite the links of the previous
installation without freeing them, so the previous programs stay
attached until the cgroup is removed, and keep enforcing whatever
settings they were loaded with.

For example, a unit with SocketBindDeny=any that is allowed to bind to a
port with "systemctl set-property foo.service SocketBindAllow=tcp:1234"
still cannot do so once its cgroup is realised again, as the previous
program keeps denying it. Whoops!

To fix this let's free the previous links once the new ones are
attached.

(cherry picked from commit 2f11fb19b7292339632e9b396fcab12729cde1ff)
2026-10-16 17:24:50 +01:00
Yu Watanabe 356b2edcc1 TEST-17-UDEV: drop redundant test cases
All test cases are covered by TEST-17-UDEV.device-unit-state-transition-netif.sh
added in the previous commit.

(cherry picked from commit 1ac7d20002fe6e94d24c1e652cdffa5515e1461e)
2026-10-16 17:24:50 +01:00
Yu Watanabe 8f20400e85 test: introduce several helper functions
(cherry picked from commit 04c4fe7930d83247b68427dd1cc61b19219596c2)
2026-10-16 11:36:33 +01:00
Yu Watanabe f85b6ddaae test: show name of failed test case
(cherry picked from commit 4ef7744c2e275bf6dd4199623aa7959f9f6551c8)
2026-10-16 11:36:33 +01:00
Jonghyun An 6f2b2f4df0 ukify: accept whitespace around commas in PCR bank and phase lists
Splitting on either a comma or whitespace produces empty items when
whitespace is adjacent to a comma. This rejects valid phase lists and leaves
empty entries in PCR bank lists.

Consume whitespace around commas and accept a single trailing comma in
both lists. Reject leading commas, empty entries between commas and
repeated trailing commas. Treat an empty PCR bank list as no banks.

Update the existing configuration test to cover whitespace around commas
and a trailing comma in both settings.

(cherry picked from commit 44cf775de15c1853c28fd2610f49014855ba09ec)
2026-10-16 11:36:33 +01:00
Nick Rosbrook 7457840e90 ssh-generator: do not log unusable CID
For consistency with ssh-issue output, do not log about the CID if it is
not a usable destination.

(cherry picked from commit 0d59bcb6944d1f34e8eca9208af198f5357e8535)
2026-10-16 11:36:33 +01:00
Nick Rosbrook fd34e93645 ssh-issue: never suggest connecting with VMADDR_CID_ANY
Even if the vsock driver allows using this as a wildcard to listen over
vsock, it still cannot be used as a destination CID from the host (and
is rejected by systemd-ssh-proxy). Show a more generic message in this
case instead.

Use VSOCK_CID_IS_REGULAR() to exclude other similar cases too.

Follow-up for 85afe8e82d.

Fixes: https://github.com/systemd/systemd/issues/43364
(cherry picked from commit affcccd4d07180b82d918c0c5f0601d1dec80946)
2026-10-16 11:36:33 +01:00
Dustin Kirkland f844429534 bootctl: don't fail 'status' when the ESP has no random seed
Since f90efd2d13 the result of the
access() check for loader/random-seed is stored in 'r', which is what
verb_status() returns. A missing seed file then makes 'bootctl status'
exit with 1 without logging anything, even though it's only reported as
"Exists: no". Use 'k' for the check, like the other informational
probes in this function.

(cherry picked from commit 05808e11b9399e6c2149f1f524b3282545ba7569)
2026-10-16 11:36:33 +01:00
Rodrigo Campos d6bf5fbaf2 test: cover attaching with a profile that does not exist
Both attach and reattach must fail, and the latter must not detach the
image first.

(cherry picked from commit 430f8962cf2e454cc9b474a22b92a89a26872e9b)
2026-10-16 11:36:33 +01:00
Rodrigo Campos 0b1c0782bb portablectl: quote the profile name in the validation error
With an empty profile we get:

	$ portablectl attach -p "" foo
	Unit profile name not valid:

It's not clear what is the profile. Let's quote it so it's clear also
for empty profile names.

(cherry picked from commit 6c8b21d30db4f4d5a0cdce9f2dc6a99b9b47e7c7)
2026-10-16 11:36:33 +01:00
Rodrigo Campos 92d54a0d3d portable: fail attach/reattach if the profile does not exist
Before this commit, if you attach a portable service using a profile
that doesn't exist, it just doesn't add the profile dropin and no
warning nor anything is shown:

	$ portablectl attach -p nonexistent xxx
	  (Matching unit files with prefix 'xxx'.)
	  Created directory /etc/systemd/system.attached.
	  Created directory /etc/systemd/system.attached/xxx-capsule.service.d.
	  Written /etc/systemd/system.attached/xxx-capsule.service.d/20-portable.conf.
	  Copied /etc/systemd/system.attached/xxx-capsule.service.
	  Created symlink /etc/portables/xxx.raw → /var/lib/portables/xxx.raw.

	$ ls /etc/systemd/system.attached/xxx-capsule.service.d/
	  20-portable.conf

The 10-profile.conf is not added.

If no profile is attached, the /run bind mount is not added and then lot
of things inside fail in ways that don't make sense.

This patch just makes portable_attach() and reattach check the profile
exists. If it doesn't exist, it shows this error now:

	# portablectl -p doesntexists reattach xxx
	(Matching unit files with prefix 'xxx'.)
	ReattachImage failed: Profile 'doesntexists' does not exist, refusing. (Available profiles are: default, nonetwork, strict, trusted)

In reattach we do it early, before detach, so we don't detach and then
fail to attach it and leave the service detached.

An empty profile name is rejected too by the call to
filename_is_valid(). portablectl already rejects empty profile names.

Please note that we don't change install_profile_dropin(), as that skips
non-existing profiles because that is done at the unit type level and
it's okay if it doesn't exist for some unit types. For example,
/usr/lib/systemd/portable/profile/trusted/ ships a service.conf, but not
timer.conf, socket.conf, etc.

(cherry picked from commit 5642eb3d848300f7225dff25fdd82940e55101c9)
2026-10-16 11:36:33 +01:00
Rodrigo Campos 2832b3f2c9 portable: log the right error when the profile lookup fails
find_portable_profile() returns a negative errno and does not set errno,
so the two log messages reported a stale or unrelated errno value.

(cherry picked from commit 8da05abc9a8c21af85542b0d4d1d5f48a47f738e)
2026-10-16 11:36:33 +01:00
Jörg Behrmann 04a645cce5 ukify: check terminal colour support more thoroughly
This adds an extended version of mkosi's terminal_is_dumb that checks that both
stdout and stderr are connected to a TTY and also checks that the TERM
environment variable is not set to dumb. Additionally this adds support for the
NO_COLOR variable.

(cherry picked from commit 2c46b11b319e42acb113f659098fad8eeac51b69)
2026-10-16 11:36:33 +01:00
vidir-semaphor afb890d5fc Fix apparent copy-past error in (un)lock-secureboot-policy entry
(cherry picked from commit 8e39ca4bfa6c77c8639bbeb89ec938e6e6683cec)
2026-10-16 11:36:33 +01:00
Ilya Naidanov f5ecd46e22 binfmt: clear the ignored flush failure before the registration loop
The "flush out all rules" step writes to /proc/sys/fs/binfmt_misc/status and
explicitly ignores failure, but it assigns the result to the same r that
RET_GATHER() consumes below. RET_GATHER() keeps the first error it is given,
so a failed flush is still returned from run() and systemd-binfmt exits 1 even
when every rule in binfmt.d was registered successfully.

Reset r after the ignored flush so it cannot be gathered.

Tested on WSL2 (kernel 6.18.40.1-microsoft-standard-WSL2), systemd 261, where
/proc/sys/fs/binfmt_misc/status is a read-only tmpfs. Before this, the binary
registered /etc/binfmt.d/nixos.conf successfully and then exited 1; after, it
exits 0. /proc/sys/fs/binfmt_misc/WSLInterop stays enabled in both cases.

Fixes #44035.

(cherry picked from commit 8fc6b2141b113f63427a766aa800539437138d6c)
2026-10-16 11:36:33 +01:00
Jonghyun An 1de356e556 man: document ukify SignInitrdPCRs setting
UKI/SignInitrdPCRs was added together with --sign-initrd-pcrs, but only
that command-line option is documented. Document the configuration key
and move the entry to the [UKI] section.

Fixes #43863.

(cherry picked from commit 4f8ca5032fd0633c6b5caff4868a375ac91b5b0f)
2026-10-16 11:36:33 +01:00
Daan De Meyer 121d621934 rpm: Fix copy paste bug in lua triggers
(cherry picked from commit df4eba96b645d1423b3b5d2090e720c2dc28c58b)
2026-10-16 11:36:33 +01:00
Daan De Meyer 4acbcd3302 nsresourced: keep running if the BPF-LSM programs cannot be attached
Since 7eb016d60b ("nsresourced: restore the BPF-LSM policy from the
registry on startup"), the programs are loaded in manager_setup_bpf()
but only attached later in manager_attach_bpf(). Before that, a failed
attach made the whole setup fail, and nsresourced proceeded with the
user namespace interfaces disabled. Now the same failure is fatal, and
nsresourced exits on kernels that can load BPF-LSM programs but not
attach them, such as arm64 before 7.2.

Handle a failed attach like a failed setup again: log it, drop the BPF
state, and continue with the user namespace interfaces disabled.

When a program fails to attach, the programs attached before it stay
attached, because userns_restrict_attach() has already pinned their
links. The programs keep enforcing the policy. Without the ring buffer
reader, nsresourced never reaps dead namespaces from the maps. Remove
the pins created by the failed attach, so that dropping the BPF state
detaches the programs.

test-userns-restrict fails on the same kernels, because it asserts that
the attach succeeds. Skip it instead.

Fixes: #43964
(cherry picked from commit 4446b9bb51c9900f22d7ba50379fa96dcbfb58f2)
2026-10-16 11:36:33 +01:00
Zbigniew Jędrzejewski-Szmek 58befb6079 man/systemd-vmspawn: consistently mark as experimental
It was added as experimental in v255: "this component is experimental and
its public interface is subject to change". This status was never changed
and the meson config still disables vmspawn by default in non-developer
builds. I think this makes sense to keep things this way and remove all
experimental markings at once with an official announcement once we're
sure about the interface.

(cherry picked from commit f2323da4da8c3311b855f505cdddc66400c501ee)
2026-10-16 11:36:33 +01:00
Zbigniew Jędrzejewski-Szmek 945e223a6c man: add a shared "experimental" blurb for features
(cherry picked from commit a6eb2b4d2e7f747bbfb0f5f3ebb1421855113d36)
2026-10-16 11:36:33 +01:00
Zbigniew Jędrzejewski-Szmek bc97e77ba7 man: reword "experimental" blurbs to be more accurate
The text implied that the changes may happen randomly at any time.
Obviously, they can only happen after an update, but also we're unlikely
to do that not on a major release boundary. So town down that part of the
message. At the same time, it's important that the change might just
happen. For stable features, we also sometimes implement incompatible
changes, but this is preceded by announcements and lengthy deprecation
periods. So use the phrase "without advance notice".

OTOH, the text implicitly promised future stabilization. This might or
might not happen, so remind the users that it might not.

(cherry picked from commit 96cb6a5c74c8cd64334c48ddcca18e128e9a40ea)
2026-10-16 11:36:33 +01:00
Zbigniew Jędrzejewski-Szmek d81edcf73d man: reuse the shared "experimental" blurbs
The blurbs were added to be shared, but no sharing was actually
done.

Also, rename "singular"/"plural" to "option"/"options", so that we
can later have "component"/"components" and possibly other
variants.

The text were a bit different in various places, but I don't think
it was a useful distinction.

(cherry picked from commit 69dd30fddf2bbf358e05a632b0ef3383eb46b028)
2026-10-16 11:36:33 +01:00
Jonghyun An 0236ab116e ukify: reject trailing garbage in output section specifications
The output section parser matches a valid prefix and ignores any remaining
characters. For example, '.cmdline:textjunk' is treated as text output,
and '.cmdline:text@' is accepted despite the missing output filename.

Require the complete specification to match the existing grammar, and
test malformed suffixes along with valid text and binary output.

(cherry picked from commit fbb4b64bdb326fac5c19122f88bd9d1feb0350e5)
2026-10-16 11:36:33 +01:00
Yu Watanabe 4aea5ef8e9 udev: lower priority of events triggered by device monitor
Commit 905a89a219 raised the priority of
events triggered by the device monitor, so that the queue file would not
be removed while the netlink socket in the device monitor still had a
queued uevent.

However, that causes a problem: when udevd receives a flood of uevents,
sigchld and notification events from the workers are postponed. As a
result, the queued events may not be processed during the flood, and
udevd's memory consumption keeps increasing.

Let's lower the priority of these events again. To avoid removing the
queue file while a uevent is still pending on the netlink socket, check
whether the event source corresponding to the device monitor is pending.

Follow-up for 905a89a219.
Fixes #43865.

(cherry picked from commit bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398)
2026-10-16 11:36:33 +01:00
Zbigniew Jędrzejewski-Szmek dfdcaaa269 meson: use -static-pie instead of -static in PIE mode
If compiling with -Db_pie=true, we should do PIE compilation (position
independent executables), even in the static mode.

The caveat is that people distributions actually override compilation
flags when doing their builds. They'll need to set the static flags
properly if they do such builds.

(cherry picked from commit 8b289a8c4d9e2f69a2c10d109c1c19f353005047)
2026-10-16 11:36:33 +01:00
Daan De Meyer b7ae93f093 stat-util: fix null_or_empty_path_with_root() below a root
null_or_empty_path_with_root() passes a path that already includes the root
to chase_and_stat() with CHASE_PREFIX_ROOT, so the root is added twice. It
also only recognizes /dev/null when the path itself is /dev/null. Below a
root, a symlink to an empty file therefore fails with ENOENT. A symlink to
/dev/null fails the same way when the image has no /dev/null. Resolve the
symlink inside the root without requiring the target to exist, and stat the
target through the O_PATH fd that chase() returns.

chase() accepts ret_fd together with CHASE_NONEXISTENT and sets the fd to
-EBADF when the target is missing. Its comment says that ret_fd cannot be
combined with CHASE_NONEXISTENT. Fix the comment.

(cherry picked from commit f2b0c29597466bdcc800dcfa8da4c8192fb9e824)
2026-10-16 11:36:33 +01:00
cksrb63 5f73eab263 docs: fix stale links
(cherry picked from commit 26bde2b760ade0f73d3fbe90d12a492c1a5348ba)
2026-10-16 11:36:33 +01:00
Jonghyun An db049fc898 ukify: include the invalid value in boolean errors
The invalid-boolean error contains a literal f-string prefix and
placeholder, hiding the value that failed to parse. Format the message
to include the rejected value.

(cherry picked from commit aeef38045e74dc585088a64c601166f989705d75)
2026-10-16 11:36:33 +01:00
Siteshwar Vashisht e9ba92f7f0 tpm2-util: TPM2_PCR_MASK_VALID() should take 64-bit parameter
... as some of the fields like `pcr_mask` field of `struct
tpm2_credential_header` that are passed to this function are 64-bit.

(cherry picked from commit de827820240d56a142aea7a2b012121a8869282d)
2026-10-16 11:36:33 +01:00
Siteshwar Vashisht 32cfe286c9 creds-util: fix validation check for TPM2 PCR mask
... field on big-endian architectures.

(cherry picked from commit 542c3cd97a7a1a7f4d29cec2afabc431be2d651e)
2026-10-16 11:36:32 +01:00
Siteshwar Vashisht 066824ae71 udev-rules: fix remaining buffer size calculation
... in `attr_subst_subdir()`.

`strnpcpy_full()` returns space left in the buffer. Its return value
should be directly used instead of being subtracted from buffer size.

(cherry picked from commit d5b4357f8f1829608b3a5b641bb97e480a45a2c3)
2026-10-16 11:36:32 +01:00
Siteshwar Vashisht 3e069f1c23 nspawn-bind-user: fix logging an error message
... in `write_membership()` function.

Log the actual error message returned from `chase_and_open()`.

(cherry picked from commit 513e4b9947c619e2ecfe79c0e81d6461dc65480c)
2026-10-16 11:36:32 +01:00
Siteshwar Vashisht 7d433629cf logind: fix one-byte buffer overflow
... in `inhibit_what_to_string()`.

Add missing colon with `handle-reboot-key`.

(cherry picked from commit 458c5ce35cf9c2057d4516b0298b83c84118b75d)
2026-10-16 11:36:32 +01:00
Siteshwar Vashisht ea634edbb5 core/dbus-unit: fix returning on "JobTimeoutUSec"
branch in `bus_unit_set_transient_property()`.

(cherry picked from commit 041e70d7f70372f06e1651a6f2dfd82fa2a13b8e)
2026-10-16 11:36:32 +01:00
Armaan Sandhu f41defc034 report: make report-files listing and lookup agree on masked entries
The metric list is built with conf_files_list_strv(), but each metric's
value is then looked up again by walking report_files_dirs[] by hand,
and the two disagreed whenever an earlier directory had an entry that is
not a regular file:

 - conf_files_list_strv() skipped such an entry and listed the one from
   a later directory, so the metric was advertised by Describe();
 - file_metric_generate() only moved on to the next directory on
   -ENOENT, so it hit the non-regular entry, logged a warning and
   produced nothing.

The practical case is masking a vendor-supplied entry with a symlink to
/dev/null: the metric kept being described, was never listed, and every
scrape logged "Failed to open ..., skipping: File descriptor in bad
state".

Honour masks in the enumeration via CONF_FILES_FILTER_MASKED_BY_SYMLINK,
as other conf dirs do, and make the lookup skip non-regular entries the
same way the enumeration does. Document the masking in the man page and
cover both cases in TEST-74-AUX-UTILS.report.

(cherry picked from commit 08be8677539642f45c6127085283cf08b6a410b7)
2026-10-16 11:36:32 +01:00
flixman f9b52a6be3 Implement fallback for cmdline in ukify installation
Added fallback for cmdline if not provided in config.

(cherry picked from commit 1e098a4b34c68e9b1878efb9d7c1b56a2c220619)
2026-10-16 11:36:32 +01:00
nikstur aba5c2df8e taint: don't taint if /bin, /usr/sbin, /var/run don't exist
It doesn't make sense to taint a system if these fails don't exist.

A missing /usr/sbin for example doesn't indicate an unmerged-bin.
Indeed, if you have no /usr/sbin but only a /usr/bin you have a
perfectly merged bin.

(cherry picked from commit 419cf189d05e0903a233d13db444586cfb2aaf16)
2026-10-16 11:36:32 +01:00
Martin Pitt a9868c9800 vmspawn: actually enable io_uring for disks
vmspawn never used `aio=io_uring` for disks, even when QEMU supports it.
Commit 1a7b6fd9dd added a blockdev probe node named `__io_uring_probe`.
QEMU rejects that name ("Invalid node-name"), as node names have to
start with a letter. The probe then reported io_uring as unsupported.

Use a valid name, following the "vmspawn-" prefix of the other node names.
Check the multi-drive test's debug log for rejected node names to catch
this and similar issues in the future.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 9c582182e1ae1e38b7ec2dca29bb279cae83e69b)
2026-10-16 11:36:32 +01:00
Daan De Meyer e7dc2168e7 install: Pass in root prefixed path where needed
The lookup paths are root prefixed in this function, so we need to
pass in the root prefixed path as well to make sure path_is_generator()
does the right thing.

(cherry picked from commit fd6984e2d67fccf54ecf29a3d311e2486423cb98)
2026-10-16 11:36:32 +01:00
Daan De Meyer 3d267223ea systemctl: honour --root= in "is-enabled --full"
We have a root argument, let's make sure we honour it
in this case.

(cherry picked from commit b231b43ff0c3a4b951e45567474052885cad52d3)
2026-10-16 11:36:32 +01:00
Daan De Meyer c74e3aa5b7 install: preset in the scope the caller asked for
unit_file_preset() and unit_file_preset_all() zero-initialized their
install contexts, so their scope was always RUNTIME_SCOPE_SYSTEM. In
the global scope, specifiers in [Install] were then resolved as if for
the system: %U became 0 and a unit got enabled into
target-0.target.wants/. Set the scope the caller asked for, so that
this fails with -EUNATCH instead.

Covered by a new test that presets a unit using %U in the global
scope, with both functions.

(cherry picked from commit 0a4491ef3fce30d31a35c95031c8026a0235e0a2)
2026-10-16 11:36:32 +01:00
Daan De Meyer d14b9ace0c specifier: return -EUNATCH for user and group specifiers in global scope
%u, %U, %g and %G have nothing to resolve to in the global scope, and
failed with -EINVAL. Install code already treats -EUNATCH as "cannot
resolve specifiers": it is listed in ERRNO_IS_NEG_UNIT_ISSUE() and
install_change_dump_error() turns it into a proper message. With
-EINVAL, "systemctl --global enable" of a unit using these specifiers
only reported "Invalid argument".

Return -EUNATCH instead, like the machine-id and os-release
specifiers already do when their source is missing. Only the install
code uses these specifiers in the global scope.

(cherry picked from commit 03ce9bcff23d07751dc6911c7963e3bde9e780c2)
2026-10-16 11:36:32 +01:00
Daan De Meyer cb8fffda7d core: drop the dependency dropin name from the mask log line
The log line reported the file name of the masked dependency symlink, except
that entry is not assigned and is NULL at that point.

(cherry picked from commit 6e6114dd6cafb8d7c9585cf1d4ee58866db42d99)
2026-10-16 11:36:32 +01:00
Kai Lüke 9f00584fc3 test: Cover sysext/confext ordering
The ordering matters at unit startup and when we refresh on updates.
For now, just add a test for the update refresh ordering.

(cherry picked from commit 3bebfc9d85144ffe375ae076a2ba5cf58ade4284)
2026-10-16 11:36:32 +01:00
Kai Lüke efa8139061 sysext: refresh confexts before sysexts on sysupdate notifications
The extension refresh on update did sysext first and then confext but
the units until the previous commit didn't have any ordering. Since it
makes sense to first merge configuration and then the service that might
be influenced by that configuration, this ordering was chosen for the
unit startup path.
Align the update refresh order with the unit startup order.

(cherry picked from commit 2d5e73a485f892059e12d95ef69964bd40d04457)
2026-10-16 11:36:32 +01:00
Kai Lüke 0eee5712fd sysext: Order sysext unit after confext to provide guarantees
Up to now there was no clear ordering of confext and sysext units.
Normally, configuration should be able to influence the behavior of
services (config files or unit drop-ins), so it makes sense to order
confext before sysext. The mounting from the initrd for the final system
makes this less important together with the fact that live merges/
refreshes can encode unit restarts now. Yet I think it's better to know
what gets merged first and if wanted one can avoid encoding restarts if
one doesn't care about later live content changes. Where it matters more
for me is consistent behavior for the refresh check during boot for
non-verity images because they get compared by file handle and mount ID
which means whether the overlay was set up or not determines the
identity and decides if we do a refresh or not and this should not
vary by boot merely due to timing or other dependencies impacting the
ordering. (Note that one extension type shipping another extension type
is not the reason for the ordering and these cycles should be avoided
because they never free the mounts and backing loop devices.)

(cherry picked from commit 7197b862b2a132ea044fed59d914d5eb3e8ae9dd)
2026-10-16 11:36:32 +01:00
WilliButz fdd193ff22 docs: mention LoaderInfo efivar in BLI
(cherry picked from commit cfb11e1feb3c944fb0274c8a326a55b406f09582)
2026-10-16 11:36:32 +01:00
iacopo 5274598b37 man: fix sd_bus_destroy_t return type
(cherry picked from commit 4e7b8f2282430dfb6bac570a908ce47041af8d26)
2026-10-16 11:36:32 +01:00
SecretLUL 29646b6f1c journal-file: don't zero freshly allocated hash tables
The hash tables are only ever set up in newly created journal files, in
space that was just allocated via posix_fallocate() and hence reads as
zeroes anyway, so zeroing the items explicitly is unnecessary.

It is also harmful: the sequential write faults of the memzero() make the
kernel's mmap readahead instantiate the table in ever larger folios, up to
the size of the readahead window, on file systems that support large folios
in the page cache (e.g. XFS, and ext4 since kernel 6.16). And since write
faults on shared file mappings dirty the whole folio, each later update of
a single 16 byte hash bucket then has the whole folio written back. Without
the explicit zeroing, the table's pages are only faulted in when buckets
are first accessed, in random order, and hence mostly as order-0 folios.

Measured on Linux 6.18 with a new journal file (SystemMaxFileSize=50M),
appending 15 syslog-like entries with 23 fields each per second for 120s,
while writing back the file's dirty pages every second, as happens on
machines under page cache pressure, where reclaim keeps waking up the
flusher threads. Bytes written to the (loop) device, median and range of
4-5 runs:

          before                    after
  ext4    182.8M (178.4M-185.7M)    41.2M (31.6M-41.9M)
  xfs     172.7M (161.0M-182.4M)    40.1M (39.7M-44.9M)

This also avoids writing out the whole data hash table once for every new
journal file, i.e. ~2.8% of the maximum file size.

Related: #40262
(cherry picked from commit 6db7cf38d40e8fe6a11392d2f0cc044ed5acf812)
2026-10-16 11:36:32 +01:00