diff --git a/docs/file-system-development/storage-architecture.md b/docs/file-system-development/storage-architecture.md index ef5bfb0..929ee3b 100644 --- a/docs/file-system-development/storage-architecture.md +++ b/docs/file-system-development/storage-architecture.md @@ -3,18 +3,23 @@ > **Status:** the layered model below is the settled design > ([storage-design-rationale.md](storage-design-rationale.md) records how it was > reached, and [volume-manager-plan.md](../volume-manager-plan.md) how it was -> built). **Built** (the volume-manager track, V0–V4): the data path, the driver +> built). **Built** (V0–V4 + the storage-stack S1/S2): the data path, the driver > range confinement (per-sender clamp + the confinement gate), the `medium_changed` > presence event, the volume manager itself — it probes the partition table, > confines each filesystem to its partition, spawns one filesystem per volume, and -> supervises it — and the removal half of the lifecycle (a pulled stick unmounts). -> **Still pending**: the fuller identity ladder and the `volumes.csv` mount map, -> multi-volume (one FAT volume today), the volume manager *consuming* -> `medium_changed` (removal is detected by device-presence polling; the event is -> published but only a card-reader medium change needs the subscription), and the -> remount-on-replug end-to-end (the logic is in place; QEMU can't re-present the -> boot-controller device, so it is bench-verified). A few markers below are left -> where a duty is still pending. +> supervises it — the removal half of the lifecycle (a pulled stick unmounts), the +> identity ladder (GPT GUID + name, FAT serial + label, MBR), and the mount map: +> `filesystems.csv` (signature → binary) + `volumes.csv` (identity → optional +> override), a volume's mount path IS its content id (`/volumes/`), with the +> label as display metadata a `volumes` query returns. **Still pending**: the +> `filesystem UUID` rung (needs a non-FAT engine), multi-volume (one FAT volume +> today; fat's boot rewrites are unconditional until S3 makes them +> content-conditional), the volume manager *consuming* `medium_changed` (removal +> is detected by device-presence polling; the event is published but only a +> card-reader medium change needs the subscription), and the remount-on-replug +> end-to-end (the logic is in place; QEMU can't re-present the boot-controller +> device, so it is bench-verified). A few markers below are left where a duty is +> still pending. ## The model @@ -85,16 +90,17 @@ manager's tree for a storage provider; when one appears it consumer-hellos for the block channel, reads the partition table and the first blocks itself (**it** is the prober), defines the volume's sub-range on the driver, spawns the matching filesystem service confined to that range, and supervises it (backoff, -crash-loop cap). *(Pending)*: it decides mount placement from `volumes.csv` and -picks the filesystem binary from `filesystems.csv` — today it hands every -FAT-shaped volume to the FAT service and the FAT service carries hardcoded mount -prefixes. Those tables are CSV configuration, read by it (the policy), enforced -by nobody else: +crash-loop cap). *(Built)*: it picks the filesystem binary from +`filesystems.csv` by the volume's content signature, and mounts the volume at its +content id (`/volumes/`) — or a `volumes.csv` override. The label is display +metadata the `volumes` query returns, never the path. Those tables are CSV +configuration, read by it (the policy), enforced by nobody else: -- `filesystems.csv` *(pending)* — content signature → filesystem binary. Adding +- `filesystems.csv` *(built)* — content signature → filesystem binary. Adding a filesystem adds a row. -- `volumes.csv` *(pending)* — the mount map, danos's fstab: **volume identity → mount - prefix**, keyed on content identity and never on port, path, or arrival +- `volumes.csv` *(built)* — the mount map, danos's fstab: an OPTIONAL **volume + identity → mount prefix** override (a volume with no row mounts at its default + `/volumes/`), keyed on content identity and never on port, path, or arrival order (the lesson of Linux's `/dev/sda1`-era fstab, which broke on every port move until `UUID=` replaced it). Identity is read off the medium by the prober, strongest first: GPT partition GUID → filesystem UUID → FAT @@ -105,8 +111,8 @@ by nobody else: identity (cloned sticks, together) is policy: first keeps the name, the second mounts suffixed and is logged loudly. The boot volume is the recorded identity of the volume carrying `/system/configuration` and - `/system/logs`, findable on any port. Unknown volumes mount under - `/volumes/`. + `/system/logs`, findable on any port. Every volume's default mount is + `/volumes/` — its rendered content identity. **Filesystem service** (the FAT service today; one process per volume): the proven unit — block-client + engine + file-protocol provider in one binary. It @@ -114,12 +120,13 @@ receives its block channel at spawn; it never discovers devices. It registers its own mounts with the kernel; its write cache lives inside the process, so a write error is observed by the code that owns the volume and surfaces on the owning channel (the anti-fsyncgate rule — never a system-wide dirty pool). -*(Today, interim:)* fat still hardcodes its mount prefixes (`/volumes/usb` plus -the two boot-volume hierarchy subtrees it rewrites in place); a `volumes.csv` -mount map will migrate that to the volume manager. It no longer self-acquires a -volume — the V3b flip made it receive its volume id at spawn and its block -channel from the volume manager's hello reply, consistent with "it never -discovers devices" above. +*(Built:)* fat receives its mount path as `argv[2]` from the volume manager (the +volume's id-path, e.g. `/volumes/fat-12345678`) and mounts its root there, plus +the two `/system` hierarchy rewrites it installs in place (unconditional this +increment; S3 makes them content-conditional across volumes). It no longer +self-acquires a volume — the V3b flip made it receive its volume id and block +channel from the volume manager, consistent with "it never discovers devices" +above. **Kernel** (mechanism only): the mount table routes paths to backend endpoints — resolve and redirect, never data. Remount-replace is the restart diff --git a/docs/file-system-development/storage-design-rationale.md b/docs/file-system-development/storage-design-rationale.md index a5c2f81..fb29fc2 100644 --- a/docs/file-system-development/storage-design-rationale.md +++ b/docs/file-system-development/storage-design-rationale.md @@ -218,9 +218,10 @@ matrix-proven shape; genuinely open. **content identity, never port or discovery order**. Build status: rungs 1, 3, and 4 (GPT partition GUID, FAT serial + label, MBR signature + index) are implemented (S1); rung 2 waits on a non-FAT engine. The `volumes.csv` map and - the id-derived mount path land with S2, so today a single volume still mounts - at the fixed `/volumes/usb` and its recorded identity is not yet consulted to - pick a path. The ladder the prober reads off the medium, strongest first: + the id-derived mount path are built (S2): a volume's mount path IS its content + id (`/volumes/`, e.g. `/volumes/fat-12345678`), or a `volumes.csv` + override; the label is display metadata a `volumes` query returns, never the + path. The ladder the prober reads off the medium, strongest first: 1. GPT partition GUID — 128-bit, unique, stable for the volume's life — **built (S1)**; 2. filesystem UUID (ext-family and most modern formats, in the superblock) *(planned)*; 3. FAT volume serial + label — 32 bits, weak (dd-cloned sticks share it)