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:
co-authored by
Claude Sonnet 5
parent
e5cbc71f46
commit
2035ebeac0
+48
@@ -526,6 +526,54 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
commented-out default. Verified clean compile and clean boot on all three architectures in
|
||||
this reverted state.
|
||||
|
||||
**Substrate corrected (Captain Bob, 2026-08-26): no files, ever — this OS's entire reason
|
||||
for being is anti-POSIX, anti-file.** The "dedicated system-identity disk" recommendation
|
||||
above was framed in file/filesystem language by mistake; corrected before any code was
|
||||
written. The only real persistence primitives here are content-addressed capsules and raw
|
||||
LBN-numbered blocks (`block_subsystem.c`) — never a filesystem, never file paths. Saved as
|
||||
`feedback_no_files_anti_posix.md` so this isn't re-learned next session.
|
||||
|
||||
**Design, agreed on request: a growable metadata fence at the TOP of a device's block
|
||||
space, mirroring the bottom BAM reservation from the opposite end.** `block_subsystem.c`'s
|
||||
BAM already reserves the bottom `BLK_DISK_SYS_RESERVED` (32) blocks of every attached
|
||||
device, invisible to FORTH's `BLOCK`/`BUFFER`. Zuse's cert (and future system metadata)
|
||||
gets a second reservation at the *top* of the same device, starting at
|
||||
`BLK_META_FENCE_INIT` (128) blocks and growing downward as needed — the two reservations
|
||||
grow toward each other from opposite ends, never colliding, same shape as a stack/heap.
|
||||
Explicitly never RAM-backed (the fast-RAM/ramdrive LBN ranges are documented as volatile in
|
||||
this same file's own header comment — losing Zuse's identity to a RAM eviction is exactly
|
||||
the failure this is designed against). Reuses Artemis's own already-attached, already-proven
|
||||
virtio-blk device — no new device attachment. Rejected reusing BAM's own bottom-reserved
|
||||
zone directly: those 32 blocks are fully claimed by BAM/volume-metadata bookkeeping, not
|
||||
free space.
|
||||
|
||||
**Step 1 (field round-trip) implemented and verified 2026-08-26, allocator not yet
|
||||
touched.** New `meta_fence_blocks` field in `blk_volume_meta_t`, appended after
|
||||
`reloc_devblocks` and carved from `_pad[]` — identical graceful-default technique the
|
||||
`reloc_start`/`reloc_devblocks` fields already established (a pre-existing formatted volume
|
||||
reads the field back as 0 via its zeroed former padding, not a format-breaking change).
|
||||
Added a compile-time `_Static_assert(sizeof(blk_volume_meta_t) == 4096, ...)`, same
|
||||
discipline `homeblocks_sig.h` already uses — caught a real bug immediately: the hand-summed
|
||||
`_pad[]` size formula was off by 4 bytes (a compiler-inserted alignment gap before
|
||||
`tracked_blocks` that the manual byte-count missed), found via `offsetof()` rather than by
|
||||
re-deriving the arithmetic by hand again, consistent with this project's standing rule to
|
||||
never trust a hand-derived numeric claim in this class of code.
|
||||
|
||||
Worked against disposable clones throughout, never the real `disk/artemis.img`
|
||||
(`ARTDISK=...` is `?=`-overridable) — `disk/artemis-metafence-fresh.img` (blank, exercises
|
||||
the fresh-format path) and `disk/artemis-metafence-test.img` (a copy of the pre-existing
|
||||
`artemis.img`, exercises the graceful-default-on-reload path), both kept as regression
|
||||
fixtures per `disk/README.md`'s existing convention (mirrors `artemis-reloc-test.img`
|
||||
exactly). **Verified independently via direct byte reads of the disk image, not the
|
||||
kernel's own self-report** (`log_message(LOG_INFO, ...)` turned out not to reach serial
|
||||
output at all in this build — an unrelated, pre-existing log-level gap, not a regression):
|
||||
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.
|
||||
|
||||
### From FABRIC-2.md §X, Milestone 5 — Console/VM key-match binding
|
||||
|
||||
- [ ] Settle the still-open question: reuse `ACL-PIN`/`acl_allow` directly, or build a
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-26T19:54:10Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-26T23:14:17Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
@@ -83,6 +83,25 @@ carrying timestamp noise in git history.
|
||||
`BLK-CONFIRM-FORMAT`-committed in the repo copy — commit that step live if
|
||||
reusing this fixture for further reloc-table testing.
|
||||
|
||||
- `artemis-metafence-fresh.img` — 30MB raw image, blank at creation,
|
||||
added 2026-08-26 for the top-of-device system-metadata fence
|
||||
(`meta_fence_blocks` in `blk_volume_meta_t`, FABRIC-3.md Phase 8 §C).
|
||||
Same reasoning as `artemis-reloc-test.img` above: the fence is only
|
||||
initialized to `BLK_META_FENCE_INIT` (128) by
|
||||
`blk_compute_fresh_geometry()` on a fresh format, so a genuinely blank
|
||||
volume was needed to exercise that path. Verified round-trip: fresh
|
||||
format writes 128 (confirmed via direct byte read at header offset 184,
|
||||
independent of kernel self-report), a second boot without reformatting
|
||||
reads it back unchanged. Keep in its formatted (`meta_fence_blocks=128`)
|
||||
state — a future change that resets or corrupts this on reload is a
|
||||
real regression.
|
||||
- `artemis-metafence-test.img` — 30MB raw image, a direct copy of the
|
||||
pre-existing (pre-fence) `artemis.img`, added 2026-08-26 alongside the
|
||||
fixture above to verify the *other* direction: an old volume that
|
||||
predates `meta_fence_blocks` correctly reads it back as 0 (graceful
|
||||
default via zeroed former padding, not corruption) rather than crashing
|
||||
or misreading adjacent fields.
|
||||
|
||||
- `zuse.img` — 64MB raw image simulating the physical Zuse superuser
|
||||
thumbdrive for QEMU testing (FABRIC-3.md, Phase 8: `zuse.img` "bleach"
|
||||
mechanism, added 2026-08-26). **64MB is only this fixture's size, not a
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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) */
|
||||
|
||||
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
File diff suppressed because it is too large
Load Diff
@@ -526,6 +526,7 @@ static void blk_compute_fresh_geometry(blk_dev_slot_t *slot) {
|
||||
* variable-size region that might need to grow later. */
|
||||
slot->vol_meta.reloc_devblocks = 1;
|
||||
slot->vol_meta.devblock_base = slot->vol_meta.reloc_start + slot->vol_meta.reloc_devblocks;
|
||||
slot->vol_meta.meta_fence_blocks = BLK_META_FENCE_INIT;
|
||||
compute_totals_from_B(&slot->vol_meta);
|
||||
|
||||
if (sf_has_rtc()) slot->vol_meta.created_time = sf_realtime_ns();
|
||||
@@ -701,14 +702,15 @@ int blk_subsys_attach_device(struct blkio_dev *dev) {
|
||||
|
||||
log_message(LOG_INFO,
|
||||
"blk: disk '%s' v2 LBN %u..%u (%u user blocks); "
|
||||
"devblocks=%llu bam=%u base=%u total=%llu free=%llu",
|
||||
"devblocks=%llu bam=%u base=%u total=%llu free=%llu fence=%u",
|
||||
slot->vol_meta.label,
|
||||
slot->start_lbn, slot->start_lbn + slot->user_blocks - 1,
|
||||
slot->user_blocks,
|
||||
(unsigned long long) slot->vol_meta.total_devblocks,
|
||||
slot->vol_meta.bam_devblocks, slot->vol_meta.devblock_base,
|
||||
(unsigned long long) slot->vol_meta.total_blocks,
|
||||
(unsigned long long) slot->vol_meta.free_blocks);
|
||||
(unsigned long long) slot->vol_meta.free_blocks,
|
||||
slot->vol_meta.meta_fence_blocks);
|
||||
return BLK_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user