Repository navigation
A path is routed through the view's own names, asking the kernel for none - #1225
Conversation
…none Routing an absolute path tried each of its first four prefixes as a capability name, deepest first, and remembered every answer: a path whose prefix the view does not hold cost a 2 MiB window made and dropped and a namespace open the kernel refused, the first time, and an entry kept for the life of the process ever after. A program that names many files four components deep or less, as anything writing into /tmp does, grew that table by one entry a file. Each later path paid two allocations and a locked lookup per prefix tried. A process's namespace is immutable and already listed for its directories, so the held directories are kept beside them and a path is matched against those: no allocation but the path beneath the capability, and no capability is asked for that the view does not hold. On the T14 the SDK's own time for a path call falls by 0.3 to 0.9 µs, and the build-shaped rounds, whose every compile is a new process naming fresh /tmp paths, take 12% less wall time at one job and 26% less at eight. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1225 at 6f2ea34ArchitectureThe fix sits in the right place. A process's namespace is immutable and the SDK already lists it, so routing a path against the held directories in that listing removes a kernel round trip for each prefix the view doesn't hold, and it removes the unbounded negative cache. The change touches only the SDK. Production code grows by a net 22 lines and tests by 22. Routing keeps the same "longest held prefix" meaning ( RequiredBLOCKER
OptionalNone. EvidenceChecked rather than taken from the PR:
After the fix, rerun A note for the orchestrator, not a finding: the judge refused all three readbacks because the bench runner's SEND BACK |
…refusal is the call's Routing still tried a shallower held directory where the deepest would not connect, kept every failed connect, and a test pinned that fall-through as intended. A view's names are immutable and a server never refuses a hello as NotHeld, so only a misbehaving server reached it, and then a path was quietly resolved on another server. A path now goes to the deepest held directory it lies in, a refused connect is the call's error, and only connections are kept. The routing comment no longer says a path costs the kernel nothing: the first path into each held directory connects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review r1, at 5386a47: a path goes to the deepest held directory, and that directory's refused connect is the call's error. 🤖 Generated with Claude Code |
Review round 2 of #1225 at 5386a47ArchitectureNo change since round 1. Routing stays in the SDK, where the view's listing already lives. The round removes the fall-through: a path goes to the deepest held directory it lies in, and that directory's connect is the only one tried. This round deletes 13 lines net: 38 removed, 25 added. Round-1 blockerResolved.
Optional
Evidence
LAND |
|
Orchestrator: follow-up review r2 LAND at 5386a47. A path routes only to the deepest held directory; the fall-through loop and cached failures are gone. The reused guest run 43054675576 and the build-round metal are valid, since the only removed code is a path no measured boot reached. Queueing. |
Problem
Routing an absolute path tried each of its first four prefixes as a capability name, deepest first, and
remembered every answer. A prefix the process's view does not hold cost, the first time, a 2 MiB window made and
dropped and a namespace open the kernel refused, and then an entry kept for the life of the process. A program
naming many files up to four components deep, as anything writing into
/tmpdoes, grew that table by one entrya file without bound. Every later path paid two allocations and a locked lookup per prefix tried.
Change
A process's namespace is immutable and the SDK already lists it for its directories. The held directories are now
kept beside them, and a path goes to the deepest held directory it lies in: no capability the view does not hold is
asked for, and nothing is allocated but the path beneath the capability. That directory's refusal to connect is the
call's error; nothing falls through to a shallower directory's server. Only connections are kept, so the table is
bounded by the view.
The routing helper's host test asserts that no unheld name is ever asked for, and the tests pin the deepest match,
the root's capability for what no other holds, and a name that only shares a prefix (
/homestead).Evidence
Metal, T14, one boot with the change (B-1) against two without it (A-1, A-2), each the
osbench_fileopsjob(all three verdict
passed, judged offline from the readbacks). The images carried scratch stage timers that donot land; A and B differ only in this change. Readbacks, extracted rows, p50 tables and judge logs:
https://github.com/ToyOSOrg/evidence/tree/33f7f469ebba9f0b82c8d4df8c59ea5aaa86a44c/fileops-diagnosis
statin /tmpstaton DATAThe whole-row latencies move less and within more noise (
statin /tmp 9.88 / 9.51 to 9.27 µs). The largergain is in programs that start: each compile is a new process naming fresh
/tmppaths, and paid the refusedopens and windows for each. B ran before the A pair on the bench; the order does not bear on these readings
(each boot flashes its image, and these rows touch only /tmp and /system). B's process also made 531 fewer of
each of two namespace system calls and 539 fewer allocations over the job: the refused connects that are gone.
The harness's offline judge refused all three readbacks for one reason outside this change: the runner's
toyos-metalwrote noback_unix_secsinboot.txt, which the judge at this base requires. Every boot's own logends
===TEST_END osbench_fileops exit=0===.Host, at 5386a47 (review round 1; logs:
https://github.com/ToyOSOrg/evidence/tree/c20541dd31d1e8b3e5b52e0e00d37a6cafb19b6d/host-checks-r1): the change is confined to the SDK's
filesmodule, sothe checks are that module's host tests and the SDK's lint.
cargo test -p toyos --lib files::exit 0 (11 passed);cargo clippy -p toyos --all-targetsandcargo clippy -p toyos --lib --features fd-table, each with the adoptedlints and warnings denied, exit 0. The round only removed the fall-through no measured boot reached, so the guest
row and the metal measurement below still hold for it. The full host matrix runs in the merge queue.
Guest, at 6f2ea34 (run 43054675576, log):
a_row_reaches_its_own_state_and_no_other, a nested/state/<row>capability held beside/, which exercises thedeepest-held match: PASS,
--ci rowsall green. x86-64 only: an SDK change with no architecture-specific code. Thefile-call binaries (
state_view,hierarchy_pathsand the rest) are members of the metal shared boot, not QEMU rows;two earlier dispatches named them or
osbench_files, a metal bench job, and failed at selection (runs 43036474857and 43042985719).
Risks
None known. As before, a capability more than four components deep (
MAX_CAPABILITY_DEPTH) is not routed to;the view's listing already skips it.
🤖 Generated with Claude Code