Commit e36f6204 authored by Keith Busch's avatar Keith Busch Committed by Jens Axboe

block: split bios to max possible length

This splits bio in the middle of a vector to form the largest possible
bio at the h/w's desired alignment, and guarantees the bio being split
will have some data.

The criteria for splitting is changed from the max sectors to the h/w's
optimal sector alignment if it is provided. For h/w that advertise their
block storage's underlying chunk size, it's a big performance win to not
submit commands that cross them. If sector alignment is not provided,
this patch uses the max sectors as before.

This addresses the performance issue commit d3805611 attempted to
fix, but was reverted due to splitting logic error.
Signed-off-by: default avatarKeith Busch <keith.busch@intel.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ming Lei <tom.leiming@gmail.com>
Cc: Kent Overstreet <kent.overstreet@gmail.com>
Cc: <stable@vger.kernel.org> # 4.4.x-
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent cda22646
...@@ -83,9 +83,6 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, ...@@ -83,9 +83,6 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio *new = NULL; struct bio *new = NULL;
bio_for_each_segment(bv, bio, iter) { bio_for_each_segment(bv, bio, iter) {
if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
goto split;
/* /*
* If the queue doesn't support SG gaps and adding this * If the queue doesn't support SG gaps and adding this
* offset would create a gap, disallow it. * offset would create a gap, disallow it.
...@@ -93,6 +90,22 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, ...@@ -93,6 +90,22 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset))
goto split; goto split;
if (sectors + (bv.bv_len >> 9) >
blk_max_size_offset(q, bio->bi_iter.bi_sector)) {
/*
* Consider this a new segment if we're splitting in
* the middle of this vector.
*/
if (nsegs < queue_max_segments(q) &&
sectors < blk_max_size_offset(q,
bio->bi_iter.bi_sector)) {
nsegs++;
sectors = blk_max_size_offset(q,
bio->bi_iter.bi_sector);
}
goto split;
}
if (bvprvp && blk_queue_cluster(q)) { if (bvprvp && blk_queue_cluster(q)) {
if (seg_size + bv.bv_len > queue_max_segment_size(q)) if (seg_size + bv.bv_len > queue_max_segment_size(q))
goto new_segment; goto new_segment;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment