Skip to content

paged: a holder's fstat is its object's, without a request (FS stage 3a) - #1144

Draft
Japabu wants to merge 2 commits into
fs-7bfrom
fs-3a
Draft

Japabu wants to merge 2 commits into
fs-7bfrom
fs-3a

Conversation

@Japabu

@Japabu Japabu commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

FS phase 2, stage 3a, stacked on #1141, whose write-span version it publishes. The rulings are the orchestrator's: a per-holder stat syscall; the kernel owns size and version; the owner writes mtime as a word on Write; one counter. Review only the top commit until #1141 lands.

What changes

  • SYS_PAGED_STAT(holder) -> PagedStat {size, mtime, version}, read without a request. The size and version are the kernel's own. It is atomic against the pager's writes, as a read is: while a write is under way it answers WouldBlock, and the SDK asks the server instead.
  • The SDK keeps the open reply's stat beside the holder. A held descriptor's fstat is the object's size and mtime over that reply's kind, node, volume, nlink, atime and ctime. No change to the file moves those.
  • The owner writes mtime. It travels as PagedArgs.time on Write and Resize, as an argument to paged_create, and through a new PagedOp::Stamp for a utimens.
    • The file server hands over the volume's own value after every change that moves it: a reserve, a truncate, an open that truncates, a set time, and a refused write's cut-back. So the precision is the volume's.
    • Stamp is the one op beyond the ruling. A utimens moves no bytes or size, and no other call carries a time.
  • FAT's mtime is now its last write's. It used to be the entry's last level, so through a handle it disagreed with the same file reopened (issues/a-fat-files-mtime-through-its-handle-is-its-last-level.md, closed). That made it unpublishable. A write or resize now records its even second, which the handle answers and the level stamps.

Commits

Rebased onto #1141's r2 head 029ca221c (main 058bea2). SYS_PAGED_STAT is now 164, numbered against main (whose last is SYS_CURRENT_CPU = 163); SYSCALL_PROFILE_BINS is 166.

  • ea23ee415 stage 3a: kernel, ABI, SDK, file server, the FAT mtime fix and a guest member.
  • ca6340ef3 issues: FS stage 3b waits for memory stage 7b's mappings (records only).

Checks

Evidence after the rebase: https://github.com/ToyOSOrg/evidence/tree/f589db58a6b52c475fa6bac957352ffb046239c1/r2 (r0: the original checks and controls; r1: the metal A/B).

  • cargo run -- --ci host at ca6340e: rc=0, 109 steps green.
  • QEMU x86_64, the testcases boot via --debug, at ca6340e with a clean tree: rc=0. The new a_held_files_fstat_is_its_servers_stat exits 0, as do the tear member, a_served_file_reads_through_its_paged_object, served_file_offset, a_pager_s_end_answers_its_waiting_holders_gone, std_fs, file_mtime and stat_identity.
  • Why the new guest test. A held fstat and the server's stat come from the kernel's object and the file server's volume. Only a guest runs both. Each side's rule is host-tested. Targets: QEMU x86_64 (run), T14 and AMD (staged).
  • Negative controls, all built and red:
    • host C8–C12 (the server's mtime hand-over, FAT's write time, the pure model's publication);
    • guest G2 (the kernel publishes mtime 0), which also shows the held fstat is the kernel's answer.
  • Metal: run before the rebase, claim met (r1). fs.disk.fstat went from 9.63/8.17 to 0.361/0.361 us on AMD and from 10.11/10.34 to 0.452/0.452 us on the T14 (−96%). The rebase moved only the syscall number, so that result stands. The rule-2 flags (AMD write_4k_fsync +8.3%; T14 create_write_unlink and mkdir_rmdir, disk-mutation rows 3a's code doesn't touch) match the boot modes paged: a holder's read is atomic against its pager's write; an fsync commits its own file #1141's r2 documents. Every testcases member passed on both benches.
  • Controls C8–C12 and G2 (r0) ran on the pre-rebase tree. The code they mutate is unchanged.

Risks

  • An mtime is published only when the file server hands it over. A future path that moves a volume's mtime without calling Files::stamped, write, truncate or truncated would leave holders stale. The host test covers every path that exists today.
  • A stat during a write costs a round trip. It falls back while any write to the file is under way.

🤖 Generated with Claude Code

Japabu and others added 2 commits November 2, 2026 00:18
A served file's fstat was a file server round trip. A paged object now
publishes what a holder's fstat needs that can change: the kernel's own
size and write-span version, and the mtime its pager sets.
SYS_PAGED_STAT(holder) answers {size, mtime, version} under the
object's lock, WouldBlock while a write is under way (atomic as a read
is), and the SDK then asks the server. Kind, node, volume and nlink come
from the open's reply, which no change to the file moves.

The owner sets the mtime as a word it already sends: PagedArgs.time on
Write and Resize, paged_create's mtime, and PagedOp::Stamp for a utimens.
The file server hands the object the volume's own value after each
change (reserve, truncate, an open that truncates, a set time, a refused
write's cut back), at the volume's resolution. The version is the
object's data generation; there is no second counter.

FAT's mtime was its entry's last level, not its last write
(issues/a-fat-files-mtime-through-its-handle-is-its-last-level.md),
so it could not be published. A write or resize now records its even
second, which the handle answers until the level stamps it.

Tests:
- kernel::paged: a stat publishes no version while a write is held.
- fileserver pages: the object's size and mtime are the volume's after
  an open, a write, a refused write, a truncate and a stamp.
- fileserver fat: a file's mtime is its last write's through its handle,
  off the disk a sync later and after a reopen (replaces the test that
  pinned the stamp to the flush).
- guest a_held_files_fstat_is_its_servers_stat: the held fstat agrees
  with the server's stat of the path after each change.

Closes issues/a-fat-files-mtime-through-its-handle-is-its-last-level.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The orchestrator's ruling on the stage-3 split. The client name cache
comes on mapped paged objects, with file slots, since stat by path of an
existing file is the row that matters. Built before mappings, its slots
would be read by syscall and it would need a names-only pager for SYSTEM
and a dirty allowance for BOOT: an interim mechanism the mappings would
replace. 3a, a held descriptor's fstat, is this PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #1152, the storage consolidation. This PR will be closed when #1152 lands.

Its last pushed head, ca6340e, numbered SYS_PAGED_STAT 164. Main has since taken 164 (SYS_DEVICE_FIRMWARE_WINDOW), so whatever carries this forward needs the next free number. Its metal claim (fs.disk.fstat −96% on both benches) is in https://github.com/ToyOSOrg/evidence/tree/50415279a8a7b88a9f019adeeb2dea8e0df9e16c/r1, and the checks after the last rebase are in https://github.com/ToyOSOrg/evidence/tree/f589db58a6b52c475fa6bac957352ffb046239c1/r2.

Japabu added a commit that referenced this pull request Nov 3, 2026
Main took syscall 165 for SYS_TIMING_CONTROL (#1063). This branch's
SYS_NAMESPACE_NAMES stays 166 above it, with 168 profile bins, and the
one bound assertion names the highest number.

Merged rather than rebased: the branch carries the merge commits that
joined #1141, #1144 and the integration's own lines, and a linear
rebase would replay their merged-in commits onto bases they were never
written for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant