diff --git a/local/docs/INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md b/local/docs/INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md index 6f8d03e50b..f3a98e42d3 100644 --- a/local/docs/INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md +++ b/local/docs/INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md @@ -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`