Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dm: optimize REQ_PREFLUSH with data when using the linear target

If the table has only linear targets and there is just one underlying
device, we can optimize REQ_PREFLUSH with data - we don't have to split
it to two bios - a flush and a write. We can pass it to the linear target
directly.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Tested-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>

+25 -8
+1
drivers/md/dm-core.h
··· 292 292 struct dm_io *next; 293 293 struct dm_stats_aux stats_aux; 294 294 blk_status_t status; 295 + bool requeue_flush_with_data; 295 296 atomic_t io_count; 296 297 struct mapped_device *md; 297 298
+24 -8
drivers/md/dm.c
··· 490 490 } 491 491 EXPORT_SYMBOL_GPL(dm_start_time_ns_from_clone); 492 492 493 - static inline bool bio_is_flush_with_data(struct bio *bio) 494 - { 495 - return ((bio->bi_opf & REQ_PREFLUSH) && bio->bi_iter.bi_size); 496 - } 497 - 498 493 static inline unsigned int dm_io_sectors(struct dm_io *io, struct bio *bio) 499 494 { 500 495 /* 501 496 * If REQ_PREFLUSH set, don't account payload, it will be 502 497 * submitted (and accounted) after this flush completes. 503 498 */ 504 - if (bio_is_flush_with_data(bio)) 499 + if (io->requeue_flush_with_data) 505 500 return 0; 506 501 if (unlikely(dm_io_flagged(io, DM_IO_WAS_SPLIT))) 507 502 return io->sectors; ··· 585 590 io = container_of(tio, struct dm_io, tio); 586 591 io->magic = DM_IO_MAGIC; 587 592 io->status = BLK_STS_OK; 593 + io->requeue_flush_with_data = false; 588 594 589 595 /* one ref is for submission, the other is for completion */ 590 596 atomic_set(&io->io_count, 2); ··· 944 948 struct mapped_device *md = io->md; 945 949 blk_status_t io_error; 946 950 bool requeued; 951 + bool requeue_flush_with_data; 947 952 948 953 requeued = dm_handle_requeue(io, first_stage); 949 954 if (requeued && first_stage) ··· 961 964 __dm_start_io_acct(io); 962 965 dm_end_io_acct(io); 963 966 } 967 + requeue_flush_with_data = io->requeue_flush_with_data; 964 968 free_io(io); 965 969 smp_wmb(); 966 970 this_cpu_dec(*md->pending_io); ··· 974 976 if (requeued) 975 977 return; 976 978 977 - if (bio_is_flush_with_data(bio)) { 979 + if (unlikely(requeue_flush_with_data)) { 978 980 /* 979 981 * Preflush done for flush with data, reissue 980 982 * without REQ_PREFLUSH. ··· 1994 1996 } 1995 1997 init_clone_info(&ci, io, map, bio, is_abnormal); 1996 1998 1997 - if (bio->bi_opf & REQ_PREFLUSH) { 1999 + if (unlikely((bio->bi_opf & REQ_PREFLUSH) != 0)) { 2000 + /* 2001 + * The "flush_bypasses_map" is set on targets where it is safe 2002 + * to skip the map function and submit bios directly to the 2003 + * underlying block devices - currently, it is set for dm-linear 2004 + * and dm-stripe. 2005 + * 2006 + * If we have just one underlying device (i.e. there is one 2007 + * linear target or multiple linear targets pointing to the same 2008 + * device), we can send the flush with data directly to it. 2009 + */ 2010 + if (map->flush_bypasses_map) { 2011 + struct list_head *devices = dm_table_get_devices(map); 2012 + if (devices->next == devices->prev) 2013 + goto send_preflush_with_data; 2014 + } 2015 + if (bio->bi_iter.bi_size) 2016 + io->requeue_flush_with_data = true; 1998 2017 __send_empty_flush(&ci); 1999 2018 /* dm_io_complete submits any data associated with flush */ 2000 2019 goto out; 2001 2020 } 2002 2021 2022 + send_preflush_with_data: 2003 2023 if (static_branch_unlikely(&zoned_enabled) && 2004 2024 (bio_op(bio) == REQ_OP_ZONE_RESET_ALL)) { 2005 2025 error = __send_zone_reset_all(&ci);