fat: install the FHS boot rewrites only on the system volume (S3)

A volume backs /system/configuration and /system/logs only when it
actually carries the /system tree — decided by content (resolve
/system/configuration on its own media at mount), not by spawn order.
The boot volume takes the branch and installs the two rewrites; a data
volume resolves null, mounts only at its id-path, and never shadows the
running system's config or logs with a dead mount.

This retires the "resolve-at-bring-up quirk" the single-volume step
deferred around: that diagnosis was wrong. A boot probe confirmed
resolve() works the instant mount() returns — /system, /system/
configuration, /system/kernel, /system/services all resolve at bring-up
(mount reads LBA 0 through the same block path, so a directory read
cannot fail where the boot-sector read succeeded). No deferral needed.

Behavior-preserving on the single boot volume (it carries the system
tree, so it still installs all three mounts): suite stays 128/128.
This commit is contained in:
Daniel Samson
2026-08-10 01:37:32 +01:00
parent b2a5a0a3c6
commit 9750db14da
+14 -7
View File
@@ -173,16 +173,23 @@ 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 });
// 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.
// Every volume mounts at its own id-path (argv[2]). The boot/system volume —
// the one carrying the /system tree — ADDITIONALLY installs the two FHS
// rewrites, so hierarchy paths (config reads, the logger's persistent
// /system/logs) stay decoupled from which volume backs them. Detection is by
// CONTENT, not spawn order: a volume is the system volume iff /system/
// configuration resolves on its own media. A data volume has no /system, so it
// mounts only at its id-path and never shadows the running system's config or
// logs with a dead mount.
mount_specs[0] = .{ .prefix = volume_mount_prefix };
var mount_count: usize = 1;
if (filesystem.resolve("/system/configuration") != null) {
std.log.info("volume {d} carries the system tree; backing /system/configuration and /system/logs", .{my_volume_id});
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 };
mount_count = 3;
}
return .{ .engine = &filesystem, .mounts = mount_specs[0..mount_count], .flush = flushIfDirty };
}
pub fn main(init: process.Init) void {