aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2015-11-23 21:35:30 -0500
committerJens Axboe <axboe@fb.com>2015-11-23 22:16:53 -0500
commit02e707424c2eadbcda68cd38876c9f4434ca8e1a (patch)
tree697fced5154db2d7890d97a72f87cfa211345370 /block
parent578270bfbd2803dc7b0b03fbc2ac119efbc73195 (diff)
blk-merge: fix blk_bio_segment_split
Commit bdced438acd83a(block: setup bi_phys_segments after splitting) introduces function of computing bio->bi_phys_segments during bio splitting. Unfortunately both bio->bi_seg_front_size and bio->bi_seg_back_size arn't computed, so too many physical segments may be obtained for one request since both the two are used to check if one segment across two bios can be possible. This patch fixes the issue by computing the two variables in blk_bio_segment_split(). Fixes: bdced438acd83a(block: setup bi_phys_segments after splitting) Reported-by: Michael Ellerman <mpe@ellerman.id.au> Reported-by: Mark Salter <msalter@redhat.com> Tested-by: Laurent Dufour <ldufour@linux.vnet.ibm.com> Tested-by: Mark Salter <msalter@redhat.com> Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-merge.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/block/blk-merge.c b/block/blk-merge.c
index f2efe8ae75bb..50793cdc5331 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -76,6 +76,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
76 struct bio_vec bv, bvprv, *bvprvp = NULL; 76 struct bio_vec bv, bvprv, *bvprvp = NULL;
77 struct bvec_iter iter; 77 struct bvec_iter iter;
78 unsigned seg_size = 0, nsegs = 0, sectors = 0; 78 unsigned seg_size = 0, nsegs = 0, sectors = 0;
79 unsigned front_seg_size = bio->bi_seg_front_size;
80 bool do_split = true;
81 struct bio *new = NULL;
79 82
80 bio_for_each_segment(bv, bio, iter) { 83 bio_for_each_segment(bv, bio, iter) {
81 if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q)) 84 if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
@@ -111,13 +114,26 @@ new_segment:
111 bvprvp = &bvprv; 114 bvprvp = &bvprv;
112 seg_size = bv.bv_len; 115 seg_size = bv.bv_len;
113 sectors += bv.bv_len >> 9; 116 sectors += bv.bv_len >> 9;
117
118 if (nsegs == 1 && seg_size > front_seg_size)
119 front_seg_size = seg_size;
114 } 120 }
115 121
116 *segs = nsegs; 122 do_split = false;
117 return NULL;
118split: 123split:
119 *segs = nsegs; 124 *segs = nsegs;
120 return bio_split(bio, sectors, GFP_NOIO, bs); 125
126 if (do_split) {
127 new = bio_split(bio, sectors, GFP_NOIO, bs);
128 if (new)
129 bio = new;
130 }
131
132 bio->bi_seg_front_size = front_seg_size;
133 if (seg_size > bio->bi_seg_back_size)
134 bio->bi_seg_back_size = seg_size;
135
136 return do_split ? new : NULL;
121} 137}
122 138
123void blk_queue_split(struct request_queue *q, struct bio **bio, 139void blk_queue_split(struct request_queue *q, struct bio **bio,