Conversation
…service rechunker-group-fix.service is ordered Before=systemd-sysusers.service (since projectbluefin#530) but also Wants=/After=local-fs.target. systemd-sysusers is ordered before systemd-tmpfiles-setup-dev.service < local-fs-pre.target < local-fs.target, so the unit closes an ordering cycle on every boot: Found ordering cycle on systemd-sysusers.service/start; has dependency on rechunker-group-fix.service/start, local-fs.target/start, local-fs-pre.target/start, systemd-tmpfiles-setup-dev.service/start systemd breaks it by deleting whichever job it reaches first, so the outcome is per-boot nondeterministic: systemd-udevd (90 s device timeouts, /var never mounted), systemd-sysusers, local-fs-pre.target, or systemd-ask-password-console.path (LUKS volumes never unlocked after the initrd hands over). Measured on ghcr.io/projectbluefin/bluefin-lts:stable with `systemd-analyze verify --generators=yes` over default, multi-user, graphical, cryptsetup and the unit itself: 16 cycle lines before, 0 after. Order the unit exactly like systemd-sysusers.service and bootc-sysusers-shadow-sync.service instead: After=systemd-remount-fs.service (so /etc is writable), After=bootc-sysusers-shadow-sync.service, Before=systemd-sysusers.service. Drop the trailing systemd-tmpfiles pass: the unit now runs before local-fs-pre.target, where /var and /tmp are not mounted and the pass exits 65, and systemd-tmpfiles-setup.service runs the same command after local-fs.target and sysusers anyway. Tests: a static ordering-contract check plus a `systemd-analyze verify --root=` run over a minimal fixture of the stock early-boot units, which reports the cycle for the previous unit and nothing for this one. Closes projectbluefin#918 Refs projectbluefin/bluefin-lts#628, projectbluefin/bluefin-lts#585, projectbluefin/bluefin-lts#466, projectbluefin/bluefin-lts#391 Assisted-by: Claude Opus 5 (Claude Code) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0114TUzBMEH13zPa2VVYwLdW
castrojo
left a comment
There was a problem hiding this comment.
Reviewed diff and verified ordering contract. Dropping Wants=/After=local-fs.target removes the boot ordering cycle on systemd-sysusers. Fixes projectbluefin/bluefin-lts#628 and common#918.
castrojo
left a comment
There was a problem hiding this comment.
LGTM, approving as second review to satisfy ruleset.
Scope correctionThis PR was opened as the fix for projectbluefin/bluefin-lts#628. It most likely isn't. What changed: the reporter posted console output from the failing boot. It fails inside the initrd, before any of the units this PR touches ever run: Current theory (not yet confirmed): the Fedora What this means for this PR:
|
|
This is actually a little interesting...if true its exactly the kind of thing that could bite on an LTS version because it ships something different. |
castrojo
left a comment
There was a problem hiding this comment.
LGTM: verified drop of Wants=/After=local-fs.target eliminates the ordering cycle on systemd-sysusers. CI checks green.
Pull request was closed
The bug
rechunker-group-fix.serviceships from here intobluefinandbluefin-lts, and it declares two things that cannot both be true:Before=systemd-sysusers.serviceWants=/After=local-fs.targetWalking the stock edges between those two points shows why:
So every boot of a consuming image opens with an ordering cycle.
Why the symptom is a coin toss
systemd breaks a cycle by deleting whichever job in the loop it reaches first, and that choice varies per boot and per image. Depending on the victim you get:
systemd-udevd/varnever mounts, no home directoriessystemd-ask-password-console.pathsystemd-sysuserslocal-fs-pre.targetOne defect, several bug reports that look unrelated: projectbluefin/bluefin-lts#585, projectbluefin/bluefin-lts#466, projectbluefin/bluefin-lts#391 and #918.
Confirmed on real hardware since this PR was opened — the reporter in bluefin-lts#628 posted a journal from their own machine showing the cycle with yet another victim (the ESP's fsck job):
The change
1. Order the unit the way its neighbours are ordered. Match
systemd-sysusers.serviceand bootc's ownbootc-sysusers-shadow-sync.service:No
local-fs.targetedges at all. Thesystemd-remount-fs.serviceanchor answers the "is/etcwritable yet?" question raised in the #921 review — it is the same precondition sysusers itself relies on to write/etc/passwd.2. Drop the trailing
ExecStart=systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev. With the unit now running beforelocal-fs-pre.target,/varand/tmpare not mounted yet and that pass exits 65 on every single boot — this is therechunker-group-fix.servicefailure line in everyujust report, and what @fabsah and @jlbauss were seeing. Nothing is lost by removing it:systemd-tmpfiles-setup.serviceruns the identical command later, afterlocal-fs.targetand aftersystemd-sysusers.service, i.e. after the groups repaired here exist.3. Document the boundary in
docs/skills/submodule-boundary.md, specifically why a downstream drop-in cannot fix this. systemd cannot resetAfter=orWants=from a drop-in, andAfter=with an empty value is a no-op for dependencies (verified withsystemctl show -p Afteron systemd 259). So the bluefin-lts#527 / bluefin-lts#603 style drop-ins only manage to addBefore=local-fs-pre.target, producing a tighter cycle than the one they were meant to break.Regression coverage
tests/test_rechunker_group_fix.batsadds three tests:local-fs*.targetedges, nosystemd-tmpfilesExecStart.systemd-analyze verify --root=<fixture> default.targetover a minimal fixture of the stock early-boot units (systemd-remount-fs,systemd-sysusers,systemd-tmpfiles-setup-dev,systemd-udevd,local-fs-pre.target,local-fs.target,sysinit.target). This lets systemd itself compute the boot transaction, and asserts noordering cycle/deleted to breakoutput.After=local-fs.targetto a copy of the fixture and asserts systemd does report the cycle, so test 2 cannot silently pass on a broken fixture.Run on Ubuntu 24.04 / bats 1.10 / systemd 255 (the CI runner environment):
Validation performed
Tests and linters
bats tests/test_rechunker_group_fix.bats— 10/10 pass (Ubuntu 24.04 container, systemd 255). Tests 8–9 fail against the unit onmain.shellcheckon the script and the bats file;just check;git diff --check.scripts/check-doc-links.sh,check-skill-index.sh,generate_skill_index.py --check— all clean.Against the real consumer image
ghcr.io/projectbluefin/bluefin-lts:stable(amd64sha256:33ba155b…, kernel 7.1.8-200.fc44, systemd 257-33.el10), in a container with an Anaconda-style/etc/fstab+/etc/crypttabfor a LUKS root. Ransystemd-analyze verify --generators=yesoverdefault.target,multi-user.target,graphical.target,cryptsetup.targetandrechunker-group-fix.service:ordering cyclelinesAs shipped, one of those cycles runs through
cryptsetup.targetand deletes the LUKS password agent, which would leave any encrypted volume that still needs unlocking after switch-root without a prompt:For comparison, the bluefin-lts#527/#603 drop-in measured in the same image: 14 cycle lines, versus 10 for the same anchor set without it — including
Job local-fs.target/start deleted.Not performed
systemd-analyze verify) run against the real image's unit set, plus the bats fixture. A lab boot of a consuming image — ideally an upgrade from a legacy rechunked image with a LUKS root, as in bluefin-lts#585 — is still needed before promotion, per the warning in the unit header.pre-commit run --all-filesandactionlintwere not run locally (not installed). The individual hook scripts listed above were run directly.Closes #918
Refs projectbluefin/bluefin-lts#628 (scope corrected — not fixed by this PR)
Refs projectbluefin/bluefin-lts#585 projectbluefin/bluefin-lts#466 projectbluefin/bluefin-lts#391
🤖 Generated with Claude Code
https://claude.ai/code/session_0114TUzBMEH13zPa2VVYwLdW