From 4de22a08e2aade1f81f41faa8558a8a1bcd1f38f Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sun, 14 Jun 2026 15:06:29 +0300 Subject: [PATCH] Fix partial padded read checksum verification --- src/blockstore/v1/flush.cpp | 3 ++- src/blockstore/v1/impl.cpp | 5 ++++ src/blockstore/v1/impl.h | 3 ++- src/blockstore/v1/read.cpp | 46 +++++++++++++++++++++++++++++---- src/test/test_blockstore_v1.cpp | 10 +++++++ 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/blockstore/v1/flush.cpp b/src/blockstore/v1/flush.cpp index 009f4fca..f4bada67 100644 --- a/src/blockstore/v1/flush.cpp +++ b/src/blockstore/v1/flush.cpp @@ -1111,7 +1111,8 @@ void journal_flusher_co::scan_dirty() last--; read_to_fill_incomplete = bs->fill_partial_checksum_blocks( v, fulfilled, bmp_ptr, NULL, false, NULL, v[0].offset/bs->dsk.csum_block_size * bs->dsk.csum_block_size, - ((v[last].offset+v[last].len-1) / bs->dsk.csum_block_size + 1) * bs->dsk.csum_block_size + ((v[last].offset+v[last].len-1) / bs->dsk.csum_block_size + 1) * bs->dsk.csum_block_size, + 0, bs->dsk.data_block_size ); } else if (fill_incomplete && clean_init_bitmap) diff --git a/src/blockstore/v1/impl.cpp b/src/blockstore/v1/impl.cpp index 2978d5ed..80400738 100644 --- a/src/blockstore/v1/impl.cpp +++ b/src/blockstore/v1/impl.cpp @@ -36,6 +36,11 @@ blockstore_impl_t::blockstore_impl_t(blockstore_config_t & config, ring_loop_i * blockstore_impl_t::~blockstore_impl_t() { + for (auto& obj: dirty_db) + { + if (obj.second.dyn_data) + free(obj.second.dyn_data); + } delete data_alloc; delete flusher; if (zero_object) diff --git a/src/blockstore/v1/impl.h b/src/blockstore/v1/impl.h index 86476f18..13fa01a2 100644 --- a/src/blockstore/v1/impl.h +++ b/src/blockstore/v1/impl.h @@ -234,7 +234,8 @@ class blockstore_impl_t: public blockstore_i uint8_t *clean_entry_bitmap, int *dyn_data, uint32_t item_start, uint32_t item_end, uint64_t clean_loc, uint64_t clean_ver); int fill_partial_checksum_blocks(std::vector & rv, uint64_t & fulfilled, - uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, uint64_t read_offset, uint64_t read_end); + uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, + uint32_t read_offset, uint32_t read_end, uint32_t item_start, uint32_t item_end); int pad_journal_read(std::vector & rv, copy_buffer_t & cp, uint64_t dirty_offset, uint64_t dirty_end, uint64_t dirty_loc, uint8_t *csum_ptr, int *dyn_data, uint64_t offset, uint64_t submit_len, uint64_t & blk_begin, uint64_t & blk_end, uint8_t* & blk_buf); diff --git a/src/blockstore/v1/read.cpp b/src/blockstore/v1/read.cpp index 3d292908..3a793007 100644 --- a/src/blockstore/v1/read.cpp +++ b/src/blockstore/v1/read.cpp @@ -167,7 +167,8 @@ uint8_t* blockstore_impl_t::get_clean_entry_bitmap(uint64_t block_loc, int offse } int blockstore_impl_t::fill_partial_checksum_blocks(std::vector & rv, uint64_t & fulfilled, - uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, uint64_t read_offset, uint64_t read_end) + uint8_t *clean_entry_bitmap, int *dyn_data, bool from_journal, uint8_t *read_buf, + uint32_t read_offset, uint32_t read_end, uint32_t item_start, uint32_t item_end) { if (read_end == read_offset) return 0; @@ -175,7 +176,35 @@ int blockstore_impl_t::fill_partial_checksum_blocks(std::vector & read_buf -= read_offset; uint32_t last_block = (read_end-1)/dsk.csum_block_size; uint32_t start_block = read_offset/dsk.csum_block_size; + uint32_t item_start_block = item_start/dsk.csum_block_size; uint32_t end_block = 0; + auto zero_range = [&](int pos, bool alloc, uint32_t cur_start, uint32_t cur_end) + { + if (alloc) + return 0; + copy_buffer_t el = { + .copy_flags = COPY_BUF_ZERO, + .offset = cur_start, + .len = cur_end-cur_start, + }; + rv.insert(rv.begin() + pos, el); + if (read_buf) + memset(read_buf + el.offset - read_offset, 0, el.len); + fulfilled += el.len; + return 1; + }; + if (read_offset < item_start) + { + // Zero-fill the beginning + find_holes(rv, read_offset, item_start, zero_range); + read_offset = item_start; + } + if (read_end > item_end) + { + // Zero-fill the end + find_holes(rv, item_end, read_end, zero_range); + read_end = item_end; + } while (start_block <= last_block) { if (read_range_fulfilled(rv, fulfilled, read_buf, from_journal ? NULL : clean_entry_bitmap, @@ -202,8 +231,10 @@ int blockstore_impl_t::fill_partial_checksum_blocks(std::vector & .copy_flags = COPY_BUF_CSUM_FILL | (from_journal ? COPY_BUF_JOURNALED_BIG : 0), .offset = start_block*dsk.csum_block_size, .len = (end_block-start_block)*dsk.csum_block_size, - // save clean_entry_bitmap if we're reading clean data from the journal -- for checksums - .csum_buf = from_journal ? clean_entry_bitmap : NULL, + // save checksum reference if we're reading clean data from the journal + .csum_buf = from_journal + ? clean_entry_bitmap + dsk.clean_entry_bitmap_size + (start_block-item_start_block)*(dsk.data_csum_type & 0xFF) + : NULL, .dyn_data = dyn_data, }); if (dyn_data) @@ -630,7 +661,7 @@ bool blockstore_impl_t::fulfill_clean_read(blockstore_op_t *read_op, uint64_t & { auto & rv = PRIV(read_op)->read_vec; int req = fill_partial_checksum_blocks(rv, fulfilled, clean_entry_bitmap, dyn_data, from_journal, - (uint8_t*)read_op->buf, read_op->offset, read_op->offset+read_op->len); + (uint8_t*)read_op->buf, read_op->offset, read_op->offset+read_op->len, item_start, item_end); if (!inmemory_meta && !from_journal && req > 0) { // Read checksums from disk @@ -845,7 +876,7 @@ bool blockstore_impl_t::verify_clean_padded_checksums(blockstore_op_t *op, uint6 { uint32_t offset = clean_loc % dsk.data_block_size; if (from_journal) - return verify_padded_checksums(NULL, dyn_data + dsk.clean_entry_bitmap_size, offset, iov, n_iov, bad_block_cb); + return verify_padded_checksums(NULL, dyn_data, offset, iov, n_iov, bad_block_cb); clean_loc = (clean_loc / dsk.data_block_size) * dsk.data_block_size; if (!dyn_data) { @@ -883,6 +914,11 @@ void blockstore_impl_t::handle_read_event(ring_data_t *data, blockstore_op_t *op rv[i].buf = NULL; continue; } + if (rv[i].copy_flags & COPY_BUF_ZERO) + { + // Zero read + continue; + } if (rv[i].copy_flags & COPY_BUF_COALESCED) { // Sub-block shared with another read. Skip diff --git a/src/test/test_blockstore_v1.cpp b/src/test/test_blockstore_v1.cpp index 65fadc73..58c6f75d 100644 --- a/src/test/test_blockstore_v1.cpp +++ b/src/test/test_blockstore_v1.cpp @@ -340,6 +340,16 @@ static void test_validate_padded_big_journal() read_op.len = 16*1024; test.exec_op(&read_op); assert(read_op.retval == read_op.len); + assert(memcheck(read_op.buf, 0xAA, 16*1024)); + + printf("read v1 0+16k\n"); + read_op.version = 2; + read_op.offset = 0; + read_op.len = 16*1024; + test.exec_op(&read_op); + assert(read_op.retval == read_op.len); + assert(memcheck(read_op.buf, 0, 4*1024)); + assert(memcheck(read_op.buf + 4*1024, 0xAA, 12*1024)); free(op.buf); free(read_op.buf);