Phase 8 C (4/n): metadata fence allocator integration + zone I/O

Corrected meta_fence_blocks units from "Forth 1 KiB blocks" to 4 KiB
devblocks (matching bam_devblocks/reloc_devblocks) before anything
depended on the original meaning -- a clean fix, not a migration. This
let the fence fold directly into compute_totals_from_B()'s existing
payload4k formula (total_devblocks - 1 - B - R - F) instead of a
separate user_blocks subtraction: total_blocks/user_blocks/free_blocks
all shrink correctly for free, in both the fresh-format and reload
paths, from one formula change.

New blk_meta_zone_read()/blk_meta_zone_write() -- raw, unpacked 4 KiB
devblock I/O, same shape as the header/BAM/reloc-table regions,
addressed by devblock_from_top counting down from the device's last
physical devblock. Refuses rather than clamps if the index exceeds the
on-disk meta_fence_blocks. C-only, no FORTH word wraps either -- same
discipline as vm_zuse_cert_install(), which will be this zone's first
real tenant.

Verified independently at every step, never trusting the kernel's own
report: capacity math cross-checked against a from-scratch Python
recomputation of the same formula (exact match); accessor correctness
via a temporary probe (written/run/captured/reverted) that wrote a
known pattern and read it back, then independently confirmed via a raw
read of the disk image at the exact expected physical byte offset.
Full 3-arch acceptance boot against the real, untouched disk/artemis.img,
probe code fully reverted -- clean, conservation intact.

Still open: wiring vm_zuse_cert_install() to actually persist through
these accessors, and the MINT word itself. Documented in FABRIC-3.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U14ET9CWAtbQMbYqomKgXd
This commit is contained in:
Robert Allan James
2026-08-26 19:40:43 -04:00
co-authored by Claude Sonnet 5
parent 2035ebeac0
commit 6e9c1d3bc2
12 changed files with 54356 additions and 19 deletions
+34 -14
View File
@@ -90,8 +90,9 @@ extern "C" {
#define BLK_DISK_SYS_RESERVED 32u /* First 32 blocks of each disk reserved (byte-aligned BAM offset) */
#endif
#ifndef BLK_META_FENCE_INIT
#define BLK_META_FENCE_INIT 128u /* Starting size (Forth 1 KiB blocks) of the top-of-device
* system-metadata fence, grows downward from here. */
#define BLK_META_FENCE_INIT 128u /* Starting size (4 KiB devblocks -- 512 KiB) of the
* top-of-device system-metadata fence, grows downward
* from here. */
#endif
/* =========================
@@ -148,18 +149,26 @@ typedef struct {
uint32_t reloc_start; /* usually bam_start + bam_devblocks */
uint32_t reloc_devblocks; /* number of 4 KiB pages used by the reloc table (0 = none) */
/* System-metadata fence (Phase 8, 2026-08-26): a reserved zone at the
* TOP of the device's Forth block space, opposite end from
* reserved_disk_lo's bottom BAM reservation, growing DOWNWARD as
* system metadata (starting with Zuse's cert) needs more room.
* Never RAM-backed -- this field only exists on real disk-backed
* slots. Appended after reloc_devblocks, carved out of what was
* previously _pad[] -- same graceful-default technique as
* reloc_devblocks itself: a pre-existing formatted volume's zeroed
* padding reads back here as meta_fence_blocks=0 ("no fence yet"),
* not a format-breaking change. See FABRIC-3.md's Phase 8 §C
* writeup for the full design. */
uint32_t meta_fence_blocks; /* current fence size, in Forth 1 KiB blocks (0 = none yet) */
/* System-metadata fence (Phase 8, 2026-08-26): a reserved zone of
* whole, RAW (unpacked -- same shape as the header/BAM/reloc-table
* devblocks, not the 3-Forth-blocks-per-devblock user payload
* packing) devblocks at the TOP of the device's payload region,
* opposite end from reserved_disk_lo's bottom BAM reservation,
* growing DOWNWARD as system metadata (starting with Zuse's cert)
* needs more room. Never RAM-backed -- this field only exists on
* real disk-backed slots. Units are 4 KiB devblocks, same as
* bam_devblocks/reloc_devblocks (NOT Forth 1 KiB blocks -- corrected
* 2026-08-26, before anything depended on the original wrong unit,
* so this reads as a clean field, not a migration). Folded directly
* into compute_totals_from_B()'s payload4k calculation, so
* total_blocks/user_blocks/free_blocks all shrink correctly with no
* separate subtraction needed elsewhere. Appended after
* reloc_devblocks, carved out of what was previously _pad[] -- same
* graceful-default technique as reloc_devblocks itself: a
* pre-existing formatted volume's zeroed padding reads back here as
* meta_fence_blocks=0 ("no fence yet"), not a format-breaking
* change. See FABRIC-3.md's Phase 8 §C writeup for the full design. */
uint32_t meta_fence_blocks; /* current fence size, in 4 KiB devblocks (0 = none yet) */
/* Padding to keep header ≤ 4096 bytes */
uint8_t _pad[4096 - (
@@ -324,6 +333,17 @@ int blk_get_volume_meta(blk_volume_meta_t *meta);
int blk_set_volume_meta(const blk_volume_meta_t *meta);
/* Top-of-device system-metadata fence I/O (Phase 8, 2026-08-26) -- raw,
* unpacked 4 KiB devblocks, no FORTH word wraps either. See
* block_subsystem.c's own doc comment on these two functions for the
* full addressing/refusal rules. buf must point to exactly 4096 bytes.
* Returns BLK_OK, BLK_ENODEV (no disk-backed device attached),
* BLK_EINVAL (devblock_from_top >= the on-disk fence size, or NULL buf),
* or BLK_EIO (underlying blkio read/write failed). */
int blk_meta_zone_read(uint32_t devblock_from_top, uint8_t buf[4096]);
int blk_meta_zone_write(uint32_t devblock_from_top, const uint8_t buf[4096]);
/* CRC-64/ISO (poly 0x42F0E1EBA9EA3693), reflected, init/final all-ones --
* exposed for homeblocks_sig.c's drive-signature integrity check, which
* needs the exact same algorithm this file already uses for per-block