wip(blocks): a BAM flush reads and writes only the pages that hold the volume's bits (#155) [skip ci]
Not yet accepted. bam_flush_to_disk() and bam_sync_from_disk() read and wrote every page of the BAM; with the stick's BAM sized for 256 GiB (6144 devblocks, 24 MiB) every flush of a dirty block moved 24 MiB each way. They now touch only the pages that hold the slot's bits -- its reserved bits and one per user block (bam_pages_used()) -- the pages past them are never set, so the bytes on disk are the same. Test (qemu_session.py bam_flush, --target qemu-stick --stick-gib 16): three SAVE-BUFFERS of an Artemis block, each timed, then the BAM hashed. Before: 5.1 / 5.6 / 6.1 s (the 2 s limit fails; it was set after seeing this baseline). After: 1.1 / 1.1 / 1.1 s. The BAM's bytes the same either way: sha256 79197a40...b9e44b50, 5 non-zero bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
@@ -402,6 +402,19 @@ void blk_subsys_set_format_bam_for(uint64_t total_devblocks) {
|
||||
|
||||
/* ===== physical BAM I/O (sync to/from slot->bam[]) ===== */
|
||||
|
||||
/* The BAM pages that hold a slot's bits: its reserved bits and one per user
|
||||
* block (bit i is in page i / 32768). A BAM sized for a larger volume than
|
||||
* the slot is -- the stick's, sized for 256 GiB -- has pages past these that
|
||||
* no allocation ever sets, so they are neither read nor written: the bytes on
|
||||
* disk are the same, and a flush of a 2 GiB volume no longer moves a 24 MiB
|
||||
* BAM (#155). */
|
||||
static uint32_t bam_pages_used(const blk_dev_slot_t *slot) {
|
||||
uint64_t bits = (uint64_t) BLK_DISK_SYS_RESERVED + slot->user_blocks;
|
||||
uint64_t pages = (bits + 32767ULL) / 32768ULL;
|
||||
uint32_t b = slot->vol_meta.bam_devblocks;
|
||||
return (pages < (uint64_t) b) ? (uint32_t) pages : b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read physical BAM from disk; populate slot->bam[i].allocated for user blocks.
|
||||
* Physical bit [BLK_DISK_SYS_RESERVED + i] → slot->bam[i].allocated.
|
||||
@@ -410,11 +423,12 @@ static int bam_sync_from_disk(blk_dev_slot_t *slot) {
|
||||
blk_volume_meta_t *m = &slot->vol_meta;
|
||||
if (!slot->dev || m->bam_devblocks == 0) return BLK_EINVAL;
|
||||
|
||||
size_t psize = (size_t)4096u * m->bam_devblocks;
|
||||
uint32_t npages = bam_pages_used(slot);
|
||||
size_t psize = (size_t)4096u * npages;
|
||||
uint8_t *pbam = (uint8_t *) calloc(1, psize);
|
||||
if (!pbam) return BLK_ENOMEM;
|
||||
|
||||
for (uint32_t i = 0; i < m->bam_devblocks; i++) {
|
||||
for (uint32_t i = 0; i < npages; i++) {
|
||||
uint32_t base1k = (m->bam_start + i) * 4u;
|
||||
for (uint32_t k = 0; k < 4; k++) {
|
||||
if (blkio_read(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK)
|
||||
@@ -439,12 +453,13 @@ static int bam_flush_to_disk(blk_dev_slot_t *slot) {
|
||||
blk_volume_meta_t *m = &slot->vol_meta;
|
||||
if (m->bam_devblocks == 0) return BLK_OK;
|
||||
|
||||
size_t psize = (size_t)4096u * m->bam_devblocks;
|
||||
uint32_t npages = bam_pages_used(slot);
|
||||
size_t psize = (size_t)4096u * npages;
|
||||
uint8_t *pbam = (uint8_t *) calloc(1, psize);
|
||||
if (!pbam) return BLK_ENOMEM;
|
||||
|
||||
/* read current on-disk BAM */
|
||||
for (uint32_t i = 0; i < m->bam_devblocks; i++) {
|
||||
for (uint32_t i = 0; i < npages; i++) {
|
||||
uint32_t base1k = (m->bam_start + i) * 4u;
|
||||
for (uint32_t k = 0; k < 4; k++) {
|
||||
if (blkio_read(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK)
|
||||
@@ -462,7 +477,7 @@ static int bam_flush_to_disk(blk_dev_slot_t *slot) {
|
||||
}
|
||||
|
||||
/* write back */
|
||||
for (uint32_t i = 0; i < m->bam_devblocks; i++) {
|
||||
for (uint32_t i = 0; i < npages; i++) {
|
||||
uint32_t base1k = (m->bam_start + i) * 4u;
|
||||
for (uint32_t k = 0; k < 4; k++) {
|
||||
if (blkio_write(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK) {
|
||||
|
||||
Reference in New Issue
Block a user