Skip to content

Commit 7dd76d1

Browse files
Ming LeiMike Snitzer
authored andcommitted
dm: improve bio splitting and associated IO accounting
The current DM code (ab)uses late assignment of dm_io->orig_bio (after __map_bio() returns and any bio splitting is complete) to indicate the FS bio has been processed and can be accounted. This results in awkward waiting until ->orig_bio is set in dm_submit_bio_remap(). Also the bio splitting was implemented using bio_split()+bio_chain() -- a well-worn pattern but it requires bio cloning purely for the benefit of more natural IO accounting. The bio_split() result was stored in ->orig_bio to represent the mapped part of the original FS bio. DM has switched to the bdev based IO accounting interface. DM's IO accounting can be implemented in terms of the original FS bio (now stored early in ->orig_bio) via access to its sectors/bio_op. And if/when splitting is needed, set a new DM_IO_WAS_SPLIT flag and use new dm_io fields of .sector_offset & .sectors to allow IO accounting for split bios _without_ needing to clone a new bio to store in ->orig_bio. Signed-off-by: Ming Lei <[email protected]> Co-developed-by: Mike Snitzer <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent d3de6d1 commit 7dd76d1

File tree

2 files changed

+59
-24
lines changed

2 files changed

+59
-24
lines changed

drivers/md/dm-core.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,12 @@ struct dm_io {
267267
blk_status_t status;
268268
atomic_t io_count;
269269
struct mapped_device *md;
270+
271+
/* The three fields represent mapped part of original bio */
270272
struct bio *orig_bio;
273+
unsigned int sector_offset; /* offset to end of orig_bio */
274+
unsigned int sectors;
275+
271276
/* last member of dm_target_io is 'struct bio' */
272277
struct dm_target_io tio;
273278
};
@@ -277,7 +282,8 @@ struct dm_io {
277282
*/
278283
enum {
279284
DM_IO_START_ACCT,
280-
DM_IO_ACCOUNTED
285+
DM_IO_ACCOUNTED,
286+
DM_IO_WAS_SPLIT
281287
};
282288

283289
static inline bool dm_io_flagged(struct dm_io *io, unsigned int bit)

drivers/md/dm.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,10 @@ static void dm_io_acct(struct dm_io *io, bool end)
516516
*/
517517
if (bio_is_flush_with_data(bio))
518518
sectors = 0;
519-
else
519+
else if (likely(!(dm_io_flagged(io, DM_IO_WAS_SPLIT))))
520520
sectors = bio_sectors(bio);
521+
else
522+
sectors = io->sectors;
521523

522524
if (!end)
523525
bdev_start_io_acct(bio->bi_bdev, sectors, bio_op(bio),
@@ -526,10 +528,18 @@ static void dm_io_acct(struct dm_io *io, bool end)
526528
bdev_end_io_acct(bio->bi_bdev, bio_op(bio), start_time);
527529

528530
if (static_branch_unlikely(&stats_enabled) &&
529-
unlikely(dm_stats_used(&md->stats)))
531+
unlikely(dm_stats_used(&md->stats))) {
532+
sector_t sector;
533+
534+
if (likely(!dm_io_flagged(io, DM_IO_WAS_SPLIT)))
535+
sector = bio->bi_iter.bi_sector;
536+
else
537+
sector = bio_end_sector(bio) - io->sector_offset;
538+
530539
dm_stats_account_io(&md->stats, bio_data_dir(bio),
531-
bio->bi_iter.bi_sector, sectors,
540+
sector, sectors,
532541
end, start_time, stats_aux);
542+
}
533543
}
534544

535545
static void __dm_start_io_acct(struct dm_io *io)
@@ -582,7 +592,7 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
582592
io->status = BLK_STS_OK;
583593
atomic_set(&io->io_count, 1);
584594
this_cpu_inc(*md->pending_io);
585-
io->orig_bio = NULL;
595+
io->orig_bio = bio;
586596
io->md = md;
587597
io->map_task = current;
588598
spin_lock_init(&io->lock);
@@ -1219,6 +1229,13 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
12191229

12201230
*tio->len_ptr -= bio_sectors - n_sectors;
12211231
bio->bi_iter.bi_size = n_sectors << SECTOR_SHIFT;
1232+
1233+
/*
1234+
* __split_and_process_bio() may have already saved mapped part
1235+
* for accounting but it is being reduced so update accordingly.
1236+
*/
1237+
dm_io_set_flag(tio->io, DM_IO_WAS_SPLIT);
1238+
tio->io->sectors = n_sectors;
12221239
}
12231240
EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
12241241

@@ -1257,13 +1274,6 @@ void dm_submit_bio_remap(struct bio *clone, struct bio *tgt_clone)
12571274
/* Still in target's map function */
12581275
dm_io_set_flag(io, DM_IO_START_ACCT);
12591276
} else {
1260-
/*
1261-
* Called by another thread, managed by DM target,
1262-
* wait for dm_split_and_process_bio() to store
1263-
* io->orig_bio
1264-
*/
1265-
while (unlikely(!smp_load_acquire(&io->orig_bio)))
1266-
msleep(1);
12671277
dm_start_io_acct(io, clone);
12681278
}
12691279

@@ -1357,6 +1367,31 @@ static void __map_bio(struct bio *clone)
13571367
}
13581368
}
13591369

1370+
static void setup_split_accounting(struct clone_info *ci, unsigned len)
1371+
{
1372+
struct dm_io *io = ci->io;
1373+
1374+
if (ci->sector_count > len) {
1375+
/*
1376+
* Split needed, save the mapped part for accounting.
1377+
* NOTE: dm_accept_partial_bio() will update accordingly.
1378+
*/
1379+
dm_io_set_flag(io, DM_IO_WAS_SPLIT);
1380+
io->sectors = len;
1381+
}
1382+
1383+
if (static_branch_unlikely(&stats_enabled) &&
1384+
unlikely(dm_stats_used(&io->md->stats))) {
1385+
/*
1386+
* Save bi_sector in terms of its offset from end of
1387+
* original bio, only needed for DM-stats' benefit.
1388+
* - saved regardless of whether split needed so that
1389+
* dm_accept_partial_bio() doesn't need to.
1390+
*/
1391+
io->sector_offset = bio_end_sector(ci->bio) - ci->sector;
1392+
}
1393+
}
1394+
13601395
static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
13611396
struct dm_target *ti, unsigned num_bios)
13621397
{
@@ -1396,6 +1431,8 @@ static void __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
13961431
case 0:
13971432
break;
13981433
case 1:
1434+
if (len)
1435+
setup_split_accounting(ci, *len);
13991436
clone = alloc_tio(ci, ti, 0, len, GFP_NOIO);
14001437
__map_bio(clone);
14011438
break;
@@ -1559,6 +1596,7 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
15591596
ci->submit_as_polled = ci->bio->bi_opf & REQ_POLLED;
15601597

15611598
len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count);
1599+
setup_split_accounting(ci, len);
15621600
clone = alloc_tio(ci, ti, 0, &len, GFP_NOIO);
15631601
__map_bio(clone);
15641602

@@ -1592,7 +1630,6 @@ static void dm_split_and_process_bio(struct mapped_device *md,
15921630
{
15931631
struct clone_info ci;
15941632
struct dm_io *io;
1595-
struct bio *orig_bio = NULL;
15961633
blk_status_t error = BLK_STS_OK;
15971634

15981635
init_clone_info(&ci, md, map, bio);
@@ -1608,23 +1645,15 @@ static void dm_split_and_process_bio(struct mapped_device *md,
16081645
io->map_task = NULL;
16091646
if (error || !ci.sector_count)
16101647
goto out;
1611-
16121648
/*
16131649
* Remainder must be passed to submit_bio_noacct() so it gets handled
16141650
* *after* bios already submitted have been completely processed.
1615-
* We take a clone of the original to store in io->orig_bio to be
1616-
* used by dm_end_io_acct() and for dm_io_complete() to use for
1617-
* completion handling.
16181651
*/
1619-
orig_bio = bio_split(bio, bio_sectors(bio) - ci.sector_count,
1620-
GFP_NOIO, &md->queue->bio_split);
1621-
bio_chain(orig_bio, bio);
1622-
trace_block_split(orig_bio, bio->bi_iter.bi_sector);
1652+
bio_trim(bio, io->sectors, ci.sector_count);
1653+
trace_block_split(bio, bio->bi_iter.bi_sector);
1654+
bio_inc_remaining(bio);
16231655
submit_bio_noacct(bio);
16241656
out:
1625-
if (!orig_bio)
1626-
orig_bio = bio;
1627-
smp_store_release(&io->orig_bio, orig_bio);
16281657
if (dm_io_flagged(io, DM_IO_START_ACCT))
16291658
dm_start_io_acct(io, NULL);
16301659

0 commit comments

Comments
 (0)