aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-merge.c
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2008-10-13 08:19:05 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-17 02:46:56 -0400
commit8677142710516d986d932d6f1fba7be8382c1fec (patch)
tree5221f48b4e7e62590f8bbb832b4065886681d6cf /block/blk-merge.c
parent0fc71e3d6520ba7abad5cfbc9a33db0190e4d5b8 (diff)
block: fix nr_phys_segments miscalculation bug
This fixes the bug reported by Nikanth Karthikesan <knikanth@suse.de>: http://lkml.org/lkml/2008/10/2/203 The root cause of the bug is that blk_phys_contig_segment miscalculates q->max_segment_size. blk_phys_contig_segment checks: req->biotail->bi_size + next_req->bio->bi_size > q->max_segment_size But blk_recalc_rq_segments might expect that req->biotail and the previous bio in the req are supposed be merged into one segment. blk_recalc_rq_segments might also expect that next_req->bio and the next bio in the next_req are supposed be merged into one segment. In such case, we merge two requests that can't be merged here. Later, blk_rq_map_sg gives more segments than it should. We need to keep track of segment size in blk_recalc_rq_segments and use it to see if two requests can be merged. This patch implements it in the similar way that we used to do for hw merging (virtual merging). Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/blk-merge.c')
-rw-r--r--block/blk-merge.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 908d3e11ac52..8681cd6f9911 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -77,12 +77,20 @@ void blk_recalc_rq_segments(struct request *rq)
77 continue; 77 continue;
78 } 78 }
79new_segment: 79new_segment:
80 if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
81 rq->bio->bi_seg_front_size = seg_size;
82
80 nr_phys_segs++; 83 nr_phys_segs++;
81 bvprv = bv; 84 bvprv = bv;
82 seg_size = bv->bv_len; 85 seg_size = bv->bv_len;
83 highprv = high; 86 highprv = high;
84 } 87 }
85 88
89 if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
90 rq->bio->bi_seg_front_size = seg_size;
91 if (seg_size > rq->biotail->bi_seg_back_size)
92 rq->biotail->bi_seg_back_size = seg_size;
93
86 rq->nr_phys_segments = nr_phys_segs; 94 rq->nr_phys_segments = nr_phys_segs;
87} 95}
88 96
@@ -106,7 +114,8 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
106 if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags)) 114 if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
107 return 0; 115 return 0;
108 116
109 if (bio->bi_size + nxt->bi_size > q->max_segment_size) 117 if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
118 q->max_segment_size)
110 return 0; 119 return 0;
111 120
112 if (!bio_has_data(bio)) 121 if (!bio_has_data(bio))
@@ -309,6 +318,8 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
309 struct request *next) 318 struct request *next)
310{ 319{
311 int total_phys_segments; 320 int total_phys_segments;
321 unsigned int seg_size =
322 req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size;
312 323
313 /* 324 /*
314 * First check if the either of the requests are re-queued 325 * First check if the either of the requests are re-queued
@@ -324,8 +335,13 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
324 return 0; 335 return 0;
325 336
326 total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; 337 total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
327 if (blk_phys_contig_segment(q, req->biotail, next->bio)) 338 if (blk_phys_contig_segment(q, req->biotail, next->bio)) {
339 if (req->nr_phys_segments == 1)
340 req->bio->bi_seg_front_size = seg_size;
341 if (next->nr_phys_segments == 1)
342 next->biotail->bi_seg_back_size = seg_size;
328 total_phys_segments--; 343 total_phys_segments--;
344 }
329 345
330 if (total_phys_segments > q->max_phys_segments) 346 if (total_phys_segments > q->max_phys_segments)
331 return 0; 347 return 0;