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:
co-authored by
Claude Sonnet 5
parent
2035ebeac0
commit
6e9c1d3bc2
+37
-3
@@ -570,9 +570,43 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
fresh format writes `meta_fence_blocks=128` at header byte offset 184; a second boot without
|
||||
reformatting reads it back unchanged; the pre-existing old-format image correctly reads back
|
||||
0. Full 3-arch acceptance boot against the real, untouched `disk/artemis.img` also clean —
|
||||
conservation intact, no panics. The allocator (`user_blocks` math) still doesn't know about
|
||||
this reservation yet, and there are no read/write accessors for the zone's actual data —
|
||||
both still open, next steps.
|
||||
conservation intact, no panics.
|
||||
|
||||
**Step 2 (allocator + read/write accessors), done 2026-08-26.** Units corrected 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, since nothing consumed the
|
||||
field yet. This let the fence fold directly into `compute_totals_from_B()`'s existing
|
||||
`payload4k` calculation (`total_devblocks - 1 - B - R - F`, F = `meta_fence_blocks`) instead
|
||||
of needing a second, separate subtraction against `user_blocks` — `total_blocks`,
|
||||
`user_blocks`, and `free_blocks` all shrink correctly for free, in both the fresh-format and
|
||||
reload code paths, from this one formula change.
|
||||
|
||||
New `blk_meta_zone_read()`/`blk_meta_zone_write()` (`block_subsystem.c`/`.h`) — raw, unpacked
|
||||
4 KiB devblock I/O (no Forth-block packing, same shape as the header/BAM/reloc-table
|
||||
regions), addressed by `devblock_from_top` counting down from the device's last physical
|
||||
devblock, refusing (not silently clamping) if the index isn't within the on-disk
|
||||
`meta_fence_blocks`. No FORTH word wraps either — C-only, same discipline as
|
||||
`vm_zuse_cert_install()` itself, which will be this zone's first real tenant.
|
||||
|
||||
**Verified independently at every step, never trusting the kernel's own report:**
|
||||
- Capacity math: read a freshly-formatted image's header bytes directly and independently
|
||||
recomputed the expected `total_blocks` in a separate Python script using the same formula
|
||||
— exact match (22647, down from what it would have been without the fence).
|
||||
- Accessor correctness: a temporary probe (written, run, captured, reverted) wrote a known
|
||||
256-byte-repeating pattern via `blk_meta_zone_write(0, ...)`, read it back via
|
||||
`blk_meta_zone_read(0, ...)`, and compared in-memory (`PASS`) — then, independently,
|
||||
read the raw image file at the exact expected physical byte offset
|
||||
(`(total_devblocks-1)*4096`) and confirmed the pattern landed there byte-for-byte.
|
||||
- `log_message(LOG_INFO, ...)` still doesn't reach serial output in this build (same
|
||||
pre-existing gap noted in Step 1) — all verification here used `console_println` (which
|
||||
does reach serial) for the temporary probe, and direct file reads for everything else.
|
||||
|
||||
Full 3-arch acceptance boot (real, untouched `disk/artemis.img`, probe code fully reverted)
|
||||
clean on all three architectures — conservation intact, no panics.
|
||||
|
||||
**Still open:** wiring `vm_zuse_cert_install()`'s seed+pubkey to actually persist through
|
||||
these new accessors (the zone exists and works; nothing writes Zuse's cert into it yet), and
|
||||
the `MINT` word itself.
|
||||
|
||||
### From FABRIC-2.md §X, Milestone 5 — Console/VM key-match binding
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-26T23:14:17Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-26T23:37:35Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
+34
-14
@@ -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
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+44
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user