Phase 8 C (3/n): top-of-device metadata fence, step 1 (field round-trip)

Corrected substrate: this OS is anti-POSIX, anti-file by design -- the
prior "dedicated system-identity disk" framing was wrong vocabulary,
caught before any code was written (saved as
feedback_no_files_anti_posix.md). The real primitives are
content-addressed capsules and raw LBN blocks, never a filesystem.

Design (agreed on request): a growable metadata fence at the TOP of a
device's block space, mirroring block_subsystem.c's existing bottom BAM
reservation from the opposite end -- the two grow toward each other,
never colliding, same shape as a stack/heap. Starts at
BLK_META_FENCE_INIT (128 blocks), explicitly never RAM-backed. Reuses
Artemis's already-attached, already-proven virtio-blk device -- no new
device. Rejected reusing BAM's own reserved zone directly: those blocks
are fully claimed by BAM bookkeeping, not free space.

Step 1 only: new meta_fence_blocks field in blk_volume_meta_t, appended
after reloc_devblocks and carved from _pad[] -- identical graceful-
default technique reloc_devblocks already established (a pre-existing
volume reads it back as 0, not a format break). Added a compile-time
_Static_assert on the struct's total size, same discipline
homeblocks_sig.h uses -- caught a real bug immediately: the hand-summed
_pad[] formula was off by 4 bytes (a compiler alignment gap the manual
count missed), found via offsetof() rather than re-deriving by hand.

Worked against disposable clones throughout, never the real
disk/artemis.img (ARTDISK is ?=-overridable) -- artemis-metafence-fresh.img
(blank, fresh-format path) and artemis-metafence-test.img (copy of the
pre-existing artemis.img, graceful-default-on-reload path), kept as
regression fixtures matching disk/README.md's existing convention.
Verified independently via direct byte reads of the disk image, not the
kernel's own log output (log_message(LOG_INFO,...) doesn't reach serial
in this build -- unrelated pre-existing gap): fresh format writes 128 at
header offset 184, a reboot without reformatting preserves it, the old
pre-fence image reads back 0. Full 3-arch acceptance boot against the
real, untouched disk/artemis.img also clean.

Allocator (user_blocks math) and zone read/write accessors both still
open -- next steps, 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:18:21 -04:00
co-authored by Claude Sonnet 5
parent e5cbc71f46
commit 2035ebeac0
15 changed files with 63373 additions and 4 deletions
+32 -1
View File
@@ -89,6 +89,10 @@ extern "C" {
#ifndef BLK_DISK_SYS_RESERVED
#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. */
#endif
/* =========================
* On-disk volume header v2
@@ -144,10 +148,28 @@ 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) */
/* Padding to keep header ≤ 4096 bytes */
uint8_t _pad[4096 - (
4 + 4 + /* magic, version */
4 + 4 + 64 + /* total_volumes, flags, label */
4 + /* compiler alignment gap before total_devblocks'
* uint64_t sibling tracked_blocks -- verified via
* offsetof(), not hand-derived (2026-08-26: this
* exact formula was off by 4 bytes from trusting
* arithmetic alone before this fix) */
8 + /* total_devblocks */
4 + 4 + 4 + /* bam_start, bam_devblocks, devblock_base */
8 + 8 + 8 + /* tracked_blocks, total_blocks, free_blocks */
@@ -155,10 +177,19 @@ typedef struct {
4 + 4 + /* reserved ranges */
8 + 8 + /* timestamps */
8 + /* hdr_crc */
4 + 4 /* reloc_start, reloc_devblocks */
4 + 4 + /* reloc_start, reloc_devblocks */
4 /* meta_fence_blocks */
)];
} blk_volume_meta_t;
/* Same discipline homeblocks_sig.h's own header-size check uses: the pad
* math above is meant to keep this struct at exactly one 4 KiB devblock,
* verified at compile time rather than trusted by inspection -- adding
* meta_fence_blocks is exactly the kind of edit that could silently
* throw this off by a few bytes. */
_Static_assert(sizeof(blk_volume_meta_t) == 4096,
"blk_volume_meta_t must be exactly one 4 KiB devblock");
/* Per-1 KiB block metadata (packed into top 1 KiB region of each 4 KiB sector). */
typedef struct {
/* Core integrity (16 bytes) */