ADR-027 — Thin VFS + in-RAM memfs
- Status: Accepted (memfs mile Verified when the serial / tests pass; Track A / app hosting still Planned)
- Date: 2026-09-12
Context
Track A (issue #31) wants a freestanding app to read and write named buffers. Issue #37 is this mile: a thin VFS with one backend, an in-RAM memfs, plus a fail-closed create / write / read / close probe.
ADR-021 already has exit / uart_write / yield (16–18). There is no path, no handle, and no store. A later virtio-blk + on-disk FS (A7 / issue #38) must not invent a second “open” story. The VFS ADR lands first.
This is not Linux VFS. Not POSIX open / stat / mount. Not a disk. Not app hosting.
Hypotheses
| ID | Option | Notes |
|---|---|---|
| H1 (chosen) | Tiny VfsOps (create / open / read / write / close) + one MemFs of heap Vec<u8> named files. New public SVC 19–23. Kernel probe + EL0 trampoline. | Same “easiest in-tree” shape as a coop task. No DMA. One backend this mile. |
| H2 (rejected) | Skip the trait and call memfs from SVC only. | A7 would then invent a second interface. The VFS is the mile. |
| H3 (rejected) | Ship virtio-blk or FAT in the same PR. | A7. Host -drive without guest code is not a probe. Do not say “supports FAT.” |
| H4 (rejected) | Linux/POSIX open flags, directories, cwd, O_CREAT. | Inflates the mile and invites a POSIX claim. |
Decision
-
Thin VFS.
src/vfs.rsdefinesVfsOps:create/open/read/write/closeon a path + handle. One global backend this mile:MemFs. Later A7 may add a block FS behind the same trait. Not a superblock. Not a dentry cache. -
memfs. Flat namespace. Paths are
/plus 1–15 bytes of[a-z0-9_-](no extra/, no.). At most 8 files, 256 bytes each, 4 handles. File bytes live on the first-fit heap (Vec<u8>, ADR-009). Handles are1..=4. Offset is per handle.createfails if the name exists.openfails if missing.writestores at the handle offset and grows up toFILE_MAX.readcopies from the offset.closedrops the handle; the file stays. Not a directory tree. -
Public SVC numbers (extends ADR-021). Same calling convention (
SVC #<n>,x0–x2, returnx0). Reserved 0–2 stay ADR-013 probes.Number Name Args Effect Return 19 fs_createx0= user path,x1= lengthCreate an empty named file and a handle fd >= 1, or020 fs_openx0= user path,x1= lengthOpen an existing name fd >= 1, or021 fs_readx0= fd,x1= user buf,x2= lengthCopy from the handle offset into a user-mapped and kernel-mapped range bytes, or u64::MAXon reject (0is a valid empty read)22 fs_writex0= fd,x1= user buf,x2= lengthCopy into the file at the handle offset bytes, or 023 fs_closex0= fdDrop the handle 0on success,u64::MAXon rejectPath / I/O length is capped (path 16, I/O 64). Fail-closed: empty length, overflow, non-canonical / TTBR1 alias, or a range that is not user-mapped or not kernel-mapped returns the reject value and does not mutate the file. Kernel
.datais rejected. Unknown immediates still park. -
libctoswrappers.fs_create/fs_open/fs_read/fs_write/fs_closeoversvc #19–#23. The A2 hello payload staysexit/uart_write/yieldonly so A2–A4 markers do not change. -
Fail-closed probe. Kernel create / write / read / close of
/kprobeprintsfs: create/fs: write/fs: read. An EL0 trampoline does the same for/eprobeand printsfs: el0. Thenfs: ok.scripts/qemu-smoke.shgreps those and rejectsfs: probe missed.#[test_case]covers the kernel round-trip, a missingopen, the EL0 trip, and a kernel-.datawrite reject. Existingsvc:/libctos:/loader:/el0: task-*/ A5ident: rodata*/pan:*markers stay. -
Honesty. Say “the guest created, wrote, and read a named in-RAM file behind a thin VFS” only when the serial / tests pass. Do not say: app hosting is done, POSIX, Linux VFS, FAT, virtio-blk, on-disk FS, userspace, “EL0 isolated,” or “secure OS.” Track A A7–A9 stay Planned.
-
NFR-10 text is revised in place (ID unchanged) to name this memfs mile. Do not mint FR-16+ or NFR-15+.
Consequences
- Code:
src/vfs.rs,src/syscall.rs(19–23),libctos/wrappers,scripts/qemu-smoke.sh. - Docs: filesystem.md, overview/filesystem.md, syscall.md, track-a.md. Roadmap cites #37 / Track A #31.
- A7 (virtio-blk + FAT or xv6-like on that block device) is not this PR. Choose the on-disk format in that ADR.