Skip to content

Commit 61b6e2e

Browse files
Ming LeiMike Snitzer
authored andcommitted
dm: fix BLK_STS_DM_REQUEUE handling when dm_io represents split bio
Commit 7dd76d1 ("dm: improve bio splitting and associated IO accounting") removed using cloned bio when dm io splitting is needed. Using bio_trim()+bio_inc_remaining() rather than bio_split()+bio_chain() causes multiple dm_io instances to share the same original bio, and it works fine if IOs are completed successfully. But a regression was caused for the case when BLK_STS_DM_REQUEUE is returned from any one of DM's cloned bios (whose dm_io share the same orig_bio). In this BLK_STS_DM_REQUEUE case only the mapped subset of the original bio for the current exact dm_io needs to be re-submitted. However, since the original bio is shared among all dm_io instances, the ->orig_bio actually only represents the last dm_io instance, so requeue can't work as expected. Also when more than one dm_io is requeued, the same original bio is requeued from all dm_io's completion handler, then race is caused. Fix this issue by still allocating one clone bio for completing io only, then io accounting can rely on ->orig_bio being unmodified. This is needed because the dm_io's sector_offset and sectors members are recorded relative to an unmodified ->orig_bio. In the future, we can go back to using bio_trim()+bio_inc_remaining() for dm's io splitting but then delay needing a bio clone only when handling BLK_STS_DM_REQUEUE, but that approach is a bit complicated (so it needs a development cycle): 1) bio clone needs to be done in task context 2) a block interface for unwinding bio is required Fixes: 7dd76d1 ("dm: improve bio splitting and associated IO accounting") Reported-by: Benjamin Marzinski <[email protected]> Signed-off-by: Ming Lei <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 78ccef9 commit 61b6e2e

File tree

2 files changed

+8
-4
lines changed

2 files changed

+8
-4
lines changed

drivers/md/dm-core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ struct dm_io {
272272
atomic_t io_count;
273273
struct mapped_device *md;
274274

275+
struct bio *split_bio;
275276
/* The three fields represent mapped part of original bio */
276277
struct bio *orig_bio;
277278
unsigned int sector_offset; /* offset to end of orig_bio */

drivers/md/dm.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
594594
atomic_set(&io->io_count, 2);
595595
this_cpu_inc(*md->pending_io);
596596
io->orig_bio = bio;
597+
io->split_bio = NULL;
597598
io->md = md;
598599
spin_lock_init(&io->lock);
599600
io->start_time = jiffies;
@@ -887,7 +888,7 @@ static void dm_io_complete(struct dm_io *io)
887888
{
888889
blk_status_t io_error;
889890
struct mapped_device *md = io->md;
890-
struct bio *bio = io->orig_bio;
891+
struct bio *bio = io->split_bio ? io->split_bio : io->orig_bio;
891892

892893
if (io->status == BLK_STS_DM_REQUEUE) {
893894
unsigned long flags;
@@ -1693,9 +1694,11 @@ static void dm_split_and_process_bio(struct mapped_device *md,
16931694
* Remainder must be passed to submit_bio_noacct() so it gets handled
16941695
* *after* bios already submitted have been completely processed.
16951696
*/
1696-
bio_trim(bio, io->sectors, ci.sector_count);
1697-
trace_block_split(bio, bio->bi_iter.bi_sector);
1698-
bio_inc_remaining(bio);
1697+
WARN_ON_ONCE(!dm_io_flagged(io, DM_IO_WAS_SPLIT));
1698+
io->split_bio = bio_split(bio, io->sectors, GFP_NOIO,
1699+
&md->queue->bio_split);
1700+
bio_chain(io->split_bio, bio);
1701+
trace_block_split(io->split_bio, bio->bi_iter.bi_sector);
16991702
submit_bio_noacct(bio);
17001703
out:
17011704
/*

0 commit comments

Comments
 (0)