ADR-034 — Linux VFS concepts vs thin ctos VFS
- Status: Accepted (docs compare; no Linux FS claim)
- Date: 2026-09-12
- Number: ADR-034 is frozen for this mile. Main holds ADR-033 (B4 ELF / auxv /
PT_INTERP, #68 /774c672) and ADR-035 (B3 process model, #67 /d81a53a). Do not yield this number again.
Context
Track B (issue #40) is Linux-compat research. Child B5 / #45 asks how ctos VFS / memfs / FAT stays thin while optionally mapping to Linux-like semantics later.
ADR-031 already framed Linux-compat as ABI-subset research and told this child: compare Linux VFS concepts vs the thin ctos VFS; do not grow POSIX open flags / dentries. B2 already mapped the file-descriptor slice: Linux AArch64 openat / read / write / close are partial against ctos fs_create / fs_open / fs_read / fs_write / fs_close (SVC 19–23). Linux mount / umount2 / pivot_root stay never-per-ADR-031.
Track A first cuts stay freestanding:
- Thin VFS + in-RAM memfs (ADR-027):
VfsOpsis create / open / read / write / close. Flat path/+ 1–15 of[a-z0-9_-]. At most 8 files, 256 bytes, 4 handles. - virtio-blk + FAT16 behind the same
vfs::open(ADR-028); write depth ADR-050. Known files/probeand A9/hello; guest may create/fwr. Serialfat: mountis a probe marker, notmount(2).
This ADR does not implement B3, B4, or B6. It does not mint FR-16+ or NFR-15+. It does not add POSIX flags, dentries, cwd, or a second open story to src/. File presence of this page is not a Linux filesystem.
Hypotheses
| ID | Option | Notes |
|---|---|---|
| H1 (chosen) | Compare Linux VFS objects (dentry / inode / path / mount) to today’s thin VFS. Stay thin. Document gaps. Optional later mapping is translation after B6, not a dentry cache this mile. | Matches #45 / ADR-031. Leaves B6 room to choose never. |
| H2 (rejected) | Grow POSIX open flags, dentries, cwd, or O_CREAT in this PR. | ADR-031 forbids it. Inflates Track A probes and invites a POSIX claim. |
| H3 (rejected) | Say “ctos has Linux VFS” because memfs + FAT16 exist. | Honesty fail (NFR-06). Serial fs: ok / fat: ok are thin-VFS probes, not Linux VFS. |
| H4 (rejected) | Add mount(2), overlay, or a mount namespace as Planned on Track B. | Conflicts with ADR-031 / ADR-029. A7 FAT attach is not a Linux mount tree. |
| H5 (rejected) | Decide compat layer vs reimplement vs never here. | That is B6 / #46. |
Decision
-
Stay thin.
VfsOpsremains five calls on a path + handle. Oneopenstory. memfs first; if the name is missing, FAT16 root (8.3) is tried. FAT fds are tagged so the router does not invent a second interface. Not a superblock. Not a dentry cache. Not POSIXopen. -
What Linux VFS is (concepts, not a port). Linux path lookup is a walk of cached dentries that bind a name to an inode, under a vfsmount, on a super_block. An open file is a separate file object (
f_pos,f_op). A path is the pair(mnt, dentry). Hard links share an inode across dentries../../ extra// relative names /AT_FDCWD/ symlinks are part of that walk. This paragraph is a teaching sketch of Linux, not a claim that ctos implements any of it. -
Concept map. Status words match B2: present means the Linux object exists here with comparable semantics; partial means a related ctos object exists but identity or walk still differ; absent means no analog; never-per-ADR-031 means a Linux mount / overlay / namespace class already ruled out.
No Linux VFS object is
present.Linux concept ctos today Status Why not presentsuper_block(FS instance,s_op, root)Two backends behind one router ( MemFs+Fat16)absent No superblock, no FS type registration, no s_root.inode(identity,i_ino,i_mode,i_op)memfs File(name +Vec<u8>) or FAT 8.3 dirent + clusterabsent No inode number, mode, nlink, or inode ops. Close does not destroy the memfs bytes; that is not an inode lifetime. dentry(cached name → inode,d_parent)Exact string match on a flat table absent No dentry cache, no parent, no hash walk, no RCU-walk. ADR-027 rejected a dentry cache. path(vfsmount+dentry)Canonical byte string /+[a-z0-9_-]partial A path exists as a name. It is not a (mnt, dentry)pair.file(open instance,f_pos,f_op)Handle 1..=4with a per-handle offsetpartial Related effect to an fd + offset. Four handles. No f_op, no fd 0/1/2, nodup. FAT handles use a tag bit, not a Linux fd table.vfsmount/ mount treeSerial fat: mountafter virtio + FAT attachnever-per-ADR-031 Not mount(2). No mount namespace, no overlay, noumount2/pivot_root. B2 already marked those never-per-ADR-031.Directory / getdents64Flat namespace; FAT root is a lookup table, not a listed dir absent No mkdirat, no cwd.stat/statx/ inode metadataNone absent B2: newfstatat/fstat/statxabsent.Symlink / hard link None absent One name per memfs slot; FAT 8.3 one dirent. POSIX path walk ( .,..,//, relative,AT_FDCWD)valid_pathrejects extra/,., and anything outside[a-z0-9_-]absent See path grammar below. -
POSIX path grammar vs ctos names.
Item Linux / POSIX ctos ( valid_path)Shape Absolute or relative; /separators; empty components collapseMust start with /; no extra/./..Current / parent Rejected Length PATH_MAX(typically 4096)2–16 bytes total ( /+ 1–15)Alphabet Almost any byte except NUL and /[a-z0-9_-]after the first/cwd / chdir/getcwdYes No. B2: chdir/getcwdabsentdirfd/AT_FDCWDopenatfirst argumentNo. fs_opentakes a user path pointer + lengthO_*/ modeopenatflags + modeNo. Create is a separate SVC ( fs_create19). Existing name isfs_open20.FAT 8.3 vfatlong names + short namesGuest path /probemaps toPROBE;/hellotoHELLO. Not VFAT. -
Backends are not Linux FS types. memfs is named heap buffers, not
tmpfs. FAT16 on virtio-blk is a host-built 4 MiB image with two known files, not Linuxvfat/msdos. Do not say “supports FAT” as a product. Say “the guest read a known FAT16 file through the thin VFS” only when the ledger hasfat: ok. -
Syscall slice stays on B2. This ADR does not retarget SVC 19–23 to Linux
x8. The B2 rows still stand:openatpartial,readpartial,writepartial (uart_writeorfs_write, neither iswrite(1, …)),closepartial,lseek/pread64/getdents64/ioctlabsent,mountnever-per-ADR-031. -
Optional later mapping (not a decision). If B6 ever names a compat path, the smallest file slice would still be convention translation of
openat/read/write/closeonto the existing thin VFS — not a Linux dentry cache, not POSIX flags, not cwd, notmount(2). Growing those objects needs a later epic + ADR after B6. Never remains valid. -
Not claiming a Linux filesystem. Say that sentence on the Track B page. Today:
- Thin VFS + memfs / read-only FAT16 is not Linux VFS.
fat: mountis notmount(2).- A9 FAT
/hellois not a Linux rootfs. - The ledger row “Guest runs host apps (Linux ELF / shell / Python)” stays Planned. This ADR does not change that row to Verified.
-
Keep (ctos specificity). Honesty (NFR-06): this file is not Verified Linux VFS. Antifragility keeps
fs:/blk:/fat:smoke strings. Security: no “Linux-compat isolation” from a compare. Performance: no invented VFS bench. Freestanding Track A path stays. Guest containers stay ADR-029.
Consequences
- Docs: track-b.md B5 becomes Documented. SUMMARY.md and roadmap.md link here. Site extra: filesystem.md / filesystem.md point at the compare without a Linux FS claim.
- B6 stays Planned research. B3 is Documented (ADR-035). B4 is Documented (ADR-033). No
src/change in this PR. - Track A A6/A7 probes stay the product path for named files. Do not grow
VfsOpsto look like Linux so a research ADR can saypresent. - Honesty: document inspection of this ADR +
src/vfs.rs/src/fat.rs+ the B2 gap table. Do not add a Verified Linux-filesystem ledger row because this file exists.