diff options
author | Huang, Tao <huangtao@rock-chips.com> | 2016-02-18 16:03:29 +0800 |
---|---|---|
committer | Huang, Tao <huangtao@rock-chips.com> | 2016-02-18 16:03:29 +0800 |
commit | fbcc24698c3040c28f358bc7ffb669290309d63f (patch) | |
tree | 0656dae30f5da9d53ead57b1cc18e65dbc83acaa /block | |
parent | 5f478558d45d6000e960faa8e27a68515fe3daa3 (diff) | |
parent | 1cb8570bf04ab12a03c31c397a4d158f24895d9c (diff) |
Merge tag 'v4.4.2'
This is the 4.4.2 stable release
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-merge.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/block/blk-merge.c b/block/blk-merge.c index e01405a3e8b3..b966db8f3556 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -68,6 +68,18 @@ static struct bio *blk_bio_write_same_split(struct request_queue *q, return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs); } +static inline unsigned get_max_io_size(struct request_queue *q, + struct bio *bio) +{ + unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector); + unsigned mask = queue_logical_block_size(q) - 1; + + /* aligned to logical block size */ + sectors &= ~(mask >> 9); + + return sectors; +} + static struct bio *blk_bio_segment_split(struct request_queue *q, struct bio *bio, struct bio_set *bs, @@ -79,11 +91,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, unsigned front_seg_size = bio->bi_seg_front_size; bool do_split = true; struct bio *new = NULL; + const unsigned max_sectors = get_max_io_size(q, bio); 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 * offset would create a gap, disallow it. @@ -91,6 +101,21 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) goto split; + if (sectors + (bv.bv_len >> 9) > max_sectors) { + /* + * Consider this a new segment if we're splitting in + * the middle of this vector. + */ + if (nsegs < queue_max_segments(q) && + sectors < max_sectors) { + nsegs++; + sectors = max_sectors; + } + if (sectors) + goto split; + /* Make this single bvec as the 1st segment */ + } + if (bvprvp && blk_queue_cluster(q)) { if (seg_size + bv.bv_len > queue_max_segment_size(q)) goto new_segment; |