If dm-writecache overwrote existing cached data, it would split the
incoming bio to many block-sized bios. The I/O scheduler would reassemble
these bios into one large request. This split and reassemble causes
performance degradation.

This patch avoids splitting the bio if the target area that is being
overwritten is contiguous.

Signed-off-by: Mikulas Patocka <[email protected]>

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
@@ -1360,14 +1360,18 @@ read_next_block:
        } else {
                do {
                        bool found_entry = false;
+                       bool search_used = false;
                        if (writecache_has_error(wc))
                                goto unlock_error;
                        e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 
0);
                        if (e) {
-                               if (!writecache_entry_is_committed(wc, e))
+                               if (!writecache_entry_is_committed(wc, e)) {
+                                       search_used = true;
                                        goto bio_copy;
+                               }
                                if (!WC_MODE_PMEM(wc) && !e->write_in_progress) 
{
                                        wc->overwrote_committed = true;
+                                       search_used = true;
                                        goto bio_copy;
                                }
                                found_entry = true;
@@ -1404,13 +1408,30 @@ bio_copy:
                                sector_t current_cache_sec = start_cache_sec + 
(bio_size >> SECTOR_SHIFT);
 
                                while (bio_size < bio->bi_iter.bi_size) {
-                                       struct wc_entry *f = 
writecache_pop_from_freelist(wc, current_cache_sec);
-                                       if (!f)
-                                               break;
-                                       write_original_sector_seq_count(wc, f, 
bio->bi_iter.bi_sector +
-                                                                       
(bio_size >> SECTOR_SHIFT), wc->seq_count);
-                                       writecache_insert_entry(wc, f);
-                                       wc->uncommitted_blocks++;
+                                       if (!search_used) {
+                                               struct wc_entry *f = 
writecache_pop_from_freelist(wc, current_cache_sec);
+                                               if (!f)
+                                                       break;
+                                               
write_original_sector_seq_count(wc, f, bio->bi_iter.bi_sector +
+                                                                               
(bio_size >> SECTOR_SHIFT), wc->seq_count);
+                                               writecache_insert_entry(wc, f);
+                                               wc->uncommitted_blocks++;
+                                       } else {
+                                               struct wc_entry *f;
+                                               struct rb_node *next = 
rb_next(&e->rb_node);
+                                               if (!next)
+                                                       break;
+                                               f = container_of(next, struct 
wc_entry, rb_node);
+                                               if (f != e + 1)
+                                                       break;
+                                               if (read_original_sector(wc, f) 
!= read_original_sector(wc, e) + (wc->block_size >> SECTOR_SHIFT))
+                                                       break;
+                                               if 
(unlikely(f->write_in_progress))
+                                                       break;
+                                               if 
(writecache_entry_is_committed(wc, f))
+                                                       wc->overwrote_committed 
= true;
+                                               e = f;
+                                       }
                                        bio_size += wc->block_size;
                                        current_cache_sec += wc->block_size >> 
SECTOR_SHIFT;
                                }

--
dm-devel mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to