vfs: the root moves into the kernel — resolve + redirect cutover
runtime.fs now routes every path through fs_resolve: kernel-served /system nodes are read via fs_node (tokens, no open state); everything under a userspace mount goes straight to the owning backend's endpoint with the kernel-rewritten mount-relative path — one syscall of naming, then the unchanged vfs-protocol rendezvous, public API untouched. mkdir/ unlink/rename resolve-then-forward (rename checks both paths land on the SAME backend); mount is the fs_mount syscall. The fat server mounts twice — /mnt/usb from the volume root and /var from its /var subtree — so the logger now writes the FHS path /var/log/<boot-stamp>/... and swapping the persistent medium later touches only fat's two mount calls. With clients holding fat's node ids directly, fat records each handle's owner, checks it, and sweeps a dead client's handles via the published exit events (the old router's pattern, now where the state actually lives). The userspace vfs server and its router die; ServiceId.vfs=1 stays reserved-retired; protocol.zig moves to system/vfs-protocol.zig (the wire contract is backend-only now). vfs-test becomes the ring-3 proof of the kernel VFS (own-binary ELF magic through /system, read-only refusals, listing); vfs-client-death becomes the fat sweep test over the full storage chain, with a ring-scanning check (the last-write buffer is too racy under a chattering tree).
This commit is contained in:
@@ -1309,8 +1309,7 @@ fn systemKlogStatus(state: *architecture.CpuState) void {
|
||||
/// through the kernel mount table (docs/vfs-protocol.md). Kernel-served ->
|
||||
/// rax=fs_route_kernel, rdx=node token. Backend-served -> rax=fs_route_backend,
|
||||
/// rdx=an endpoint handle in the caller's table (deduplicated), and the
|
||||
/// rewritten mount-relative path copied to `out` with its length in the third
|
||||
/// result register. Fails for unknown paths, create-intent on /system, or an
|
||||
/// rewritten mount-relative path copied into `out` behind a u16 length prefix. Fails for unknown paths, create-intent on /system, or an
|
||||
/// undersized out buffer.
|
||||
fn systemFsResolve(state: *architecture.CpuState) void {
|
||||
const path_ptr = architecture.systemCallArg(state, 0);
|
||||
@@ -1331,14 +1330,18 @@ fn systemFsResolve(state: *architecture.CpuState) void {
|
||||
architecture.setSystemCallResult2(state, node_token);
|
||||
},
|
||||
.backend => |*backend| {
|
||||
if (backend.path_len > out_cap) return fail(state);
|
||||
// The rewritten path goes back in the out buffer behind a u16
|
||||
// length prefix (a third result register would collide with r8's
|
||||
// argument role in the userspace stub).
|
||||
if (backend.path_len + 2 > out_cap) return fail(state);
|
||||
const handle = ipc.installHandleDeduped(t, backend.endpoint);
|
||||
if (handle < 0) return fail(state);
|
||||
const destination: [*]u8 = @ptrFromInt(out_ptr);
|
||||
@memcpy(destination[0..backend.path_len], backend.path[0..backend.path_len]);
|
||||
destination[0] = @intCast(backend.path_len & 0xFF);
|
||||
destination[1] = @intCast(backend.path_len >> 8);
|
||||
@memcpy(destination[2..][0..backend.path_len], backend.path[0..backend.path_len]);
|
||||
architecture.setSystemCallResult(state, abi.fs_route_backend);
|
||||
architecture.setSystemCallResult2(state, @intCast(handle));
|
||||
architecture.setSystemCallResult3(state, backend.path_len);
|
||||
},
|
||||
.not_found => fail(state),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user