establishment: a reporter's death reaps its subtree, and the re-report rebuilds it

P3 of docs/establishment-planes-plan.md — the restart-zombie fix. A class
driver cannot observe its provider's death: an HID driver blocks on
interrupt reports that will simply never come, and storage answers its
callers with refusals forever. Worse, the dead generation's still-used
entries made the matcher's dedupe refuse the respawn when the restarted bus
re-reported — the subtree was a permanent zombie, which is the exact
opposite of the restart-a-driver-live goal the driver model exists for.

pruneChildrenOf now reaps: each pruned child's bound driver is killed and
its entry cleared (the exit notification finds no entry, so the death is
never double-counted; its device returns by the loan rule; its stored
endpoint handle is closed). The re-report then spawns a fresh generation
whose hellos fetch the successor's channel.

The usb-report drill now asserts the subtree WORKS after the restart: the
respawned storage opens its device on the NEW bus instance and reads block
0. Discrimination: against the pre-reap manager the drill fails — no reap
line, no post-restart respawn (the survivors were zombies), verified by a
stash run. Note the scenario boots no input service, so the HID drivers of
BOTH generations exit after their input lookup times out — storage is the
functional proof.
This commit is contained in:
Daniel Samson
2026-08-09 12:34:13 +01:00
parent 1d7850239d
commit 8710944a92
2 changed files with 41 additions and 4 deletions
+16 -4
View File
@@ -606,9 +606,17 @@ CASES = [
"smp": 4,
"expect": r"DANOS-TEST-RESULT: PASS",
"fail": r"DANOS-TEST-RESULT: FAIL"},
# M18.2: bus tree reports — the xHCI driver scans its root-hub ports and
# reports both QEMU devices; the manager mirrors, prunes on the reporter's
# death, and the respawned driver re-reports (docs/device-manager.md).
# M18.2 + establishment P3: bus tree reports, and the restart REBUILDING
# the subtree. The manager prunes on the reporter's death — reaping the
# class drivers bound to the pruned children, which hold channels into the
# dead process and cannot observe the death themselves — and when the
# respawned instance re-reports, the matcher spawns fresh class drivers
# whose hellos fetch the successor's channel. The tail asserts the subtree
# WORKS again: the respawned usb-storage opens its device on the NEW bus
# instance and reads block 0. (The HID "ok" lines never appear in this
# scenario — it boots no input service — so storage is the functional
# proof.) Before the reap existed, the stale entries blocked the respawn
# and the survivors were silent zombies, so this tail could not match.
{"name": "usb-report",
"smp": 4,
"timeout": 150,
@@ -617,9 +625,13 @@ CASES = [
"expect": r"device-manager: child added[\s\S]*"
r"device-manager: child added[\s\S]*"
r"device-manager: test mode: killing the reporter[\s\S]*"
r"device-manager: reaping \S*usb-storage[\s\S]*"
r"device-manager: child removed[\s\S]*"
r"device-manager: restarting \S*usb-xhci-bus[\s\S]*"
r"device-manager: child added",
r"device-manager: child added[\s\S]*"
r"device-manager: delegated device \d+ to /system/drivers/usb-storage[\s\S]*"
r"usb-storage: ready[\s\S]*"
r"usb-storage: block 0 signature 0x55aa",
"fail": r"DANOS-TEST-RESULT: FAIL"},
# USB HID end to end: boot the full tree, enumerate the xHCI, and let the
# manager spawn the USB keyboard driver, which opens its device over the