Fix zero-padded big_write checksum verification in the new store

This commit is contained in:
Vitaliy Filippov
2026-07-04 21:37:22 +03:00
parent 5ef9d78461
commit 462482d319
3 changed files with 94 additions and 1 deletions
+2 -1
View File
@@ -1139,6 +1139,7 @@ bool blockstore_heap_t::calc_block_checksums(uint32_t *block_csums, uint8_t *bit
{
bool res = true;
uint32_t pos = start;
uint32_t block_start = (start/dsk->csum_block_size)*dsk->csum_block_size;
uint32_t block_end = (start/dsk->csum_block_size + 1)*dsk->csum_block_size;
uint32_t block_crc = 0;
bool isset = false;
@@ -1153,7 +1154,7 @@ bool blockstore_heap_t::calc_block_checksums(uint32_t *block_csums, uint8_t *bit
while (pos < end && pos < block_end && !(bitmap[pos/dsk->bitmap_granularity/8] & (1 << ((pos/dsk->bitmap_granularity) % 8))))
pos += dsk->bitmap_granularity;
// zero padding at the beginning or at the end of the block is not counted
if (pos > prev && prev > 0 && pos < block_end)
if (pos > prev && prev > block_start && pos < block_end)
block_crc = crc32c_pad(block_crc, NULL, 0, pos-prev, 0);
prev = pos;
while (pos < end && pos < block_end && (bitmap[pos/dsk->bitmap_granularity/8] & (1 << ((pos/dsk->bitmap_granularity) % 8))))
+45
View File
@@ -834,6 +834,50 @@ static void test_fsync_batch_big()
free(op2.buf);
}
static void test_padded_csum_sparse_leading_hole()
{
printf("\n-- test_padded_csum_sparse_leading_hole\n");
bs_test_t test;
test.default_cfg();
test.config["csum_block_size"] = "16384";
test.init();
// Initial write at offset=20K, len=4K on a fresh object.
// The csum block is [16K..32K); granule [16K..20K) is a leading hole.
printf("writing\n");
blockstore_op_t op;
op.opcode = BS_OP_WRITE_STABLE;
op.oid = { .inode = 1, .stripe = 0 };
op.version = 1;
op.offset = 20*1024;
op.len = 4096;
op.buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, 4096);
memset(op.buf, 0xaa, 4096);
test.exec_op(&op);
assert(op.retval == op.len);
// Read it back - without the fix, verify_read_checksums returns -EDOM
// because the recomputed CRC includes zero-padding for [16K..20K) while
// the stored CRC was computed only over [20K..24K).
printf("reading\n");
blockstore_op_t op2;
op2.opcode = BS_OP_READ;
op2.oid = { .inode = 1, .stripe = 0 };
op2.version = UINT64_MAX;
op2.offset = 0;
op2.len = 128*1024;
op2.buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, 128*1024);
test.exec_op(&op2);
assert(op2.retval == op2.len);
assert(is_zero(op2.buf, 20*1024));
assert(memcheck(op2.buf+20*1024, 0xaa, 4*1024));
assert(is_zero(op2.buf+24*1024, 104*1024));
free(op.buf);
free(op2.buf);
}
// FIXME Add a simple intent_write / big_intent test
int main(int narg, char *args[])
@@ -844,6 +888,7 @@ int main(int narg, char *args[])
test_intent_over_unstable();
test_padded_csum_intent(false);
test_padded_csum_intent(true);
test_padded_csum_sparse_leading_hole();
test_perfect_csum_interrupted();
test_padded_csum_parallel_read(false, 8192);
test_padded_csum_parallel_read(true, 8192);
+47
View File
@@ -2719,6 +2719,52 @@ void test_postpone_load()
assert(obj);
assert(count_writes(heap, obj) == 11);
}
printf("OK test_postpone_load\n");
}
void test_big_padded_csum()
{
blockstore_disk_t dsk;
_test_init(dsk, true, [](std::map<std::string, std::string> & config)
{
config["csum_block_size"] = "32k";
});
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
blockstore_heap_t heap(&dsk, buffer_area.data());
heap.finish_recheck();
{
memset(buffer_area.data()+4096, 0xab, 4*1024);
_test_big_write(heap, dsk, 1, 0, 1, 0, true, 36*1024, 4*1024, buffer_area.data()+4096);
object_id oid = { .inode = INODE_WITH_POOL(1, 1), .stripe = 0 };
heap_entry_t *obj = heap.lock_and_read_entry(oid);
assert(obj);
// Read the whole checksum block and verify its checksum
bool csum_ok = heap.calc_block_checksums(
(uint32_t*)obj->get_checksums(&heap) + 1, buffer_area.data(), obj->get_int_bitmap(&heap),
32*1024, 32*1024+32*1024, false, [](uint32_t, uint32_t, uint32_t) {}
);
assert(csum_ok);
// Part 2 - check internal padding
memset(buffer_area.data()+12*1024, 0xab, 4*1024);
std::vector<uint8_t> bitmap(dsk.clean_entry_bitmap_size);
bitmap_set(bitmap.data(), 36*1024, 4*1024, 4096);
bitmap_set(bitmap.data(), 44*1024, 4*1024, 4096);
std::vector<uint8_t> new_csums(dsk.data_block_size/32768*4);
memcpy(new_csums.data(), obj->get_checksums(&heap), new_csums.size());
((uint32_t*)new_csums.data())[1] = crc32c(0, buffer_area.data()+4*1024, 12*1024);
csum_ok = heap.calc_block_checksums(
(uint32_t*)new_csums.data() + 1, buffer_area.data(), bitmap.data(),
32*1024, 32*1024+32*1024, false, [](uint32_t, uint32_t, uint32_t) {}
);
assert(csum_ok);
}
printf("OK test_big_padded_csum\n");
}
// FIXME: Add a test for big_intent, incl. explicit_complete with big_intent over big_write over deletion over big_write :)
@@ -2759,5 +2805,6 @@ int main(int narg, char *args[])
test_explicit_complete();
test_skip_double_claim();
test_postpone_load();
test_big_padded_csum();
return 0;
}