Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Filesystem: new vs extend

Today: thin VFS with two backends and a prefix mount table. In-RAM memfs (A6 / ADR-027) and FAT16 on virtio-blk (A7 / ADR-028). Same open / read / write / close. Path prefixes route to a backend (ADR-058): /mem (+ A6 probe names) → memfs; / → FAT16 (/probe, plus freestanding samples /hello / /fsdemo / /fatdemo / /yldemo). FAT16 write is a depth mile (ADR-050). Multi-cluster grow is a depth mile (ADR-064). FAT16 root listing is a depth mile (ADR-056). FAT16 root delete is a depth mile (ADR-057). Not POSIX open / mount / getdents / unlink, not Linux VFS, not FAT32, not xv6. Track B B5 compares the concepts: ADR-034. Not claiming a Linux filesystem.

Do not say “supports FAT” as a product. Say the guest read a known FAT16 file when the ledger has fat: ok, wrote FAT16 bytes when it has fat: write / fat: create, grew a file across a cluster boundary when it has fat: grow, listed root entries when it has fat: readdir / fat: entries, deleted a root file when it has fat: delete, created a root directory when it has fat: mkdir, created a one-level nested directory when it has fat: nested, and removed an empty directory when it has fat: rmdir. Hub: honesty ledger, What can run today. Extra stance: filesystem.md.

flowchart TD
  CALL["EL0 / EL1 callers"] --> VFS["Thin VFS<br/>open · read · write · close · readdir · unlink"]
  VFS --> MT["Prefix mount table<br/>ADR-058"]
  MT -->|"/mem · A6 names"| MEM["memfs<br/>in-RAM buffers"]
  MT -->|"/"| FAT["FAT16<br/>read · write · root readdir · unlink"]
  FAT --> BLK["virtio-blk<br/>host fat16.img"]

Same thin API, two backends, prefix mounts. Not POSIX open / mount / getdents / unlink. Do not say “supports FAT” as a product.

New vs extend

Prefer implementing a known small filesystem behind this thin VFS over inventing a novel on-disk format.

FitWhatWhy
LandedRamdisk / memfsNamed heap buffers. Create / lookup / read / write without DMA.
Landedvirtio-blk + FAT16 readHost-visible raw image (scripts/mkfat16.py). xv6-like was rejected so the host can inspect the volume.
LandedFAT16 writeGuest vfs::write on an open FAT handle + backend create of a small file (ADR-050).
LandedFAT16 multi-cluster growGuest write allocates a FAT chain and crosses a cluster boundary (ADR-064).
LandedFAT16 readdirGuest vfs::readdir lists FAT16 root paths (ADR-056). Not POSIX getdents.
LandedFAT16 deleteGuest vfs::unlink deletes a FAT16 root file (ADR-057). Not POSIX unlink.
LandedFAT16 mkdirGuest vfs::mkdir creates a FAT16 root directory with . / .. (ADR-073). Not POSIX mkdir.
LandedEL0 fs_mkdirSVC 27 + freestanding /mkdemo (ADR-075). Exists/BadPath fail-closed. Root create from EL0.
LandedFAT16 nested mkdir + empty rmdirOne-level /parent/child + empty vfs::rmdir (ADR-077). Not POSIX. Not arbitrary depth.
Landedctos-specific virtual mountsPrefix mounts behind the thin VFS (ADR-058). Not a new magic format. Not mount(2). Tree mounts (extra /) stay later.

Avoid early

Do not start with ext4, btrfs, ZFS, or NTFS. Those are large, journaled or feature-heavy, and hide the block mile. They are not a first cut.

Host QEMU -drive without guest virtio + a VFS read is not a filesystem.

Roadmap order

One milestone → one branch → one PR.

flowchart LR
  V["1. VFS ADR<br/>ADR-027"] --> M["2. memfs<br/>A6"]
  M --> B["3. virtio-blk<br/>A7"]
  B --> F["4. FAT16 read<br/>A7"]
  F --> H["5. host image + guest read<br/>A7/A9"]
  H --> W["6. FAT16 write<br/>ADR-050"]
  W --> P["7. FAT vs memfs write CNTPCT<br/>ADR-051"]
  P --> PR["7b. FAT vs memfs read CNTPCT<br/>ADR-065"]
  PR --> R["8. FAT16 readdir<br/>ADR-056"]
  R --> D["9. FAT16 delete<br/>ADR-057"]
  D --> V2["10. Prefix mounts<br/>ADR-058"]

A7 is virtio-blk + FAT16 read. ADR-050 is FAT16 write depth. ADR-051 / ADR-065 are same-boot measurement pairs (not benches). ADR-056 is FAT16 root listing. ADR-057 is FAT16 root delete. ADR-058 is prefix mounts. A8 is documented recipes. A9 / ADR-059 / ADR-061 / ADR-062 use the same volume for /hello / /fsdemo / /fatdemo / /yldemo. Do not say “supports FAT” as a product.

  1. VFS ADR — thin interface (create / open / read / write / close of a path).
  2. memfs — in-RAM named buffers; serial fs: ok.
  3. virtio-blk — virtqueues + sector I/O on QEMU virt. Serial blk: ok.
  4. On-disk FS — FAT16 (ADR-028). Serial fat: ok.
  5. Host-checkable image — scripts/mkfat16.py writes target/fat16.img; smoke attaches -drive if=none,file=…,id=hd0 -device virtio-blk-device,drive=hd0. Guest vfs::open("/probe") must read fat-hi. A9 adds --app so /hello is the published app ELF; ADR-059/061/062 add --app2 / --app3 / --app4 for /fsdemo / /fatdemo / /yldemo.
  6. FAT16 write — guest vfs::write on an open FAT handle + backend create of /fwr (ADR-050). Serial fat: write / fat: create; host --check-write.
  7. FAT vs memfs write CNTPCT — same-boot pair perf: fat-write / perf: memfs-write / perf: fs-write-delta (ADR-051). QEMU TCG lab — not a percent or latency SLA. 7b. FAT vs memfs read CNTPCT — same-boot pair perf: fat-read / perf: memfs-read / perf: fs-read-delta (ADR-065). QEMU TCG lab — not a percent or latency SLA.
  8. FAT16 readdir — guest vfs::readdir lists root thin-VFS paths (ADR-056). Serial fat: readdir / fat: entries. Not POSIX getdents.
  9. FAT16 delete — guest vfs::unlink deletes a root file (ADR-057). Serial fat: delete. Not POSIX unlink.
  10. Prefix mounts — mount table routes path prefixes to memfs or FAT16 (ADR-058). Serial vfs: mount / vfs: mounts. Not POSIX mount(2).

Honesty

ClaimProbeStatus
Thin VFS + memfs create/write/read/closeSerial fs: ok + #[test_case]Verified (A6; honesty ledger)
virtio-blk sector R/WSerial blk: ok + #[test_case]Verified on this tip when the ledger has the probe
FAT16 /probe via the same openSerial fat: ok + #[test_case]Verified on this tip when the ledger has the probe
FAT16 write + small createSerial fat: write / fat: rewrite / fat: create + host --check-writeVerified on this tip when the ledger has the probe (ADR-050)
FAT vs memfs write CNTPCT pairSerial perf: fat-write / perf: memfs-write / perf: fs-write-deltaVerified on this tip when the ledger has the probe (ADR-051). Not a bench.
FAT vs memfs read CNTPCT pairSerial perf: fat-read / perf: memfs-read / perf: fs-read-deltaVerified on this tip when the ledger has the probe (ADR-065). Not a bench.
FAT16 root readdirSerial fat: readdir / fat: entries + #[test_case]Verified on this tip when the ledger has the probe (ADR-056). Not POSIX.
FAT16 root deleteSerial fat: delete + #[test_case]Verified on this tip when the ledger has the probe (ADR-057). Not POSIX.
FAT16 root mkdirSerial fat: mkdir + #[test_case]Verified on this tip when the ledger has the probe (ADR-073). Not POSIX.
EL0 fs_mkdir sampleSerial libctos: mkdir-ok / mkdemo: okVerified on this tip when the ledger has the probe (ADR-075). Not POSIX.
FAT16 nested mkdir + empty rmdirSerial fat: nested / fat: rmdir + #[test_case]Verified on this tip when the ledger has the probe (ADR-077). Not POSIX. One nest level only.
Thin VFS prefix mountsSerial vfs: mount / vfs: mounts + #[test_case]Verified on this tip when the ledger has the probe (ADR-058). Not mount(2).
FAT16 /hello app slot (A9)Serial slot: ok + #[test_case]First cut when the ledger has the probe

Do not claim compatibility with anyone’s existing disk.