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
+44 -1
View File
@@ -362,8 +362,9 @@ static uint32_t choose_B(uint64_t total_devblocks_4k) {
static void compute_totals_from_B(blk_volume_meta_t *m) {
uint64_t B = m->bam_devblocks;
uint64_t R = m->reloc_devblocks; /* reserved relocation-table region, see blk_volume_meta_t's own doc comment */
uint64_t F = m->meta_fence_blocks; /* top-of-device system-metadata fence, see blk_volume_meta_t's own doc comment */
m->tracked_blocks = 32768ULL * B;
uint64_t payload4k = (m->total_devblocks > (1+B+R)) ? (m->total_devblocks - 1 - B - R) : 0;
uint64_t payload4k = (m->total_devblocks > (1+B+R+F)) ? (m->total_devblocks - 1 - B - R - F) : 0;
uint64_t storable = 3ULL * payload4k;
m->total_blocks = (m->tracked_blocks < storable) ? m->tracked_blocks : storable;
uint64_t reserved = (uint64_t) BLK_DISK_SYS_RESERVED;
@@ -1117,6 +1118,48 @@ int blk_set_volume_meta(const blk_volume_meta_t *meta) {
return BLK_OK;
}
/*
* Top-of-device system-metadata fence I/O (Phase 8, 2026-08-26).
* Raw, unpacked 4 KiB devblocks -- no Forth-block packing, same shape as
* the header/BAM/reloc-table regions. devblock_from_top counts down from
* the very last physical devblock of the canonical device (0 = last,
* 1 = second-to-last, ...); must be < the on-disk meta_fence_blocks or
* this refuses rather than silently reading/writing outside the
* reservation. Operates on the same "canonical device" first_disk_slot()
* already establishes for blk_get_volume_meta()/the relocation table.
* No FORTH word wraps this -- C-only, same discipline as
* vm_zuse_cert_install() itself; Zuse's cert is this zone's first tenant.
*/
int blk_meta_zone_read(uint32_t devblock_from_top, uint8_t buf[4096]) {
if (!buf) return BLK_EINVAL;
blk_dev_slot_t *slot = first_disk_slot();
if (!slot || !slot->dev) return BLK_ENODEV;
if (devblock_from_top >= slot->vol_meta.meta_fence_blocks) return BLK_EINVAL;
uint64_t devblock_idx = slot->vol_meta.total_devblocks - 1ULL - devblock_from_top;
uint32_t base1k = (uint32_t) devblock_idx * 4u;
for (uint32_t k = 0; k < 4; k++) {
if (blkio_read(slot->dev, base1k + k, buf + k * 1024u) != BLKIO_OK)
return BLK_EIO;
}
return BLK_OK;
}
int blk_meta_zone_write(uint32_t devblock_from_top, const uint8_t buf[4096]) {
if (!buf) return BLK_EINVAL;
blk_dev_slot_t *slot = first_disk_slot();
if (!slot || !slot->dev) return BLK_ENODEV;
if (devblock_from_top >= slot->vol_meta.meta_fence_blocks) return BLK_EINVAL;
uint64_t devblock_idx = slot->vol_meta.total_devblocks - 1ULL - devblock_from_top;
uint32_t base1k = (uint32_t) devblock_idx * 4u;
for (uint32_t k = 0; k < 4; k++) {
if (blkio_write(slot->dev, base1k + k, buf + k * 1024u) != BLKIO_OK)
return BLK_EIO;
}
return BLK_OK;
}
int blk_is_valid(uint32_t block_num) {
if (!g.initialized) return 0;
block_num = resolve_lbn(block_num);