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:
@@ -53,22 +53,6 @@ const heap = @import("heap.zig");
|
||||
/// found against registered)
|
||||
const maximum_devices_per_registrar = 4096;
|
||||
|
||||
/// Cap on children a single parent may have. A zero-resource child (legal — a USB
|
||||
/// device is addressed through its controller, not by MMIO) sidesteps the containment
|
||||
/// check, so without a bound a process that claimed one device could loop
|
||||
/// `device_register` and exhaust the whole table, permanently denying it to every other
|
||||
/// driver. This bounds the blast radius of one claim; a real quota (and a
|
||||
/// `device_release` to reclaim on exit) is future work — see docs/driver-model.md.
|
||||
///
|
||||
/// bound: children one claimed parent may register — in practice every PCI function on
|
||||
/// the machine, since pci-bus registers them all under the one host bridge
|
||||
/// decided-by: hardware
|
||||
/// protects: the shared device table, against a driver looping device_register — but
|
||||
/// it is a proxy for an authorisation the kernel does not perform, since any
|
||||
/// process may claim any unclaimed device (docs/bounds-track-plan.md phase 2)
|
||||
/// at-limit: refuse — ECHILDREN, distinct from a full table
|
||||
/// observed-by: pci-bus logs the reason per refused function, and warns at end of scan
|
||||
const maximum_children_per_parent = 16;
|
||||
|
||||
/// The table, grown on demand from the kernel heap. **There is no ceiling**: how many
|
||||
/// devices a machine has is the machine's business, and no specification bounds it, so
|
||||
@@ -368,7 +352,7 @@ pub const RegisterError = error{
|
||||
NoSuchParent, // no device with that id
|
||||
NotYourParent, // that device exists but this task has not claimed it
|
||||
TooManyResources, // the descriptor declares more resources than one device may hold
|
||||
TooManyChildren, // this parent is at maximum_children_per_parent
|
||||
TooManyChildren, // the caller is at its per-registrar allowance
|
||||
NotContained, // a child resource escapes its parent's window
|
||||
};
|
||||
|
||||
@@ -459,14 +443,6 @@ fn existingChild(parent_id: u64, descriptor: *const device_abi.DeviceDescriptor)
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Number of devices currently recorded with `parent_id` as their parent.
|
||||
fn childCount(parent_id: u64) usize {
|
||||
var n: usize = 0;
|
||||
for (devices[0..count]) |d| {
|
||||
if (d.parent == parent_id) n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/// Publish `descriptor` as a child of `parent_id`, on behalf of `owner`. Returns the new
|
||||
/// device id. The child is left **unclaimed**, so another process (a class driver)
|
||||
@@ -497,7 +473,6 @@ pub fn register(parent_id: u64, owner: u32, descriptor: *const device_abi.Device
|
||||
// below).
|
||||
if (existingChild(parent_id, descriptor)) |existing_id| return existing_id;
|
||||
|
||||
if (childCount(parent_id) >= maximum_children_per_parent) return error.TooManyChildren;
|
||||
// The allowance is charged to whoever is registering, so a driver in a loop
|
||||
// exhausts its own and every other driver carries on. There is no machine-wide
|
||||
// ceiling any more: the table grows.
|
||||
|
||||
Reference in New Issue
Block a user