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
@@ -159,9 +159,10 @@ void empty_all_buffers(VM *vm) {
|
||||
* it was last validated (Milestone 2h). A device hot-detach followed by a
|
||||
* later re-attach can reuse both the exact same LBN range
|
||||
* (block_subsystem.c's chain always appends at the current tail) *and* the
|
||||
* exact same blk_get_buffer() return address (confirmed live: glibc's
|
||||
* allocator hands the just-freed slot straight back to the very next
|
||||
* same-size calloc()), so neither LBN nor a cached pointer is a reliable
|
||||
* exact same blk_get_buffer() return address (confirmed live: this
|
||||
* kernel's own first-fit kmalloc, src/starkernel/memory/kmalloc.c, hands
|
||||
* the just-freed slot straight back to the very next same-size
|
||||
* calloc()), so neither LBN nor a cached pointer is a reliable
|
||||
* "still the same device" signal on its own. Any epoch change discards
|
||||
* every cached slot outright -- no flush attempt, matching
|
||||
* blk_subsys_detach_device()'s own reasoning: whatever device the stale
|
||||
@@ -353,6 +354,22 @@ void block_word_confirm_format(VM *vm) {
|
||||
if (blk_subsys_confirm_format((uint32_t) blk) != BLK_OK) { vm->error = 1; return; }
|
||||
}
|
||||
|
||||
/* RELOCATE-BLOCK ( home target -- ) : relocate home's content to target,
|
||||
* redirecting all future access to home transparently through target
|
||||
* from now on. See blk_subsys_relocate_block()'s own doc comment
|
||||
* (block_subsystem.h) for the full contract -- this word performs no
|
||||
* policy validation of its own (is target actually free? does the
|
||||
* caller actually own it?), matching this project's "ACL owns policy,
|
||||
* this is a mechanical primitive" direction. */
|
||||
void block_word_relocate(VM *vm) {
|
||||
if (vm->dsp < 1) { vm->error = 1; return; }
|
||||
cell_t target = vm_pop(vm);
|
||||
cell_t home = vm_pop(vm);
|
||||
if (blk_subsys_relocate_block((uint32_t) home, (uint32_t) target) != BLK_OK) {
|
||||
vm->error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* SAVE-BUFFERS ( -- ) : sync and write all dirty blocks */
|
||||
void block_word_save_buffers(VM *vm) {
|
||||
blk_vm_flush_all(vm);
|
||||
@@ -532,6 +549,7 @@ void register_block_words(VM *vm) {
|
||||
register_word(vm, "BUFFER", block_word_buffer);
|
||||
register_word(vm, "UPDATE", block_word_update);
|
||||
register_word(vm, "BLK-CONFIRM-FORMAT", block_word_confirm_format);
|
||||
register_word(vm, "RELOCATE-BLOCK", block_word_relocate);
|
||||
register_word(vm, "SAVE-BUFFERS", block_word_save_buffers);
|
||||
register_word(vm, "EMPTY-BUFFERS", block_word_empty_buffers);
|
||||
register_word(vm, "FLUSH", block_word_flush);
|
||||
|
||||
Reference in New Issue
Block a user