diff options
-rw-r--r-- | drivers/block/elevator.c | 43 | ||||
-rw-r--r-- | include/linux/blkdev.h | 3 |
2 files changed, 21 insertions, 25 deletions
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 29d6c8237ab3..415144372c75 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c | |||
@@ -83,15 +83,6 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) | |||
83 | } | 83 | } |
84 | EXPORT_SYMBOL(elv_try_merge); | 84 | EXPORT_SYMBOL(elv_try_merge); |
85 | 85 | ||
86 | inline int elv_try_last_merge(request_queue_t *q, struct bio *bio) | ||
87 | { | ||
88 | if (q->last_merge) | ||
89 | return elv_try_merge(q->last_merge, bio); | ||
90 | |||
91 | return ELEVATOR_NO_MERGE; | ||
92 | } | ||
93 | EXPORT_SYMBOL(elv_try_last_merge); | ||
94 | |||
95 | static struct elevator_type *elevator_find(const char *name) | 86 | static struct elevator_type *elevator_find(const char *name) |
96 | { | 87 | { |
97 | struct elevator_type *e = NULL; | 88 | struct elevator_type *e = NULL; |
@@ -239,6 +230,9 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
239 | unsigned max_back; | 230 | unsigned max_back; |
240 | struct list_head *entry; | 231 | struct list_head *entry; |
241 | 232 | ||
233 | if (q->last_merge == rq) | ||
234 | q->last_merge = NULL; | ||
235 | |||
242 | boundary = q->end_sector; | 236 | boundary = q->end_sector; |
243 | max_back = q->max_back_kb * 2; | 237 | max_back = q->max_back_kb * 2; |
244 | boundary = boundary > max_back ? boundary - max_back : 0; | 238 | boundary = boundary > max_back ? boundary - max_back : 0; |
@@ -265,6 +259,15 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
265 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | 259 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) |
266 | { | 260 | { |
267 | elevator_t *e = q->elevator; | 261 | elevator_t *e = q->elevator; |
262 | int ret; | ||
263 | |||
264 | if (q->last_merge) { | ||
265 | ret = elv_try_merge(q->last_merge, bio); | ||
266 | if (ret != ELEVATOR_NO_MERGE) { | ||
267 | *req = q->last_merge; | ||
268 | return ret; | ||
269 | } | ||
270 | } | ||
268 | 271 | ||
269 | if (e->ops->elevator_merge_fn) | 272 | if (e->ops->elevator_merge_fn) |
270 | return e->ops->elevator_merge_fn(q, req, bio); | 273 | return e->ops->elevator_merge_fn(q, req, bio); |
@@ -278,6 +281,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) | |||
278 | 281 | ||
279 | if (e->ops->elevator_merged_fn) | 282 | if (e->ops->elevator_merged_fn) |
280 | e->ops->elevator_merged_fn(q, rq); | 283 | e->ops->elevator_merged_fn(q, rq); |
284 | |||
285 | q->last_merge = rq; | ||
281 | } | 286 | } |
282 | 287 | ||
283 | void elv_merge_requests(request_queue_t *q, struct request *rq, | 288 | void elv_merge_requests(request_queue_t *q, struct request *rq, |
@@ -285,11 +290,10 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, | |||
285 | { | 290 | { |
286 | elevator_t *e = q->elevator; | 291 | elevator_t *e = q->elevator; |
287 | 292 | ||
288 | if (q->last_merge == next) | ||
289 | q->last_merge = NULL; | ||
290 | |||
291 | if (e->ops->elevator_merge_req_fn) | 293 | if (e->ops->elevator_merge_req_fn) |
292 | e->ops->elevator_merge_req_fn(q, rq, next); | 294 | e->ops->elevator_merge_req_fn(q, rq, next); |
295 | |||
296 | q->last_merge = rq; | ||
293 | } | 297 | } |
294 | 298 | ||
295 | void elv_requeue_request(request_queue_t *q, struct request *rq) | 299 | void elv_requeue_request(request_queue_t *q, struct request *rq) |
@@ -384,6 +388,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
384 | BUG_ON(!blk_fs_request(rq)); | 388 | BUG_ON(!blk_fs_request(rq)); |
385 | rq->flags |= REQ_SORTED; | 389 | rq->flags |= REQ_SORTED; |
386 | q->elevator->ops->elevator_add_req_fn(q, rq); | 390 | q->elevator->ops->elevator_add_req_fn(q, rq); |
391 | if (q->last_merge == NULL && rq_mergeable(rq)) | ||
392 | q->last_merge = rq; | ||
387 | break; | 393 | break; |
388 | 394 | ||
389 | default: | 395 | default: |
@@ -462,9 +468,6 @@ struct request *elv_next_request(request_queue_t *q) | |||
462 | rq->flags |= REQ_STARTED; | 468 | rq->flags |= REQ_STARTED; |
463 | } | 469 | } |
464 | 470 | ||
465 | if (rq == q->last_merge) | ||
466 | q->last_merge = NULL; | ||
467 | |||
468 | if (!q->boundary_rq || q->boundary_rq == rq) { | 471 | if (!q->boundary_rq || q->boundary_rq == rq) { |
469 | q->end_sector = rq_end_sector(rq); | 472 | q->end_sector = rq_end_sector(rq); |
470 | q->boundary_rq = NULL; | 473 | q->boundary_rq = NULL; |
@@ -518,16 +521,6 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq) | |||
518 | */ | 521 | */ |
519 | if (blk_account_rq(rq)) | 522 | if (blk_account_rq(rq)) |
520 | q->in_flight++; | 523 | q->in_flight++; |
521 | |||
522 | /* | ||
523 | * the main clearing point for q->last_merge is on retrieval of | ||
524 | * request by driver (it calls elv_next_request()), but it _can_ | ||
525 | * also happen here if a request is added to the queue but later | ||
526 | * deleted without ever being given to driver (merged with another | ||
527 | * request). | ||
528 | */ | ||
529 | if (rq == q->last_merge) | ||
530 | q->last_merge = NULL; | ||
531 | } | 524 | } |
532 | 525 | ||
533 | int elv_queue_empty(request_queue_t *q) | 526 | int elv_queue_empty(request_queue_t *q) |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a2e496f285a4..bd55b1df8997 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -630,6 +630,9 @@ static inline void blkdev_dequeue_request(struct request *req) | |||
630 | static inline void elv_dispatch_add_tail(struct request_queue *q, | 630 | static inline void elv_dispatch_add_tail(struct request_queue *q, |
631 | struct request *rq) | 631 | struct request *rq) |
632 | { | 632 | { |
633 | if (q->last_merge == rq) | ||
634 | q->last_merge = NULL; | ||
635 | |||
633 | q->end_sector = rq_end_sector(rq); | 636 | q->end_sector = rq_end_sector(rq); |
634 | q->boundary_rq = rq; | 637 | q->boundary_rq = rq; |
635 | list_add_tail(&rq->queuelist, &q->queue_head); | 638 | list_add_tail(&rq->queuelist, &q->queue_head); |