Repository navigation
The filesystem protocol speaks its own refusals, and pci-claim its own - #948
Conversation
`toyos::fs::Error` is the file protocol's word: each refusal a client can act on is one named variant with its own wire code, and a reply's status is read against that table alone, so a status, a frame type or a byte count no server sends is `Malformed` rather than another answer. The fileserver's `Volume` interface, the DATA and FAT volumes, the absent volume and the request bounds all answer it; the format crates' errors are translated once each (`data::refusal`, `fat::word`), now one-to-one where the protocol has the word (not a directory, not empty, no space, too large) instead of folded into kernel words. A kernel refusal of a call the protocol itself makes (the window, the connection, the hello's loan, a stream's pipe) is translated once by `Error::kernel`: `Gone` and `ResourceExhausted` are the only words those calls get for handles the caller made, and any other fails loudly. A directory name this process was not given is `NotHeld`; diskserver's client likewise names a missing block service `NotHeld` instead of handing the fileserver a kernel `NotFound` to match on. std's served-file path maps each refusal to its `io::ErrorKind` in one table and no longer passes kernel words through `to_io_error`. The supervisor's power-off sync and the app_view guest case read the new type directly. `toyos-pci-claim`'s `KernelRefused` carries `Why` (Gone, Exhausted, NotOffered) instead of a `SyscallError`, and `describe` is its one place a claim's description is read, so netstack's I219 path no longer builds the kernel refusal itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #948 at
|
…r cross the wire `toyos-pci-claim`'s `Why::of` panicked on `Io`, which the kernel answers every claim call once the IOMMU has refused the function an access (`pcidev::with_bound`): an untrusted device faulting during bring-up would have ended its driver. It is `Why::Faulted` now. The calls' other words, checked against the kernel again, are `Gone`, `ResourceExhausted` and `InvalidArgument`; a PCI description is infallible once claimed. `toyos::fs::Error`'s client-only words (`Gone`, `NotHeld`, `Malformed`) have no wire code: `code` answers `None` for them, `from_code` knows only the server's refusals, so a status of 29 to 31 or any other no server sends is `Malformed`, and `Reply::refused` of a client word fails loudly. The discriminants are the codes, so the compiler holds each to its own and the uniqueness test goes. A stream whose pipe the client's own full handle table refused answers `OutOfResources`, not `Malformed`, and drops the connection, since the kernel leaves the refused pipe queued for the next stream's answer. A served seek past the largest offset is `InvalidInput`, as the kernel's route answers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's HDA path built the description's refusal with `KernelRefused::on`, which this branch made private so that `toyos_pci_claim::describe` is the one place a claim's description is read and translated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review of #948 at
|
#953 moved the HDA driver out of soundserver into system/hda. The modify/delete conflict on system/soundserver/src/hda.rs resolves to the deletion: this branch's one hunk there (the description read through toyos_pci_claim::describe) is carried to the new driver. The new driver is a pci-claim caller main added, so it takes this branch's rule rather than a second path: its description is toyos_pci_claim::describe, ended by name instead of an expect, and the ring soundserver lends is mapped through toyos_pci_claim::lend, since KernelRefused::on is private here. lend names the region's own refusals Why::Unlendable (not ordinary memory, already lent, or sent without MAP): those are the peer's words about its region, not the claim's, so Why::of's panic on an unexpected word would misreport them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged origin/main 4225780 (#953, #954) at 7b77570. Resolved. The only conflict was modify/delete on #948's rule applied to main's new pci-claim caller (
The PR body has been updated to include this. |
Review: merge resolution at 7b77570 (main 4225780, #953 and #954)Scope: only what the merge resolution added, from Architectural assessmentThe resolution is correct and minimal.
A separate reason is justified. For Can a reachable kernel word still panic
Size: production +31 lines, test +11 lines (including the new test's doc comment and blank line), in FindingsNo blockers. SUGGESTION Note, outside this merge, for the orchestrator. In #953's code on main, Tests and evidence
The merge commit message and PR comment 6300158110 match the diff and the kernel code. The note that hda's LAND |
Problem
The file protocol's replies crossed as kernel ABI words:
Reply.statuswas aSyscallError, and the fileserver'sVolumeinterface, both volumes, the absent volume and the request bounds all spokeSyscallError(255 uses acrosssystem/fileserver/src/{absent,bounds,data,fat,main,volume}.rs, 42 insdk/toyos/src/fs.rs). Distinct refusals collapsed into kernel words (not empty, not a directory and is a directory were allInvalidArgument; no space and an entry past its bound were bothResourceExhausted), and an unknown status becameUnknown.toyos-pci-claimhanded its callers the kernel's word too.Resulting behavior
toyos::fs::Errorsits beside the wire types insdk/toyos/src/fs.rs. It has 31 named variants: 28 a server sends, each with its own wire code, and three that are the client end's own (Gone,NotHeld,Malformed) and have none.from_codeknows only the server's refusals, so any other status, including 29 to 31, reads asMalformed, andReply::refusedof a client word panics. A frame type or byte count no server sends isMalformedtoo. There is no catch-all and no kernel code inside it.Error::kernelcovers the calls the protocol itself makes: window create, connect, the hello's loan, the frame transport. On the server, it covers a stream's pipe. Those calls only answerGoneandResourceExhaustedfor handles the caller made, so any other word panics as a broken invariant. A name the namespace lacks becomesNotHeld.Errorthroughout. Each format crate's error is translated once (data::refusal,fat::word), now one to one where the protocol has the word (NotADirectory,IsADirectory,NotEmpty,NoSpace,FileTooLarge,LimitExceeded,InvalidName). The server's own refusals are named too:ReadOnly,NotOpenForWriting,Root,Escapes,CrossesDirectories,Loop,IntoItself,TooManyOpen/Connections/Streams,UnknownFile,InvalidPath,InvalidRequest,Stale.NotHeld, so the fileserver no longer matches onKernel(SyscallError::NotFound). A block service that ended under a DATA read is nowIoto the file client, no longerGone, which std had read as "the file server is gone".sdk/std/sys/fs.rs) maps each served refusal to itsio::ErrorKindin one exhaustive table and no longer routes served errors throughto_io_error. Kinds that change:ReadOnlystaysPermissionDenied;NoSpaceis nowStorageFulland the limits areQuotaExceeded, where both used to beOutOfMemory;NotEmptyisDirectoryNotEmpty;StaleandGoneareStaleNetworkFileHandle; a servedreaddirthat keeps growing isInterrupted(wasOutOfMemory), as the kernel route says. A served seek past the largest offset staysInvalidInput, as the kernel route answers it.app_viewguest case read the new type directly.Dir::syncreturnsError, since a link is no answer to a sync, andDir::symlinkreturnsError, since it names no path to resolve.toyos-pci-claim:KernelRefused.whyis nowWhy(Gone,Exhausted,NotOffered,Faulted), built in one place.Faultedis the kernel'sIo, which every claim call answers once the IOMMU has refused the function an access (pcidev::with_bound), so a faulting device ends its bring-up by name rather than panicking its driver, and the virtio capability walk refuses withWalkRefusal<Why>.toyos_pci_claim::describeis the one read of a claim's description, so netstack's I219 path no longer builds the kernel refusal itself.toyos_pci_claim::lendmaps a region a peer lent (PciDev::dma_map); its refusals about the region itself (not ordinary memory, already lent, sent withoutMAP) areWhy::Unlendable, since they are the peer's words and not the claim's.Remaining
SyscallErroruses (measured at the head)system/fileservermain.rs: the import and a stream pipe'sread_nonblock(WouldBlock/Gone), a syscall made and judged on the spot.bounds.rstests: aLent::Kernelfixture, which is shm's own type.sdk/toyos/src/fs.rsError::kernel's parameter and two arms, andnamespace.open'sNotFoundread asNotHeld. The tests list each kernel word.lib/pci-claimWhy::of's parameter and four arms,Why::of_lent's parameter and two arms, andKernelRefused::on's parameter, all at the syscalls.system/hda(new on main)WouldBlock, a syscall judged on the spot as every other driver'sirq()is.libc.
sdk/libcdoes not speak the file protocol: C programs name no file a file server holds (issues/c-programs-name-no-file-a-file-server-holds.md). Itserrcode::ofmaps kernel syscalls it makes itself, which is its boundary, so nothing changes there. When libc gains served paths, I recommend its errno fortoyos::fs::Errorlive insdk/libcbesideerrcode, since POSIX compatibility belongs to libc, and not in the protocol crate. That is a recommendation, not something built here.Checks and evidence
All evidence is in ToyOSOrg/evidence
pr-948at07b25c6ff6e2(README).fs::tests::every_refusal_round_trips_through_its_own_code,a_reply_outside_the_protocol_is_malformed(unknown status, the kernel's old wire words, wrong frame types, a link answering a fid call, an over-long link or count),every_kernel_refusal_the_calls_can_see_is_one_named_error, and pci-claim'severy_kernel_refusal_a_claim_call_can_see_is_one_named_reason. The fileserver's 58 unit and module tests are green with their expectations moved to the named words.cargo run -- --ci host: exit 0, 86 steps.cargo run -- --build-only: x86_64 exit 0, aarch64 exit 0, x86_64 after merging main exit 0.ResourceExhaustedfromError::kernel, removingInvalidArgumentfromWhy::of, mapping FAT'sIotoNotFound, and reading an unknown status asIo. Each went red (exit 101) in the test named above.testcasesboot. The rows that reach changed code arenvme_disk_boots(diskserver'sNotHeldlist and DATA served from it; the boot must be clean) andmachine_shutdown_short_stop(the supervisor'sDir::syncbefore the stop; its judge checks only that nothing panics, not that the sync answered).testcasesfile members andapp_viewon PROCTREECASE at394dc5e7d: 10/10 passed (orchestrator's run). The review round's changes do not reach those paths on a healthy boot.Why::Faultedis reached only after an IOMMU fault, the client words' codes are never sent, and a stream's pipe refused only by a full handle table. The merge with main brings ipc: a typed payload is exactly one T, and FrameRx refuses a frame past its MAX #942's stricter frame decoding onto every file call; this PR changes no frame layout, and the QEMU boot at the head runs the fileserver through it. So that run stands for what this PR changes.Review round (evidence)
Why::Faultedmaps the kernel'sIo, whichpcidev::with_boundanswers every claim call once the IOMMU has faulted the function. I re-checked every word pci-claim's calls can see against the kernel:Gone,ResourceExhausted,InvalidArgument,Io; a PCI description is infallible once claimed. Control neg5 removes that arm and goes red.Gone,NotHeld,Malformed) have no wire code; a status of 29 to 31 isMalformed. Control neg6 reads 29 asGoneagain and goes red. The uniqueness assertion is gone: the discriminants are the codes, so the compiler enforces it.OutOfResourcesand drops the connection, since the kernel leaves the pipe queued for the next answer. A wrong handle count isMalformed.InvalidInput, as the kernel route answers it.KernelRefused::on, which this branch made private. It now callstoyos_pci_claim::describe.cargo run -- --ci hostat the head (log): exit 1, 1 of 86 steps red, the build system'sllvm::tests::the_caller_s_environment_reaches_neither_the_build_nor_the_key. That is a host defect independent of this branch, which changes nothing underbuild/. The host's selected developer directory isXcode.app, whose/usr/bin/gitshim honors the test's ambientSDKROOT=/no/such.sdkand fails (SDKROOT=/no/such.sdk git --versionreproduces it outside the suite). The same test passed in this PR's first host run. The orchestrator should record it underissues/.Merge of main 4225780 (evidence)
system/hda. The modify/delete conflict onsystem/soundserver/src/hda.rsresolves to main's deletion; this branch's one hunk there is carried to the new driver, which reads its description throughtoyos_pci_claim::describeand ends by name on a refusal rather thanexpect, and maps soundserver's ring throughtoyos_pci_claim::lend. Control neg7 dropsPermissionDeniedfromWhy::of_lentand goes red (101).cargo run -- --ci host: exit 0, 87 steps.--build-only: x86_64 and aarch64 exit 0.nvme_disk_boots,machine_shutdown_short_stop,hda_plays_to_the_controller_that_reaches_an_output: exit 0, 3 passed. The hda row's playing controller maps its ring throughlend.Risks
Error::kernelandWhy::ofpanic on a kernel word their calls are not documented to get. I checked the kernel paths (connect_through,HandleQueue::push,sys_shm_create,dup,sys_handle_recv,sys_device_reg,pcidev::with_bound,bar_object,dma_alloc). A kernel change that adds a word will fail these clients loudly; it will not be misreported.🤖 Generated with Claude Code