Fix zero-padded big_write checksum verification in the new store
This commit is contained in:
@@ -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))))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user