Single-block relocation: RELOCATE-BLOCK, resolve_lbn(), persisted exception table
Implements the full design from the prior commit in one pass. resolve_lbn()
is the single choke point threaded through the ten public LBN-consuming
entry points (blk_get_buffer, blk_update, blk_flush, blk_is_allocated,
blk_mark_allocated, blk_mark_free, blk_is_valid, blk_get_meta, blk_set_meta,
plus blk_get_empty_buffer covered via delegation) -- an LBN->LBN redirect,
not a new storage allocator, since the LBN space is already unified across
every attached blkio_dev backend. VM window cache staleness across a
relocation reuses the existing blk_vm_check_epoch() mechanism from
Milestone 2h's hot-detach fix for free -- g.epoch bumps on relocation too.
Persistence lands in the same pass: two new uint32_t fields
(reloc_start/reloc_devblocks) appended after hdr_crc in blk_volume_meta_t,
carved from existing padding without moving any earlier field's byte
offset -- an old formatted volume's zeroed padding reads back as
reloc_devblocks=0 ("no reloc capacity"), gracefully, not a format-breaking
change. compute_totals_from_B() generalized to account for the new
reserved region. reloc_flush_to_disk()/reloc_load_from_disk() mirror the
BAM I/O functions' own absolute-devblock-addressing shape; the persisted
copy's owner is first_disk_slot() (already existed, already used for this
exact "which device is canonical" question by blk_get_volume_meta()).
blk_subsys_relocate_block() is a mechanical primitive only -- copies
content (staged through a local buffer, since obtaining the target's
blk_get_buffer() result can evict and invalidate the source's cache
pointer if they share a device), frees the source BAM entry, appends the
exception entry, bumps the epoch, flushes to disk. RELOCATE-BLOCK exposes
it to FORTH, no policy of its own (ACL's job, per this session's direction).
A first live-test attempt gave a false negative against disk/artemis.img
(predates reloc capacity, so relocation only ever existed in memory that
boot) -- traced to the test's own setup before being mistaken for a bug,
then re-verified correctly against a fresh volume (new fixture,
disk/artemis-reloc-test.img): relocated a RAMDRIVE block to the fresh
disk, confirmed live resolution through the redirect, then confirmed both
the redirect and the relocated content survived an abrupt QEMU kill and
full reboot. Also fixed three lingering "glibc" doc-comment
misattributions from Milestone 2h (the actual allocator is this kernel's
own kmalloc) that survived an earlier FABRIC-2.md-only correction. All
three architectures re-verified clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
073dae4f56
commit
36d832ff47
@@ -113,7 +113,7 @@ typedef struct {
|
||||
/* BAM placement (external 1-bit bitmap region, stored in 4 KiB pages) */
|
||||
uint32_t bam_start; /* usually 1 */
|
||||
uint32_t bam_devblocks; /* number of 4 KiB pages used by BAM */
|
||||
uint32_t devblock_base; /* first payload devblock = bam_start + bam_devblocks */
|
||||
uint32_t devblock_base; /* first payload devblock = reloc_start + reloc_devblocks */
|
||||
|
||||
/* Capacity modeling (Forth 1 KiB blocks tracked/usable) */
|
||||
uint64_t tracked_blocks; /* 32768 * bam_devblocks (bits per 4 KiB page) */
|
||||
@@ -135,6 +135,15 @@ typedef struct {
|
||||
/* Optional integrity (unused yet) */
|
||||
uint64_t hdr_crc;
|
||||
|
||||
/* Relocation-exception table placement (Milestone 2h+ single-block relocation).
|
||||
* Appended after hdr_crc, carved out of what was previously _pad[] -- appending
|
||||
* (not inserting) preserves every earlier field's byte offset, so a pre-existing
|
||||
* formatted volume's zeroed padding reads back here as reloc_devblocks=0 ("no
|
||||
* reloc capacity"), gracefully, not a format-breaking change. See
|
||||
* block_subsystem.c's reloc_flush_to_disk()/reloc_load_from_disk(). */
|
||||
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) */
|
||||
|
||||
/* Padding to keep header ≤ 4096 bytes */
|
||||
uint8_t _pad[4096 - (
|
||||
4 + 4 + /* magic, version */
|
||||
@@ -145,7 +154,8 @@ typedef struct {
|
||||
8 + 8 + /* first_free, last_allocated */
|
||||
4 + 4 + /* reserved ranges */
|
||||
8 + 8 + /* timestamps */
|
||||
8 /* hdr_crc */
|
||||
8 + /* hdr_crc */
|
||||
4 + 4 /* reloc_start, reloc_devblocks */
|
||||
)];
|
||||
} blk_volume_meta_t;
|
||||
|
||||
@@ -236,15 +246,39 @@ int blk_subsys_detach_device(struct blkio_dev *dev);
|
||||
|
||||
/* Monotonic counter, bumped on every attach/detach (Milestone 2h). A raw
|
||||
* pointer comparison against a blk_get_buffer() result cannot reliably
|
||||
* detect a same-address device swap (glibc's allocator can hand back the
|
||||
* exact address just free()'d by a detach to the very next attach's
|
||||
* calloc()) -- callers that cache a blk_get_buffer() result across calls
|
||||
* detect a same-address device swap (this kernel's own first-fit kmalloc,
|
||||
* src/starkernel/memory/kmalloc.c, can hand back the exact address just
|
||||
* free()'d by a detach to the very next attach's calloc() -- confirmed
|
||||
* live) -- callers that cache a blk_get_buffer() result across calls
|
||||
* (block_words.c's VM block window) must instead compare this epoch
|
||||
* against the value they last observed, invalidating their whole cache on
|
||||
* any change rather than trusting a stored pointer's identity.
|
||||
*/
|
||||
uint64_t blk_subsys_epoch(void);
|
||||
|
||||
/* Single-block relocation. Copies home_lbn's current content to target_lbn
|
||||
* (both must already be valid LBNs -- target_lbn is expected to be a block
|
||||
* the caller's own identity already owns, on whichever device it's being
|
||||
* relocated to; this function does not itself validate ownership, that's
|
||||
* policy, left to the caller -- see this session's ACL-owns-policy
|
||||
* direction in FABRIC-2.md), frees home_lbn's original BAM entry, records
|
||||
* an LBN->LBN redirect so every future access to home_lbn transparently
|
||||
* resolves to target_lbn instead, and bumps blk_subsys_epoch() so any VM's
|
||||
* cached block window correctly invalidates. Persisted immediately to the
|
||||
* relocation-owner device's on-disk table (see block_subsystem.c's
|
||||
* reloc_flush_to_disk()) if one exists.
|
||||
*
|
||||
* Returns BLK_OK on success.
|
||||
* Returns BLK_EINVAL if home_lbn == target_lbn, or home_lbn is already
|
||||
* relocated (call again with a different target to re-relocate --
|
||||
* not supported by simply calling this twice on the same home_lbn).
|
||||
* Returns BLK_ERANGE if either LBN doesn't resolve to a valid device.
|
||||
* Returns BLK_EIO if the content copy fails (e.g. target device refuses
|
||||
* the write -- a read-only backend like blkio_usb.c today).
|
||||
* Returns BLK_ENOMEM if the in-memory relocation table is full.
|
||||
*/
|
||||
int blk_subsys_relocate_block(uint32_t home_lbn, uint32_t target_lbn);
|
||||
|
||||
int blk_subsys_shutdown(void);
|
||||
|
||||
uint8_t *blk_get_buffer(uint32_t block_num, int writable);
|
||||
|
||||
Reference in New Issue
Block a user