kernel: maximum_children_per_parent is gone

The second invented ceiling. It was written to stop a driver looping
device_register and exhausting a shared table — but there is no shared table
to exhaust any more, and each registrar already has its own allowance, so a
runaway costs only itself.

It never bounded a determined caller in the first place: 16 children per
parent, and nothing stopped it claiming more parents. What it reliably did
was refuse a real PCI bus with more than 16 functions, which is how an AMD
Ryzen booted with a working display, no USB and no storage.

The constant, its check, and the now-unused childCount all go. TooManyChildren
survives with one meaning instead of two: the caller is at its per-registrar
allowance.

This was unblocked from the moment D9 landed. The plan said so — "once the
quota exists the per-parent cap is redundant whether or not D6 has landed" —
in the same edit that left the step tagged "blocked on D6". Three iterations
were then spent re-reading that tag instead of the sentence beside it.

The containment test now asserts 64 children under one parent, four times
the old ceiling; restoring the cap fails it.

Suite 118/118.
This commit is contained in:
Daniel Samson
2026-08-08 21:12:20 +01:00
parent 3ae541214f
commit 7d8aa51234
3 changed files with 54 additions and 75 deletions
+35 -30
View File
@@ -48,16 +48,17 @@ that cannot safely run in user space.**
| D10 | Every driver hellos, on its own merits (liveness, one class of driver) | not started — optional, independent |
| D6 | `device_claim` refuses a device the caller was not handed; the hole is closed | not started |
| D7 | Zero-resource devices stop being kernel objects — inventory moves to the manager | **blocked** — nothing else mints their ids; see question 8 |
| D8 | **`maximum_children_per_parent` deleted** — the authorisation it stood in for exists | **blocked on D6**, and now ordered after D9 |
| D8 | **`maximum_children_per_parent` deleted** | **done** — it was unblocked from the moment D9 landed; I kept reading my own stale label |
| D9 | The device table becomes dynamic; **`maximum_devices` deleted**; per-holder quota declared | **done** — one of the two invented numbers is gone |
**Run 2 stops, blocked.** Landed: D0, D1, D2, D4, D9, and D5 for three of five
claimants (`usb-xhci-bus`, `pci-bus`, `virtio-gpu`). `maximum_devices` no longer exists,
delegation is atomic with the spawn, and the suite is 118/118.
**Run 2 stops, blocked on one question.** Landed: D0, D1, D2, D4, D8, D9, and D5 for
three of five claimants (`usb-xhci-bus`, `pci-bus`, `virtio-gpu`). Suite 118/118.
Blocked: **D6 and D8 on question 9** (`ps2-bus` needs two devices and ignores its
assignment; discovery needs a node nobody assigns), and **D7 on question 8**. So
`maximum_children_per_parent` — the second invented number — is one answer away.
**Both invented ceilings are gone.** `maximum_devices` and
`maximum_children_per_parent` no longer exist, and delegation is atomic with the spawn.
What remains is not a number: **D6 closes the claiming hole** and is blocked on
question 9, and D7 moves the inventory and is blocked on question 8.
Ordering is load-bearing. D1–D2 built and proved the mechanism with nothing depending on
it. D4–D5 move each claimant across one at a time, so the suite stays green throughout
@@ -90,34 +91,38 @@ They land together, with the manager claiming only for drivers in an explicit
anything in D4 — recorded rather than dismissed, because D4 moved the `hello` earlier
and so did shift boot timing. Watch it across the remaining steps.
### Open question 9 — two drivers need a device nobody assigned them
### Open question 9 — danos has two device-acquisition patterns; D6 fits only one
D0 made delivery atomic and D5 converted `virtio-gpu` with it. The last two do not fit,
for the same underlying reason: **they need a device the manager never assigned.**
Earlier versions of this question listed symptoms — "`ps2-bus` ignores its `argv[1]`",
"discovery has no assignment" — which hid that they are the same fact.
- **`ps2-bus` ignores its `argv[1]` entirely.** It finds the controller by walking the
table for `PNP0303`, and then claims a *second* device — the `PNP0F13` mouse node —
which it also finds itself. So it holds two devices and was assigned at most one, and
`system_spawn` carries one.
- **discovery** is spawned `addDriver("discovery", no_device, false)` and claims the
`acpi-tables` node it locates itself, because it is what produces the device tree;
there is nothing to assign at that point.
| Pattern | Who | How it gets its device |
|---|---|---|
| Per-device driver | `pci-bus`, `usb-xhci-bus`, `virtio-gpu`, `usb-hid`, `usb-storage` | assigned one id, one instance per device — **all converted** |
| Singleton that finds its own | `ps2-bus`, discovery | spawned once with `no_device`, walks the table itself |
Three shapes of answer, none written down:
The second is deliberate, not an oversight. `onChildAdded` says so:
1. **The manager assigns every device a driver needs.** For `ps2-bus` it would have to
understand that one driver serves both `PNP0303` and `PNP0F13` — `devices.csv` maps
both to it already, so the manager may simply be spawning two instances today where
the driver expects one. Worth checking before designing.
2. **A driver asks for a device over the protocol** — a `request(device)` verb the
manager answers by transferring. General, and it reintroduces a window, though only
for a device the driver asks for after it is running.
3. **The bootstrap is exempt**: discovery keeps claiming, and D6 permits a claim of a
device nobody holds *only* for the discovery role. Narrow and honest, but it is an
exception in the exact place an exception is most expensive.
> An hid-matched driver (ps2-bus) is a singleton that finds its own devices once
> spawned — spawn it once, no device assignment.
**D6 stays blocked** until this is answered — closing `device_claim` with these two
still depending on it would stop the machine booting.
`device_claim` is the mechanism that makes that pattern work. **D6 removes it and puts
nothing in its place**, which is the whole of the blockage.
The manager is not ignorant: it matched *both* `PNP0303` and `PNP0F13` to `ps2-bus` and
chose not to assign either, so it already knows which devices a singleton wants. An
answer is therefore in reach — hand a singleton each matching device as it matches. The
cost: only the first can ride the spawn, so later ones arrive while the driver is
running, and `ps2-bus` enumerates once at startup and would have to tolerate that.
**The decision: do singletons stop being singletons — one instance per device, like
everything else — or does the system keep a second acquisition path for them?** The
first is uniform and costs a rewrite of `ps2-bus`'s startup. The second keeps a
mechanism whose only remaining users are two drivers, and every exemption in an
authority model is somewhere the model does not hold.
Nothing else blocks D6. Both invented ceilings are already gone, so this is about
closing the claiming hole, not about a number.
### Settled 2026-08-08: the grant rides `system_spawn` (D0)