diff options
Diffstat (limited to 'block/elevator.c')
-rw-r--r-- | block/elevator.c | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/block/elevator.c b/block/elevator.c index d4a49a3df829..e4c58827bb46 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -155,9 +155,10 @@ static void elevator_setup_default(void) | |||
155 | /* | 155 | /* |
156 | * If the given scheduler is not available, fall back to no-op. | 156 | * If the given scheduler is not available, fall back to no-op. |
157 | */ | 157 | */ |
158 | if (!(e = elevator_find(chosen_elevator))) | 158 | if ((e = elevator_find(chosen_elevator))) |
159 | elevator_put(e); | ||
160 | else | ||
159 | strcpy(chosen_elevator, "noop"); | 161 | strcpy(chosen_elevator, "noop"); |
160 | elevator_put(e); | ||
161 | } | 162 | } |
162 | 163 | ||
163 | static int __init elevator_setup(char *str) | 164 | static int __init elevator_setup(char *str) |
@@ -190,14 +191,14 @@ int elevator_init(request_queue_t *q, char *name) | |||
190 | 191 | ||
191 | eq = kmalloc(sizeof(struct elevator_queue), GFP_KERNEL); | 192 | eq = kmalloc(sizeof(struct elevator_queue), GFP_KERNEL); |
192 | if (!eq) { | 193 | if (!eq) { |
193 | elevator_put(e->elevator_type); | 194 | elevator_put(e); |
194 | return -ENOMEM; | 195 | return -ENOMEM; |
195 | } | 196 | } |
196 | 197 | ||
197 | ret = elevator_attach(q, e, eq); | 198 | ret = elevator_attach(q, e, eq); |
198 | if (ret) { | 199 | if (ret) { |
199 | kfree(eq); | 200 | kfree(eq); |
200 | elevator_put(e->elevator_type); | 201 | elevator_put(e); |
201 | } | 202 | } |
202 | 203 | ||
203 | return ret; | 204 | return ret; |
@@ -225,6 +226,7 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
225 | 226 | ||
226 | if (q->last_merge == rq) | 227 | if (q->last_merge == rq) |
227 | q->last_merge = NULL; | 228 | q->last_merge = NULL; |
229 | q->nr_sorted--; | ||
228 | 230 | ||
229 | boundary = q->end_sector; | 231 | boundary = q->end_sector; |
230 | 232 | ||
@@ -283,6 +285,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, | |||
283 | 285 | ||
284 | if (e->ops->elevator_merge_req_fn) | 286 | if (e->ops->elevator_merge_req_fn) |
285 | e->ops->elevator_merge_req_fn(q, rq, next); | 287 | e->ops->elevator_merge_req_fn(q, rq, next); |
288 | q->nr_sorted--; | ||
286 | 289 | ||
287 | q->last_merge = rq; | 290 | q->last_merge = rq; |
288 | } | 291 | } |
@@ -314,6 +317,20 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) | |||
314 | __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); | 317 | __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); |
315 | } | 318 | } |
316 | 319 | ||
320 | static void elv_drain_elevator(request_queue_t *q) | ||
321 | { | ||
322 | static int printed; | ||
323 | while (q->elevator->ops->elevator_dispatch_fn(q, 1)) | ||
324 | ; | ||
325 | if (q->nr_sorted == 0) | ||
326 | return; | ||
327 | if (printed++ < 10) { | ||
328 | printk(KERN_ERR "%s: forced dispatching is broken " | ||
329 | "(nr_sorted=%u), please report this\n", | ||
330 | q->elevator->elevator_type->elevator_name, q->nr_sorted); | ||
331 | } | ||
332 | } | ||
333 | |||
317 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, | 334 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, |
318 | int plug) | 335 | int plug) |
319 | { | 336 | { |
@@ -348,9 +365,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
348 | 365 | ||
349 | case ELEVATOR_INSERT_BACK: | 366 | case ELEVATOR_INSERT_BACK: |
350 | rq->flags |= REQ_SOFTBARRIER; | 367 | rq->flags |= REQ_SOFTBARRIER; |
351 | 368 | elv_drain_elevator(q); | |
352 | while (q->elevator->ops->elevator_dispatch_fn(q, 1)) | ||
353 | ; | ||
354 | list_add_tail(&rq->queuelist, &q->queue_head); | 369 | list_add_tail(&rq->queuelist, &q->queue_head); |
355 | /* | 370 | /* |
356 | * We kick the queue here for the following reasons. | 371 | * We kick the queue here for the following reasons. |
@@ -369,6 +384,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
369 | case ELEVATOR_INSERT_SORT: | 384 | case ELEVATOR_INSERT_SORT: |
370 | BUG_ON(!blk_fs_request(rq)); | 385 | BUG_ON(!blk_fs_request(rq)); |
371 | rq->flags |= REQ_SORTED; | 386 | rq->flags |= REQ_SORTED; |
387 | q->nr_sorted++; | ||
372 | if (q->last_merge == NULL && rq_mergeable(rq)) | 388 | if (q->last_merge == NULL && rq_mergeable(rq)) |
373 | q->last_merge = rq; | 389 | q->last_merge = rq; |
374 | /* | 390 | /* |
@@ -525,33 +541,19 @@ int elv_queue_empty(request_queue_t *q) | |||
525 | 541 | ||
526 | struct request *elv_latter_request(request_queue_t *q, struct request *rq) | 542 | struct request *elv_latter_request(request_queue_t *q, struct request *rq) |
527 | { | 543 | { |
528 | struct list_head *next; | ||
529 | |||
530 | elevator_t *e = q->elevator; | 544 | elevator_t *e = q->elevator; |
531 | 545 | ||
532 | if (e->ops->elevator_latter_req_fn) | 546 | if (e->ops->elevator_latter_req_fn) |
533 | return e->ops->elevator_latter_req_fn(q, rq); | 547 | return e->ops->elevator_latter_req_fn(q, rq); |
534 | |||
535 | next = rq->queuelist.next; | ||
536 | if (next != &q->queue_head && next != &rq->queuelist) | ||
537 | return list_entry_rq(next); | ||
538 | |||
539 | return NULL; | 548 | return NULL; |
540 | } | 549 | } |
541 | 550 | ||
542 | struct request *elv_former_request(request_queue_t *q, struct request *rq) | 551 | struct request *elv_former_request(request_queue_t *q, struct request *rq) |
543 | { | 552 | { |
544 | struct list_head *prev; | ||
545 | |||
546 | elevator_t *e = q->elevator; | 553 | elevator_t *e = q->elevator; |
547 | 554 | ||
548 | if (e->ops->elevator_former_req_fn) | 555 | if (e->ops->elevator_former_req_fn) |
549 | return e->ops->elevator_former_req_fn(q, rq); | 556 | return e->ops->elevator_former_req_fn(q, rq); |
550 | |||
551 | prev = rq->queuelist.prev; | ||
552 | if (prev != &q->queue_head && prev != &rq->queuelist) | ||
553 | return list_entry_rq(prev); | ||
554 | |||
555 | return NULL; | 557 | return NULL; |
556 | } | 558 | } |
557 | 559 | ||
@@ -691,13 +693,15 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) | |||
691 | 693 | ||
692 | set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); | 694 | set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); |
693 | 695 | ||
694 | while (q->elevator->ops->elevator_dispatch_fn(q, 1)) | 696 | elv_drain_elevator(q); |
695 | ; | ||
696 | 697 | ||
697 | while (q->rq.elvpriv) { | 698 | while (q->rq.elvpriv) { |
699 | blk_remove_plug(q); | ||
700 | q->request_fn(q); | ||
698 | spin_unlock_irq(q->queue_lock); | 701 | spin_unlock_irq(q->queue_lock); |
699 | msleep(10); | 702 | msleep(10); |
700 | spin_lock_irq(q->queue_lock); | 703 | spin_lock_irq(q->queue_lock); |
704 | elv_drain_elevator(q); | ||
701 | } | 705 | } |
702 | 706 | ||
703 | spin_unlock_irq(q->queue_lock); | 707 | spin_unlock_irq(q->queue_lock); |
@@ -744,13 +748,15 @@ error: | |||
744 | ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) | 748 | ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) |
745 | { | 749 | { |
746 | char elevator_name[ELV_NAME_MAX]; | 750 | char elevator_name[ELV_NAME_MAX]; |
751 | size_t len; | ||
747 | struct elevator_type *e; | 752 | struct elevator_type *e; |
748 | 753 | ||
749 | memset(elevator_name, 0, sizeof(elevator_name)); | 754 | elevator_name[sizeof(elevator_name) - 1] = '\0'; |
750 | strncpy(elevator_name, name, sizeof(elevator_name)); | 755 | strncpy(elevator_name, name, sizeof(elevator_name) - 1); |
756 | len = strlen(elevator_name); | ||
751 | 757 | ||
752 | if (elevator_name[strlen(elevator_name) - 1] == '\n') | 758 | if (len && elevator_name[len - 1] == '\n') |
753 | elevator_name[strlen(elevator_name) - 1] = '\0'; | 759 | elevator_name[len - 1] = '\0'; |
754 | 760 | ||
755 | e = elevator_get(elevator_name); | 761 | e = elevator_get(elevator_name); |
756 | if (!e) { | 762 | if (!e) { |