fat: mount at the id-path from argv; migrate /volumes/usb -> id-path (S2)

The flip that makes the mount path the volume's content id. fat retires its
hardcoded fat_mounts: it reads its mount path from argv[2] (the volume manager
hands it the id-path, e.g. /volumes/fat-12345678, from the FAT serial), mounts
its volume root there, and installs the /system/configuration + /system/logs FHS
rewrites so /system/logs persistence stays decoupled from which volume backs it.
The rewrites are unconditional this increment (the single volume IS the boot
volume); S3 makes them content-conditional across N volumes. Every /volumes/usb
reference migrates to /volumes/fat-12345678 in one commit — the fat-test,
badge-scope-test, and vfs-test fixtures and the four QEMU regexes — plus a new
volume-identity-name case asserting the id-path mount and the /system/logs
rewrite. Discrimination: the regexes now require /volumes/fat-12345678, which the
old hardcoded fat never emitted (it mounted /volumes/usb). Full suite 128/128.
This commit is contained in:
Daniel Samson
2026-08-10 00:47:19 +01:00
parent f1e79d0eeb
commit df61693065
5 changed files with 77 additions and 42 deletions
+33 -11
View File
@@ -64,15 +64,24 @@ var filesystem: engine.FileSystem = undefined;
/// the right volume's channel.
var my_volume_id: u64 = 0;
/// The prefixes this volume installs: /volumes/usb from the volume root, plus
/// the two hierarchy subtrees the boot volume carries (rewrite == prefix), so
/// hierarchy paths (the logger's /system/logs) stay decoupled from which volume
/// backs them.
const fat_mounts = [_]harness.MountSpec{
.{ .prefix = "/volumes/usb" },
.{ .prefix = "/system/configuration", .rewrite = "/system/configuration" },
.{ .prefix = "/system/logs", .rewrite = "/system/logs" },
};
/// The volume's own mount path, handed in as argv[2] by the volume manager: the
/// volume's content id-path (e.g. /volumes/fat-12345678). Defaults to
/// /volumes/usb only for a bare launch with no argument; the manager always
/// passes it. The slice points into the entry block, valid for the process life.
var volume_mount_prefix: []const u8 = "/volumes/usb";
/// The mounts this volume installs: its own root, plus — only if it is the boot
/// volume (it resolves /system/configuration) — the two FHS rewrites, so the
/// logger's /system/logs stays decoupled from which volume backs it. Boot-volume
/// detection is by content, so it works no matter which volume carries /system.
/// bound: mounts one volume installs (its root + the two boot rewrites)
/// decided-by: ours
/// protects: the mount_specs array
/// at-limit: truncate - unreachable today (fixed at 3); more configured mounts
/// would need this raised, a deliberate change
/// observed-by: a mount silently missing from the harness's mount log
const maximum_mounts_per_volume = 4;
var mount_specs: [maximum_mounts_per_volume]harness.MountSpec = undefined;
/// Get this volume's block channel from the volume manager (establishment by
/// lineage, communication.md "Establishment: two planes" — `block` is not a
@@ -164,14 +173,27 @@ fn fatBringUp(endpoint: ipc.Handle) ?Harness.Volume {
};
std.log.info("mounted FAT ({s}, {d} clusters, partition lba {d})", .{ @tagName(filesystem.geometry.fat_type), filesystem.geometry.cluster_count, filesystem.base_lba });
return .{ .engine = &filesystem, .mounts = &fat_mounts, .flush = flushIfDirty };
// The volume mounts at its id-path (argv[2]), plus the two FHS rewrites so
// hierarchy paths (the logger's /system/logs) stay decoupled from which
// volume backs them. This single-volume increment's one volume IS the boot
// volume, so it installs both unconditionally; S3 (multi-volume) makes the
// rewrites content-conditional — installed only by whichever volume carries
// the system, decided by content, not order.
mount_specs[0] = .{ .prefix = volume_mount_prefix };
mount_specs[1] = .{ .prefix = "/system/configuration", .rewrite = "/system/configuration" };
mount_specs[2] = .{ .prefix = "/system/logs", .rewrite = "/system/logs" };
return .{ .engine = &filesystem, .mounts = mount_specs[0..3], .flush = flushIfDirty };
}
pub fn main(init: process.Init) void {
// The volume manager spawns this process with its volume id as argv[1].
// The volume manager spawns this process with its volume id as argv[1] and
// the volume's mount path (its id-path) as argv[2].
if (init.arguments.get(1)) |id| {
my_volume_id = std.fmt.parseInt(u64, id, 10) catch 0;
}
if (init.arguments.get(2)) |prefix| {
volume_mount_prefix = prefix;
}
_ = logging.write("/system/services/fat: starting, waiting for a block device\n");
Harness.run(.{ .bringUp = fatBringUp });
}