writecache_bio_copy_ssd() unconditionally adds the number of extra blocks
in the merged bio to stats.writes_allocate. That is only correct when the
entries were taken off the freelist.

When the function is called with search_used == true -- i.e. from the
write_hits_uncommitted / write_hits_committed paths in
writecache_map_write() -- the first entry was found in the rbtree and
every following entry is picked up with rb_next(), so nothing is
allocated at all. Accordingly the writes_allocate++ that accompanies a
successful writecache_pop_from_freelist() is skipped for that case, but
the batch accounting below still adds n - 1.

An in-place overwrite of n contiguous cached blocks therefore reports n -
1 allocations that never happened. Only the dmsetup status output is
affected; there is no functional change.

Signed-off-by: Mikulas Patocka <[email protected]>
Assisted-by: Claude:claude-opus-5
Fixes: b2676e1482af ("dm writecache: count number of blocks written, not number 
of write bios")

---
 drivers/md/dm-writecache.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-2.6/drivers/md/dm-writecache.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-writecache.c
+++ linux-2.6/drivers/md/dm-writecache.c
@@ -1424,7 +1424,8 @@ static void writecache_bio_copy_ssd(stru
        dm_accept_partial_bio(bio, bio_size >> SECTOR_SHIFT);
 
        wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits;
-       wc->stats.writes_allocate += (bio->bi_iter.bi_size - wc->block_size) >> 
wc->block_size_bits;
+       if (!search_used)
+               wc->stats.writes_allocate += (bio->bi_iter.bi_size - 
wc->block_size) >> wc->block_size_bits;
 
        if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks)) {
                wc->uncommitted_blocks = 0;


Reply via email to