Add support in the bio splitting code and also in the bio submission code for bios with segments smaller than the page size. Cc: Christoph Hellwig <hch@xxxxxx> Cc: Ming Lei <ming.lei@xxxxxxxxxx> Cc: Keith Busch <kbusch@xxxxxxxxxx> Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx> --- block/blk-merge.c | 6 ++++-- block/blk-mq.c | 2 ++ block/blk.h | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index 35a8f75cc45d..7badfbed09fc 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -294,7 +294,8 @@ static struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim, if (nsegs < lim->max_segments && bytes + bv.bv_len <= max_bytes && bv.bv_offset + bv.bv_len <= PAGE_SIZE) { - nsegs++; + /* single-page bvec optimization */ + nsegs += blk_segments(lim, bv.bv_len); bytes += bv.bv_len; } else { if (bvec_split_segs(lim, &bv, &nsegs, &bytes, @@ -531,7 +532,8 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio, __blk_segment_map_sg_merge(q, &bvec, &bvprv, sg)) goto next_bvec; - if (bvec.bv_offset + bvec.bv_len <= PAGE_SIZE) + if (bvec.bv_offset + bvec.bv_len <= PAGE_SIZE && + bvec.bv_len <= q->limits.max_segment_size) nsegs += __blk_bvec_map_sg(bvec, sglist, sg); else nsegs += blk_bvec_map_sg(q, &bvec, sglist, sg); diff --git a/block/blk-mq.c b/block/blk-mq.c index f72164429446..1560e4f76f2d 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2953,6 +2953,8 @@ void blk_mq_submit_bio(struct bio *bio) bio = blk_queue_bounce(bio, q); if (bio_may_exceed_limits(bio, &q->limits)) bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); + else if (bio->bi_vcnt == 1) + nr_segs = blk_segments(&q->limits, bio->bi_io_vec[0].bv_len); if (!bio_integrity_prep(bio)) return; diff --git a/block/blk.h b/block/blk.h index fb486eff3eef..c45f86b74b1d 100644 --- a/block/blk.h +++ b/block/blk.h @@ -320,7 +320,7 @@ static inline bool bio_may_exceed_limits(struct bio *bio, } /* - * All drivers must accept single-segments bios that are <= PAGE_SIZE. + * Check whether bio splitting should be performed. * This is a quick and dirty check that relies on the fact that * bi_io_vec[0] is always valid if a bio has data. The check might * lead to occasional false negatives when bios are cloned, but compared @@ -328,6 +328,7 @@ static inline bool bio_may_exceed_limits(struct bio *bio, * doesn't matter anyway. */ return lim->chunk_sectors || bio->bi_vcnt != 1 || + bio->bi_io_vec->bv_len > lim->max_segment_size || bio->bi_io_vec->bv_len + bio->bi_io_vec->bv_offset > PAGE_SIZE; }