kernel/vfs: raise the mount ceiling for N volumes; refuse (not drop) a full table (S3)
Multi-volume makes the mount table the bottleneck: each volume installs one id-path mount and the system volume two FHS rewrites, so at the volume manager's maximum_volumes (16) the old cap of 8 is far too low. Raise maximum_mounts to 32 (headroom over the ~20-mount worst case) and declare its bounds block; drop it from the bounds allowlist. Fix a latent bug the higher pressure would expose: installMount silently dropped a mount when the table was full, and mountBackend returned true anyway — a full table was reported as a successful mount. installMount now returns whether it placed the mount, and mountBackend propagates a false so the mounting filesystem's harness logs "could not mount <prefix>". At-limit is now a refusal that is observed, not a silent success. (The full-table path has no host unit test: vfs.zig's tests are not wired into the host aggregate — its import graph reaches the freestanding kernel — so the correction rests on the propagated return and the truthful bounds block.)
This commit is contained in:
+25
-6
@@ -55,7 +55,17 @@ fn tokenIndex(t: u64) u64 {
|
|||||||
|
|
||||||
// --- the mount table ---------------------------------------------------------
|
// --- the mount table ---------------------------------------------------------
|
||||||
|
|
||||||
pub const maximum_mounts = 8;
|
/// bound: prefixes mounted in the kernel VFS table at once
|
||||||
|
/// decided-by: ours
|
||||||
|
/// protects: the `mounts` table below
|
||||||
|
/// at-limit: refuse - installMount returns false and mountBackend propagates it;
|
||||||
|
/// the mounting filesystem's harness logs "could not mount <prefix>" and the
|
||||||
|
/// mount simply does not exist (no silent success). Budget: the initrd's
|
||||||
|
/// top-level dirs (/system, /test) plus one id-path mount per volume and the
|
||||||
|
/// system volume's two FHS rewrites — a few over the volume manager's
|
||||||
|
/// maximum_volumes (16); 32 leaves headroom.
|
||||||
|
/// observed-by: the harness "file-system: could not mount <prefix>" ring line
|
||||||
|
pub const maximum_mounts = 32;
|
||||||
const maximum_prefix = 64;
|
const maximum_prefix = 64;
|
||||||
const maximum_rewrite = 32;
|
const maximum_rewrite = 32;
|
||||||
|
|
||||||
@@ -156,7 +166,10 @@ pub fn setInitialRamdisk(image: []const u8) void {
|
|||||||
for (directories[0..directory_count], 0..) |*d, index| {
|
for (directories[0..directory_count], 0..) |*d, index| {
|
||||||
const parent = parentOf(d.slice());
|
const parent = parentOf(d.slice());
|
||||||
d.parent = directoryIndex(parent) orelse index;
|
d.parent = directoryIndex(parent) orelse index;
|
||||||
if (parent.len == 1) installMount(d.slice(), .kernel_initrd, null, "");
|
// Boot-time install of one mount per top-level initrd dir (/system, /test):
|
||||||
|
// provably few, far under maximum_mounts, so a full table here is
|
||||||
|
// impossible — but discard the result explicitly rather than assume it.
|
||||||
|
if (parent.len == 1) _ = installMount(d.slice(), .kernel_initrd, null, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +180,12 @@ fn directoryIndex(path: []const u8) ?usize {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn installMount(prefix: []const u8, kind: MountKind, backend: ?*ipc.Endpoint, rewrite: []const u8) void {
|
/// Install (or remount-replace) a prefix. Returns false when the table is full
|
||||||
|
/// and no slot could be claimed — the caller must surface that, never report a
|
||||||
|
/// dropped mount as success. A remount of an already-mounted prefix reuses its
|
||||||
|
/// slot and always succeeds; a /protocol remount is refused-as-noop (returns
|
||||||
|
/// true: the first mount stands, nothing is dropped).
|
||||||
|
fn installMount(prefix: []const u8, kind: MountKind, backend: ?*ipc.Endpoint, rewrite: []const u8) bool {
|
||||||
// Remount replaces: a restarted backend re-mounts its prefix.
|
// Remount replaces: a restarted backend re-mounts its prefix.
|
||||||
var slot: ?*Mount = null;
|
var slot: ?*Mount = null;
|
||||||
for (&mounts) |*m| {
|
for (&mounts) |*m| {
|
||||||
@@ -176,19 +194,20 @@ fn installMount(prefix: []const u8, kind: MountKind, backend: ?*ipc.Endpoint, re
|
|||||||
// restarted FAT retakes /volumes/usb; letting it retake /protocol
|
// restarted FAT retakes /volumes/usb; letting it retake /protocol
|
||||||
// would hand the whole naming layer to whoever asked second.
|
// would hand the whole naming layer to whoever asked second.
|
||||||
// First mount wins, and init (PID 1) is always first.
|
// First mount wins, and init (PID 1) is always first.
|
||||||
if (std.mem.eql(u8, prefix, protocol_root)) return;
|
if (std.mem.eql(u8, prefix, protocol_root)) return true;
|
||||||
if (m.backend) |old| ipc.dropRef(old);
|
if (m.backend) |old| ipc.dropRef(old);
|
||||||
slot = m;
|
slot = m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (slot == null and !m.used) slot = m;
|
if (slot == null and !m.used) slot = m;
|
||||||
}
|
}
|
||||||
const m = slot orelse return;
|
const m = slot orelse return false;
|
||||||
m.* = .{ .used = true, .kind = kind, .backend = backend };
|
m.* = .{ .used = true, .kind = kind, .backend = backend };
|
||||||
@memcpy(m.prefix[0..prefix.len], prefix);
|
@memcpy(m.prefix[0..prefix.len], prefix);
|
||||||
m.prefix_len = prefix.len;
|
m.prefix_len = prefix.len;
|
||||||
@memcpy(m.rewrite[0..rewrite.len], rewrite);
|
@memcpy(m.rewrite[0..rewrite.len], rewrite);
|
||||||
m.rewrite_len = rewrite.len;
|
m.rewrite_len = rewrite.len;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- resolve -----------------------------------------------------------------
|
// --- resolve -----------------------------------------------------------------
|
||||||
@@ -406,7 +425,7 @@ pub fn mountBackend(prefix: []const u8, backend: *ipc.Endpoint, rewrite: []const
|
|||||||
if (!isInitrdCarveOut(prefix)) return false;
|
if (!isInitrdCarveOut(prefix)) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
installMount(prefix, .backend, backend, rewrite);
|
if (!installMount(prefix, .backend, backend, rewrite)) return false; // table full
|
||||||
for (&mounts) |*m| {
|
for (&mounts) |*m| {
|
||||||
if (m.used and std.mem.eql(u8, m.prefixSlice(), prefix)) m.owner = owner;
|
if (m.used and std.mem.eql(u8, m.prefixSlice(), prefix)) m.owner = owner;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,6 @@ system/kernel/process.zig:write_buffer
|
|||||||
system/kernel/scheduler.zig:ipc_maximum_handles
|
system/kernel/scheduler.zig:ipc_maximum_handles
|
||||||
system/kernel/scheduler.zig:maximum_space_mappings
|
system/kernel/scheduler.zig:maximum_space_mappings
|
||||||
system/kernel/vfs.zig:maximum_directories
|
system/kernel/vfs.zig:maximum_directories
|
||||||
system/kernel/vfs.zig:maximum_mounts
|
|
||||||
system/kernel/vfs.zig:maximum_prefix
|
system/kernel/vfs.zig:maximum_prefix
|
||||||
system/kernel/vfs.zig:maximum_rewrite
|
system/kernel/vfs.zig:maximum_rewrite
|
||||||
system/services/acpi/acpi.zig:blocks
|
system/services/acpi/acpi.zig:blocks
|
||||||
|
|||||||
Reference in New Issue
Block a user