Discard ranges are stored as cdev byte ranges, while
writebuffer_io_nblocks() returns a number of logical blocks.

block_cache() mixes these units up when checking whether a cache chunk
falls inside the most recent discard range.

This bug resulted in a cache hit for discarded data zeroing only the
logical block count in bytes. A 16-block chunk cleared 16 bytes instead of
16 logical blocks, leaving stale data in the rest of the cache buffer.

Fixes: e488952b9d ("block: Implement discard_range")
Signed-off-by: Ahmad Fatoum <[email protected]>
---
 common/block.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/block.c b/common/block.c
index 96f48ba7aa41..f4b2a692407a 100644
--- a/common/block.c
+++ b/common/block.c
@@ -185,9 +185,9 @@ static int block_cache(struct block_device *blk, sector_t 
block)
 
        len = writebuffer_io_nblocks(blk, chunk);
        if (chunk->block_start * BLOCKSIZE(blk) >= blk->discard_start &&
-           chunk->block_start * BLOCKSIZE(blk) + len
+           (chunk->block_start + len) * BLOCKSIZE(blk)
            <= blk->discard_start + blk->discard_size) {
-               memset(chunk->data, 0, len);
+               memset(chunk->data, 0, len << blk->blockbits);
                list_add(&chunk->list, &blk->buffered_blocks);
                return 0;
        }
-- 
2.47.3


Reply via email to