Five daemon-local hardening items on top of the AML-mutex fix. acpid is
single-threaded and serves the `acpi` scheme on the same thread that
evaluates AML, so any way it can stall or die stalls or kills every
consumer. These reduce or bound each such way (verified against
local/reference/linux-7.1 ACPICA):
- stall(): refuse >255us and warn >100us instead of an unbounded CPU
busy-spin on the serving thread (ACPICA exsystem.c:129-147). The spec
caps Stall at 100us; a long busy-spin here would delay scheme requests.
- AML mutex release(): a release of a not-currently-held mutex, or by a
non-owning thread, is now logged (ACPICA AE_NOT_ACQUIRED / owner
mismatch, exmutex.c:287,376) rather than silently decrementing depth.
- Static processor-method cache: _PSS/_PSD/_CST/_CPC are fixed after boot
but cpufreqd polls them; cache the first evaluation so later reads never
re-run the AML interpreter under the global lock. Removes acpid's
dominant recurring head-of-line source. Dynamic methods are not cached.
- Panic-free scheme path: every release_global_lock().expect(...) on the
AML-evaluation path is now log-and-continue, and a result.ok()?.unwrap()
that panicked on Ok(None) (absent method) is now `?`. A scheme-daemon
panic kills the `acpi` scheme and wedges every consumer.
- Observability: log AML evaluations >=50ms and mutex-acquire timeouts —
the early-warning signal before a stall becomes a wedge.
Context: the residual under-load boot wedge is NOT in acpid (a mutex-only
baseline wedges identically under load); it is head-of-line blocking in
the single-threaded initnsmgr. See
local/docs/INIT-NAMESPACE-MANAGER-SCALABILITY-PLAN.md and
local/docs/INITNSMGR-CONCURRENCY-DESIGN.md.
The AML mutex `acquire` handler had two defects that let a routine
`_ACQ` on ACPI processor P-state objects (`processor/CPUn/pss`, opened
by cpufreqd) deadlock acpid permanently:
1. Timeout units. ACPI `_ACQ` timeouts are milliseconds and 0xFFFF is
the spec's "wait forever" (ACPICA ACPI_WAIT_FOREVER,
actypes.h:459). The code multiplied the value by 1000, treating it
as seconds, so 0xFFFF became ~18 hours.
2. No ownership. ACPI mutexes are recursive: the owning thread may
re-acquire, each Acquire paired with a Release (ACPICA
acpi_ex_acquire_mutex_object, exmutex.c:140). The old code tracked
only a "held" set with no owner, so a nested acquire by the single
AML thread waited for a release only it could perform — a
self-deadlock.
Because acpid is single-threaded and the same thread serves the
`acpi` scheme socket, a stuck acquire stops acpid answering scheme
requests. The init namespace manager then blocks in the openat it was
proxying, and — since every restricted-namespace path resolution goes
through that single manager — the whole system's open path wedges
(observed: mini never reaches a usable brush login).
Fix: track (owner ThreadId, recursion depth) per mutex, treat a
nested acquire by the owner as a depth bump, interpret the timeout as
milliseconds, and bound any wait to MAX_MUTEX_WAIT (5s) so a
misbehaving AML method can never freeze the scheme-serving thread.
The suspend_to_ram, read_battery_status, and read_battery_info methods
were incorrectly placed inside 'impl Drop for PhysmapGuard'. They
reference fields (aml_symbols, fadt) that only exist on AcpiContext.
Move them to impl AcpiContext and fix field access (self.fadt.as_ref()
instead of self.fadt()).
Per local/docs/PATCH-PRESERVATION-AUDIT-2026-07-12.md the base
fork was carrying only 38 of 100 patches in local/patches/base/.
The other 62 patches' content was silently missing from the fork
working tree, even though their .patch files were preserved.
This commit re-applies 41 patches that genuinely still apply
cleanly + 17 hunks that partially applied. Recovery covers:
- D-Bus initfs service wiring (P4-initfs-dbus-services)
- USB service wiring (P4-initfs-usb-drm-services)
- netcfg/dhcp/dhcpv6 driver fixes
- acpid shutdown/PM/quirk fixes
- inputd/ps2d hard-fail logging
- pcid driver interface refinements (server cmd channel)
- virtio-core for VirtualBox support
- ixgbed/rtl8139/rtl8168 net drivers
- ahcid NCQ + per-function interrupt coalescing
- logd persistent logging
- bootstrap procmgr race-condition fixes
- cargo version pin to +rb0.3.0 (synchronized release branch)
58 files changed, +1444/-318 lines.
Untracked mnt/ tree and *.orig / *.rej files cleaned up after
patch application (leftover from absolute-path patch headers).
Otherwise, an open call to /scheme/acpi/tables will result in nsmgr
blocking on an `openat(acpi_root, "tables")` call, which will never
occur if acpid is itself blocking on a `ForkNs` call to nsmgr before it
can serve any scheme requests.