docs(init-nsmgr): add co-victim audit — acpid was the only active trigger
Systematic audit of all 18 scheme-serving daemons for the acpid failure
class (single-threaded daemon that can wait unboundedly in its serving
thread). Findings recorded in INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md:
- acpid was the ONLY software unbounded wait in the boot-critical path
(fixed). No other boot-path handler has an unbounded software wait or a
reentrant blocking open of another scheme.
- Hardware busy-waits (rtcd/ps2d/audio/gpu register polls) are
hardware-bounded or in daemons pcid does not spawn without the device.
- ucsid is the one remaining co-victim: it reads /scheme/acpi in
build_state() before publishing its scheme and is the only blocking,
acpi-dependent boot unit in redbear-mini. It already degrades on EAGAIN
and works with acpid fixed. It must NOT be flipped to oneshot_async
(that breaks ucsi scheme registration, which init performs via the
{scheme=…} type); the correct hardening is a source refactor
(publish-then-discover), done with runtime validation, not blind.
This commit is contained in:
@@ -76,6 +76,37 @@ via `lseek(0)`+`read`. A per-open trace in `initnsmgr` (to a debug fd from
|
||||
`UPPER_FDTBL_TAG + GlobalSchemes::Debug`) pinpointed the wedged open as `acpi:processor/CPU3/pss`
|
||||
(then, post-fix, `display.vesa:v2/2`).
|
||||
|
||||
## Co-victim audit (2026-07-21): other daemons on the same chain
|
||||
|
||||
A systematic audit of all 18 scheme-serving daemons for the acpid failure class (a single-threaded
|
||||
daemon that can wait unboundedly in its serving thread) found:
|
||||
|
||||
- **acpid was the only *software* unbounded wait** in the boot-critical path (the AML mutex bug —
|
||||
fixed). No other boot-path scheme handler contains an unbounded software wait or a reentrant
|
||||
blocking open/read/call of another scheme.
|
||||
- **Hardware busy-waits** (`rtcd` RTC UIP bit, `ps2d` PS/2 `OUTPUT_FULL`, `sb16d`/`ihdad` DSP/RIRB,
|
||||
`ihdgd`/`ahcid`/`nvmed`/`bcm2835` register polls) are either hardware-bounded (the bit clears in
|
||||
microseconds) or live in daemons that pcid does not spawn without the matching device (no audio on
|
||||
QEMU q35, etc.). Not the acpid class. (They are still a robustness item under the project WARNING
|
||||
POLICY — unbounded on paper — but adding timeouts to ~15 sites blind, without a reproducing hang,
|
||||
risks regressions and is out of scope here.)
|
||||
- **`ucsid` is the one remaining co-victim worth noting.** It consumes `/scheme/acpi/*` in
|
||||
`build_state()` *before* it publishes its scheme, and in `config/redbear-mini.toml` it is the only
|
||||
boot-critical, acpi-dependent unit with a **blocking** init type (`type = { scheme = "ucsi" }`,
|
||||
while every other acpi consumer there is `oneshot_async`). Before the acpid fix, a stalled acpid
|
||||
would have hung ucsid's init and thus boot. It already degrades gracefully on `EAGAIN`
|
||||
(`discover_ucsi_devices` returns empty), but `EAGAIN` only covers "acpid is busy", not "acpid is
|
||||
wedged" (open blocks, per the kernel corollary below). With acpid fixed it works.
|
||||
|
||||
**Do not simply flip ucsid to `oneshot_async`** to satisfy the "optional hardware must not block
|
||||
boot" rule (`bare-boot-blocking-init-units`): `ready_sync_scheme` hands the scheme cap fd to init
|
||||
via the INIT_NOTIFY pipe (`daemon/src/lib.rs:130` → `ready_with_fd`), so init registers the `ucsi`
|
||||
scheme *on the daemon's behalf* — only the `{scheme=…}` init type does that. `oneshot_async` would
|
||||
leave `ucsi` unregistered (consumers get `ENODEV`). The correct hardening is a source refactor:
|
||||
publish the scheme immediately with a lazy/empty state, then run the heavy ACPI/i2c discovery in
|
||||
the background after `ready_sync_scheme`. It is defense-in-depth against an already-fixed trigger,
|
||||
not an active bug, so it must be done with runtime validation, not blind at session end.
|
||||
|
||||
## The kernel corollary — `open` ignores `O_NONBLOCK`
|
||||
|
||||
The manager cannot even *defer* a slow open today, because in Redox an `open()` with `O_NONBLOCK`
|
||||
|
||||
Reference in New Issue
Block a user