Commit fe2733b
committed
simplify(qemu-static): kernel-counted refcount via flock on binfmt entry
Replace ~250 lines of userspace coordination (per-builder owner files in
/run/lock/armbian-native-armhf/owners/, control lock, live-owner counting)
with kernel-level flock on /proc/sys/fs/binfmt_misc/qemu-arm itself.
Why
- The previous design required /run/lock to be a host-bind-mount into
every build container, which the current Armbian docker setup does
NOT do, defeating the cross-container coordination it was built for.
- Five race rounds with Codex accumulated complexity for an edge case
the standard Armbian CI matrix does not exercise (one runner per
matrix entry, so kernel state is per-runner, no cross-container
coordination needed).
- A kernel-counted refcount is what we actually need; flock(2) provides
it directly on the very kernel object we're coordinating around.
How
- Each build holds LOCK_SH on /proc/sys/fs/binfmt_misc/qemu-arm via a
long-lived fd. Kernel BSD-flock counter is the refcount; the kernel
releases the fd on process exit (crash-safe). No per-builder lockfiles,
no shared state files, no /run/lock directory tree, just a flock on
the kernel object itself.
- First-arrival idempotently echoes 0 to disable. Subsequent arrivals
observe state==0 and proceed without writing.
- On exit, release LOCK_SH; last-out detects via LOCK_EX-LOCK_NB on a
fresh fd to the same entry, succeeds iff zero other LOCK_SH holders.
The last-out re-enables qemu-arm.
- Builders are fully independent: no shared writeable state, no per-
builder files, no awareness of each other.
Trade-off
Prior qemu-arm state is not recorded across independent builds (no
shared writeable state by design). Last-out unconditionally re-enables.
If an admin deliberately had qemu-arm disabled before any armbian build
started, that policy is lost. Rare in practice (default Ubuntu/Debian
have it enabled), and was not a strongly-preserved invariant in the
earlier implementation either.
Subtle bash gotcha fixed in this revision
exec {fd}< file 2> /dev/null permanently silences the shell's stderr
because exec without a command applies redirections to the current
shell. Every later display_alert (which writes to stderr) was silently
dropped, including from the cleanup handler. Wrap the exec in
{ ...; } 2>/dev/null to scope the stderr suppression to the exec
command alone.
Empirically verified on Hetzner CAX21 (Ubuntu 24.04 kernel 6.8.0-90-generic,
binfmt_misc fs):
- flock LOCK_SH on /proc/sys/fs/binfmt_misc/qemu-arm works.
- LOCK_EX-LOCK_NB while another holds LOCK_SH blocks as expected.
- The entry persists through echo 0 (only echo -1 unregisters).
- Single-tree build emits all 5 phase markers + last-out restore.
- Two independent armbian worktrees concurrent on same host: both enter
native armhf path, kernel SH-counter holds qemu-arm disabled across
both, first-finished's cleanup correctly suppresses restore (EX-NB
blocked by other's SH), last-finished restores qemu-arm to enabled.
Net diff: 397 -> 272 lines (-261 / +136).
Assisted-by: Claude:claude-opus-4.71 parent ca4b442 commit fe2733b
1 file changed
Lines changed: 136 additions & 261 deletions
0 commit comments