Fix blk_meta_t/BAM accounting reconciliation flagged in FABRIC-2.md §I.2

FIRSTTOUCH ownership (blk_meta_t's BLK_FLAG_CLAIMED/owner_fp) and the
generic block-allocation bitmap (BAM, blk_bam_entry_t) were two parallel,
unreconciled accounting systems: blk_firsttouch_claim() never touched the
BAM, and blk_allocate()/devblock_is_free() never checked BLK_FLAG_CLAIMED.
A FIRSTTOUCH claim could be silently overwritten by a later blk_allocate()
call, or could itself steal a devblock already in ordinary use via
BLOCK/UPDATE.

- devblock_is_free() (shared by blk_firsttouch_claim() and
  blk_migration_idle_check()) now also checks the BAM entries of all
  BLK_PACK_RATIO member LBNs, not just blk_meta_t.
- New devblock_claimed_by_lbn() helper wired into blk_allocate()'s
  free-scan, so it skips any LBN whose devblock is BLK_FLAG_CLAIMED.
- blk_firsttouch_claim() now marks the BAM allocated for all 3 member
  LBNs of each devblock it claims, which also fixes vol_meta.free_blocks
  never decrementing for FIRSTTOUCH claims.
- blk_meta_relocate_devblock() traced and confirmed NOT part of the bug —
  it already keeps BAM in sync via blk_subsys_relocate_block()'s own
  blk_mark_free()/blk_update() calls.

Both boundary cases (the reserved/user LBN split at a slot's start_lbn,
and BAM-array bounds) are guarded explicitly.

Verified with the mandatory 3-arch QEMU acceptance (identical dictionary
hashes, clean BYE) plus a live logic test: a temporary TEST-BAM-RECON
word, run once via SK_CMD and fully reverted, confirmed on running code
that ordinary allocation and a FIRSTTOUCH claim land on disjoint LBN
ranges in both directions. FABRIC-2.md §I.2 updated in place with the
closure note, per this project's documentation discipline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EjXFo7mPXjUMjfJeuUUz4
This commit is contained in:
Robert Allan James
2026-09-05 15:57:03 -04:00
co-authored by Claude Sonnet 5
parent 04cc17920e
commit aa33aedca8
3 changed files with 90 additions and 6 deletions
+24
View File
@@ -4441,6 +4441,30 @@ stale the way the original carry-forwards did.
Not fixed in this pass; flagged precisely so it isn't rediscovered as a mystery later.
*(Same location as above.)*
**CLOSED 2026-09-05.** Traced against current code before writing anything, per this
document's own discipline: `blk_meta_relocate_devblock()` turned out **not** to be part of
the gap after all — it calls `blk_subsys_relocate_block()` per member block, which already
calls `blk_mark_free()` on the home LBN and `blk_update()` (which sets the BAM bit) on the
target, so relocation was already keeping BAM in sync. The real gap was entirely in
`blk_firsttouch_claim()`'s side (never touched BAM at all) and in the reverse direction
(`devblock_is_free()`/`blk_allocate()` never checked `BLK_FLAG_CLAIMED`), confirmed by a
full-documentation audit ([[project_fabric012_full_audit_20260905]] in memory) before
fixing. **Fix** (`block_subsystem.c`): `devblock_is_free()` (shared by
`blk_firsttouch_claim()` and `blk_migration_idle_check()`) now also checks the BAM entries of
all `BLK_PACK_RATIO` member LBNs, not just `blk_meta_t`; a new `devblock_claimed_by_lbn()`
helper is wired into `blk_allocate()`'s free-scan so it skips any LBN whose devblock is
`BLK_FLAG_CLAIMED`; `blk_firsttouch_claim()` now calls `blk_mark_allocated()` on all 3 member
LBNs of each devblock it claims, which also fixes a quiet side effect where
`vol_meta.free_blocks` never decremented for FIRSTTOUCH claims. Both boundary edge cases
(the reserved/user LBN split at a slot's own `start_lbn`, and BAM-array bounds) are guarded
explicitly rather than assumed safe. **Verified, not just compiled clean**: full 3-arch QEMU
acceptance (identical dictionary hashes, clean `BYE`, no regression) plus a live logic test —
a temporary `TEST-BAM-RECON` word (written, run once via `SK_CMD`, then fully reverted,
per this project's own probe discipline) ordinary-allocated 4 LBNs, `FIRSTTOUCH`-claimed 2
devblocks, and confirmed on real running code that neither direction of the gap reproduces:
the ordinary allocations and the claim landed on disjoint LBN ranges, and `blk_allocate()`
never returned an LBN from the claimed range afterward. `PASS`, no `FAIL` lines.
### I.3 — Milestone 5 remainder (BINDSTEP) — CLOSED 2026-09-04
- [x] **`EJECT` / detach behavior.** Scoped 2026-08-27 (§F.10): flush via