[SRU][R][PATCH 0/1] linux: dtbs_install fails on Resolute builders due to uutils install(1) EEXIST race under parallel make (LP: #2166356)
Edoardo Canepa
edoardo.canepa at canonical.com
Thu Sep 3 13:55:17 UTC 2026
BugLink: https://bugs.launchpad.net/bugs/2166356
SRU Justification
[Impact]
Kernel source package builds for Resolute (26.04) fail intermittently
during dtbs_install on Launchpad builders. The failure surfaces as:
INSTALL .../device-tree/nuvoton/ma35d1-iot-512m.dtb
INSTALL .../device-tree/nuvoton/ma35d1-som-256m.dtb
INSTALL .../device-tree/nuvoton/nuvoton-npcm845-evb.dtb
install: cannot create directory '.../device-tree/nuvoton'
make[4]: *** [scripts/Makefile.dtbinst:23:
.../nuvoton/ma35d1-iot-512m.dtb] Error 1
The root cause is a race in the rust-coreutils implementation of
install(1), which provides /usr/bin/install on Resolute. In uutils'
`install -D`, parent-directory creation is done by stat_at() followed
by mkdir_at() without retry: two concurrent invocations sharing a
parent both observe NotFound before either issues mkdir_at(), the
loser then receives EEXIST from the kernel and uutils bubbles it up
as a hard error instead of treating an existing directory as success.
scripts/Makefile.dtbinst hard-codes literal `install -D -m 0644`,
one invocation per .dtb file:
quiet_cmd_dtb_install = INSTALL $@
cmd_dtb_install = install -D -m 0644 $< $@
Under `make -j`, every .dtb inside a given vendor directory (e.g.
device-tree/apple/, device-tree/nuvoton/) races on that directory's
creation, and the build fails non-deterministically.
Impact:
- Series: Resolute (26.04) only.
- Arches: any that enable do_dtbs=true (arm64, armhf); observed
on arm64 Launchpad builders for linux 7.0.0-37.37.
- Severity: hard build failure, blocks source package uploads.
[Fix]
Serialise the dtbs_install sub-make by forcing `-j1` for that single
target in debian/rules.d/2-binary-arch.mk. All other targets in the
package build ($(bldimg), modules, modules_install, headers_install)
retain full parallelism via $(conc_level).
A tree-side fix is not viable in the SRU timeframe:
- scripts/Makefile.dtbinst hard-codes the literal `install`; there
is no $(INSTALL) variable defined anywhere in the tree to hook.
- Resolute ships no GNU coreutils install(1) that we could point
to via an override even if the recipe were parametric.
- Fixing uutils is out of scope; the upstream fix (uutils/coreutils
PR #12429) is open but unmerged, and will need to land in
rust-coreutils before Resolute can benefit.
The workaround is intentionally minimal and self-documenting: an
inline comment references the uutils issues so it can be reverted
cleanly once #12429 lands in Resolute.
[Test Case]
Reproducer (without the patch):
1. On a Resolute build environment with rust-coreutils providing
/usr/bin/install (default), obtain the linux source package
and run:
dpkg-buildpackage -B -aarm64 -j$(nproc)
2. Repeat 5-10 times. dtbs_install fails intermittently with
"install: cannot create directory '.../device-tree/<vendor>'"
and a non-zero exit from make[4].
Verification (with the patch):
1. Same environment, same command. Run 10 consecutive builds.
None fail in dtbs_install.
2. Confirm the resulting linux-image-* package contains the full
set of .dtb files under
usr/lib/firmware/<abi>-<flavour>/device-tree/
matching the pre-patch layout (diff of installed file lists).
3. Wall-clock delta for dtbs_install between $(conc_level) and -j1
is under 10s on a Launchpad builder (I/O-bound, short target).
Additionally, a successful Launchpad rebuild of the affected source
(linux 7.0.0-37.37) with the patch applied is the definitive test.
[Where problems could occur]
The change is one line: swap $(conc_level) for -j1 on the single
`$(kmake) ... dtbs_install` invocation in
debian/rules.d/2-binary-arch.mk. Scope of risk:
- Build time: dtbs_install runs serially. In practice this is a
few seconds on arm64/armhf; the target is I/O-bound.
- No other build stage is touched; all other sub-makes still run
at $(conc_level).
- No change to compiler flags, config, ABI, module layout,
installed artefacts, or package contents.
- No effect on arches with do_dtbs != true (e.g. amd64), where
the guarded block is not entered at all.
- No runtime effect on end users; the change is confined to
package build.
If regressions do occur, they would manifest at build time (not on
target systems) and can be reverted trivially by restoring
$(conc_level).
[Other Info]
Upstream uutils references:
- uutils/coreutils#12355 — install -D loses some files to EEXIST
- uutils/coreutils#12429 — install: fix EEXIST race losing files
in parallel install -D (open PR)
This is a SAUCE patch (packaging-only, no upstream analogue) tagged
appropriately in the subject. It should be dropped when uutils
PR #12429 is merged and lands in Resolute's rust-coreutils; the
revert is a one-line change to restore $(conc_level).
More information about the kernel-team
mailing list