diff options
Diffstat (limited to 'drivers/block/cfq-iosched.c')
-rw-r--r-- | drivers/block/cfq-iosched.c | 372 |
1 files changed, 85 insertions, 287 deletions
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index cd056e7e64ec..94690e4d41e0 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c | |||
@@ -84,7 +84,6 @@ static int cfq_max_depth = 2; | |||
84 | (node)->rb_left = NULL; \ | 84 | (node)->rb_left = NULL; \ |
85 | } while (0) | 85 | } while (0) |
86 | #define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) | 86 | #define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) |
87 | #define ON_RB(node) ((node)->rb_color != RB_NONE) | ||
88 | #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) | 87 | #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) |
89 | #define rq_rb_key(rq) (rq)->sector | 88 | #define rq_rb_key(rq) (rq)->sector |
90 | 89 | ||
@@ -271,10 +270,7 @@ CFQ_CFQQ_FNS(expired); | |||
271 | #undef CFQ_CFQQ_FNS | 270 | #undef CFQ_CFQQ_FNS |
272 | 271 | ||
273 | enum cfq_rq_state_flags { | 272 | enum cfq_rq_state_flags { |
274 | CFQ_CRQ_FLAG_in_flight = 0, | 273 | CFQ_CRQ_FLAG_is_sync = 0, |
275 | CFQ_CRQ_FLAG_in_driver, | ||
276 | CFQ_CRQ_FLAG_is_sync, | ||
277 | CFQ_CRQ_FLAG_requeued, | ||
278 | }; | 274 | }; |
279 | 275 | ||
280 | #define CFQ_CRQ_FNS(name) \ | 276 | #define CFQ_CRQ_FNS(name) \ |
@@ -291,14 +287,11 @@ static inline int cfq_crq_##name(const struct cfq_rq *crq) \ | |||
291 | return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \ | 287 | return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \ |
292 | } | 288 | } |
293 | 289 | ||
294 | CFQ_CRQ_FNS(in_flight); | ||
295 | CFQ_CRQ_FNS(in_driver); | ||
296 | CFQ_CRQ_FNS(is_sync); | 290 | CFQ_CRQ_FNS(is_sync); |
297 | CFQ_CRQ_FNS(requeued); | ||
298 | #undef CFQ_CRQ_FNS | 291 | #undef CFQ_CRQ_FNS |
299 | 292 | ||
300 | static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); | 293 | static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); |
301 | static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *); | 294 | static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); |
302 | static void cfq_put_cfqd(struct cfq_data *cfqd); | 295 | static void cfq_put_cfqd(struct cfq_data *cfqd); |
303 | 296 | ||
304 | #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) | 297 | #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) |
@@ -311,14 +304,6 @@ static inline void cfq_del_crq_hash(struct cfq_rq *crq) | |||
311 | hlist_del_init(&crq->hash); | 304 | hlist_del_init(&crq->hash); |
312 | } | 305 | } |
313 | 306 | ||
314 | static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq) | ||
315 | { | ||
316 | cfq_del_crq_hash(crq); | ||
317 | |||
318 | if (q->last_merge == crq->request) | ||
319 | q->last_merge = NULL; | ||
320 | } | ||
321 | |||
322 | static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) | 307 | static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) |
323 | { | 308 | { |
324 | const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); | 309 | const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); |
@@ -347,18 +332,13 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) | |||
347 | return NULL; | 332 | return NULL; |
348 | } | 333 | } |
349 | 334 | ||
350 | static inline int cfq_pending_requests(struct cfq_data *cfqd) | ||
351 | { | ||
352 | return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues; | ||
353 | } | ||
354 | |||
355 | /* | 335 | /* |
356 | * scheduler run of queue, if there are requests pending and no one in the | 336 | * scheduler run of queue, if there are requests pending and no one in the |
357 | * driver that will restart queueing | 337 | * driver that will restart queueing |
358 | */ | 338 | */ |
359 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) | 339 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) |
360 | { | 340 | { |
361 | if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd)) | 341 | if (!cfqd->rq_in_driver && cfqd->busy_queues) |
362 | kblockd_schedule_work(&cfqd->unplug_work); | 342 | kblockd_schedule_work(&cfqd->unplug_work); |
363 | } | 343 | } |
364 | 344 | ||
@@ -366,7 +346,7 @@ static int cfq_queue_empty(request_queue_t *q) | |||
366 | { | 346 | { |
367 | struct cfq_data *cfqd = q->elevator->elevator_data; | 347 | struct cfq_data *cfqd = q->elevator->elevator_data; |
368 | 348 | ||
369 | return !cfq_pending_requests(cfqd); | 349 | return !cfqd->busy_queues; |
370 | } | 350 | } |
371 | 351 | ||
372 | /* | 352 | /* |
@@ -386,11 +366,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) | |||
386 | if (crq2 == NULL) | 366 | if (crq2 == NULL) |
387 | return crq1; | 367 | return crq1; |
388 | 368 | ||
389 | if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) | ||
390 | return crq1; | ||
391 | else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) | ||
392 | return crq2; | ||
393 | |||
394 | if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) | 369 | if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) |
395 | return crq1; | 370 | return crq1; |
396 | else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) | 371 | else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) |
@@ -461,10 +436,7 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
461 | struct cfq_rq *crq_next = NULL, *crq_prev = NULL; | 436 | struct cfq_rq *crq_next = NULL, *crq_prev = NULL; |
462 | struct rb_node *rbnext, *rbprev; | 437 | struct rb_node *rbnext, *rbprev; |
463 | 438 | ||
464 | rbnext = NULL; | 439 | if (!(rbnext = rb_next(&last->rb_node))) { |
465 | if (ON_RB(&last->rb_node)) | ||
466 | rbnext = rb_next(&last->rb_node); | ||
467 | if (!rbnext) { | ||
468 | rbnext = rb_first(&cfqq->sort_list); | 440 | rbnext = rb_first(&cfqq->sort_list); |
469 | if (rbnext == &last->rb_node) | 441 | if (rbnext == &last->rb_node) |
470 | rbnext = NULL; | 442 | rbnext = NULL; |
@@ -545,13 +517,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) | |||
545 | * the pending list according to last request service | 517 | * the pending list according to last request service |
546 | */ | 518 | */ |
547 | static inline void | 519 | static inline void |
548 | cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue) | 520 | cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
549 | { | 521 | { |
550 | BUG_ON(cfq_cfqq_on_rr(cfqq)); | 522 | BUG_ON(cfq_cfqq_on_rr(cfqq)); |
551 | cfq_mark_cfqq_on_rr(cfqq); | 523 | cfq_mark_cfqq_on_rr(cfqq); |
552 | cfqd->busy_queues++; | 524 | cfqd->busy_queues++; |
553 | 525 | ||
554 | cfq_resort_rr_list(cfqq, requeue); | 526 | cfq_resort_rr_list(cfqq, 0); |
555 | } | 527 | } |
556 | 528 | ||
557 | static inline void | 529 | static inline void |
@@ -571,22 +543,19 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
571 | static inline void cfq_del_crq_rb(struct cfq_rq *crq) | 543 | static inline void cfq_del_crq_rb(struct cfq_rq *crq) |
572 | { | 544 | { |
573 | struct cfq_queue *cfqq = crq->cfq_queue; | 545 | struct cfq_queue *cfqq = crq->cfq_queue; |
546 | struct cfq_data *cfqd = cfqq->cfqd; | ||
547 | const int sync = cfq_crq_is_sync(crq); | ||
574 | 548 | ||
575 | if (ON_RB(&crq->rb_node)) { | 549 | BUG_ON(!cfqq->queued[sync]); |
576 | struct cfq_data *cfqd = cfqq->cfqd; | 550 | cfqq->queued[sync]--; |
577 | const int sync = cfq_crq_is_sync(crq); | ||
578 | 551 | ||
579 | BUG_ON(!cfqq->queued[sync]); | 552 | cfq_update_next_crq(crq); |
580 | cfqq->queued[sync]--; | ||
581 | 553 | ||
582 | cfq_update_next_crq(crq); | 554 | rb_erase(&crq->rb_node, &cfqq->sort_list); |
555 | RB_CLEAR_COLOR(&crq->rb_node); | ||
583 | 556 | ||
584 | rb_erase(&crq->rb_node, &cfqq->sort_list); | 557 | if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) |
585 | RB_CLEAR_COLOR(&crq->rb_node); | 558 | cfq_del_cfqq_rr(cfqd, cfqq); |
586 | |||
587 | if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) | ||
588 | cfq_del_cfqq_rr(cfqd, cfqq); | ||
589 | } | ||
590 | } | 559 | } |
591 | 560 | ||
592 | static struct cfq_rq * | 561 | static struct cfq_rq * |
@@ -627,12 +596,12 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) | |||
627 | * if that happens, put the alias on the dispatch list | 596 | * if that happens, put the alias on the dispatch list |
628 | */ | 597 | */ |
629 | while ((__alias = __cfq_add_crq_rb(crq)) != NULL) | 598 | while ((__alias = __cfq_add_crq_rb(crq)) != NULL) |
630 | cfq_dispatch_sort(cfqd->queue, __alias); | 599 | cfq_dispatch_insert(cfqd->queue, __alias); |
631 | 600 | ||
632 | rb_insert_color(&crq->rb_node, &cfqq->sort_list); | 601 | rb_insert_color(&crq->rb_node, &cfqq->sort_list); |
633 | 602 | ||
634 | if (!cfq_cfqq_on_rr(cfqq)) | 603 | if (!cfq_cfqq_on_rr(cfqq)) |
635 | cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq)); | 604 | cfq_add_cfqq_rr(cfqd, cfqq); |
636 | 605 | ||
637 | /* | 606 | /* |
638 | * check if this request is a better next-serve candidate | 607 | * check if this request is a better next-serve candidate |
@@ -643,10 +612,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq) | |||
643 | static inline void | 612 | static inline void |
644 | cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) | 613 | cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq) |
645 | { | 614 | { |
646 | if (ON_RB(&crq->rb_node)) { | 615 | rb_erase(&crq->rb_node, &cfqq->sort_list); |
647 | rb_erase(&crq->rb_node, &cfqq->sort_list); | 616 | cfqq->queued[cfq_crq_is_sync(crq)]--; |
648 | cfqq->queued[cfq_crq_is_sync(crq)]--; | ||
649 | } | ||
650 | 617 | ||
651 | cfq_add_crq_rb(crq); | 618 | cfq_add_crq_rb(crq); |
652 | } | 619 | } |
@@ -676,49 +643,28 @@ out: | |||
676 | return NULL; | 643 | return NULL; |
677 | } | 644 | } |
678 | 645 | ||
679 | static void cfq_deactivate_request(request_queue_t *q, struct request *rq) | 646 | static void cfq_activate_request(request_queue_t *q, struct request *rq) |
680 | { | 647 | { |
681 | struct cfq_data *cfqd = q->elevator->elevator_data; | 648 | struct cfq_data *cfqd = q->elevator->elevator_data; |
682 | struct cfq_rq *crq = RQ_DATA(rq); | ||
683 | |||
684 | if (crq) { | ||
685 | struct cfq_queue *cfqq = crq->cfq_queue; | ||
686 | |||
687 | if (cfq_crq_in_driver(crq)) { | ||
688 | cfq_clear_crq_in_driver(crq); | ||
689 | WARN_ON(!cfqd->rq_in_driver); | ||
690 | cfqd->rq_in_driver--; | ||
691 | } | ||
692 | if (cfq_crq_in_flight(crq)) { | ||
693 | const int sync = cfq_crq_is_sync(crq); | ||
694 | 649 | ||
695 | cfq_clear_crq_in_flight(crq); | 650 | cfqd->rq_in_driver++; |
696 | WARN_ON(!cfqq->on_dispatch[sync]); | ||
697 | cfqq->on_dispatch[sync]--; | ||
698 | } | ||
699 | cfq_mark_crq_requeued(crq); | ||
700 | } | ||
701 | } | 651 | } |
702 | 652 | ||
703 | /* | 653 | static void cfq_deactivate_request(request_queue_t *q, struct request *rq) |
704 | * make sure the service time gets corrected on reissue of this request | ||
705 | */ | ||
706 | static void cfq_requeue_request(request_queue_t *q, struct request *rq) | ||
707 | { | 654 | { |
708 | cfq_deactivate_request(q, rq); | 655 | struct cfq_data *cfqd = q->elevator->elevator_data; |
709 | list_add(&rq->queuelist, &q->queue_head); | 656 | |
657 | WARN_ON(!cfqd->rq_in_driver); | ||
658 | cfqd->rq_in_driver--; | ||
710 | } | 659 | } |
711 | 660 | ||
712 | static void cfq_remove_request(request_queue_t *q, struct request *rq) | 661 | static void cfq_remove_request(struct request *rq) |
713 | { | 662 | { |
714 | struct cfq_rq *crq = RQ_DATA(rq); | 663 | struct cfq_rq *crq = RQ_DATA(rq); |
715 | 664 | ||
716 | if (crq) { | 665 | list_del_init(&rq->queuelist); |
717 | list_del_init(&rq->queuelist); | 666 | cfq_del_crq_rb(crq); |
718 | cfq_del_crq_rb(crq); | 667 | cfq_del_crq_hash(crq); |
719 | cfq_remove_merge_hints(q, crq); | ||
720 | |||
721 | } | ||
722 | } | 668 | } |
723 | 669 | ||
724 | static int | 670 | static int |
@@ -728,12 +674,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
728 | struct request *__rq; | 674 | struct request *__rq; |
729 | int ret; | 675 | int ret; |
730 | 676 | ||
731 | ret = elv_try_last_merge(q, bio); | ||
732 | if (ret != ELEVATOR_NO_MERGE) { | ||
733 | __rq = q->last_merge; | ||
734 | goto out_insert; | ||
735 | } | ||
736 | |||
737 | __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); | 677 | __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); |
738 | if (__rq && elv_rq_merge_ok(__rq, bio)) { | 678 | if (__rq && elv_rq_merge_ok(__rq, bio)) { |
739 | ret = ELEVATOR_BACK_MERGE; | 679 | ret = ELEVATOR_BACK_MERGE; |
@@ -748,8 +688,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
748 | 688 | ||
749 | return ELEVATOR_NO_MERGE; | 689 | return ELEVATOR_NO_MERGE; |
750 | out: | 690 | out: |
751 | q->last_merge = __rq; | ||
752 | out_insert: | ||
753 | *req = __rq; | 691 | *req = __rq; |
754 | return ret; | 692 | return ret; |
755 | } | 693 | } |
@@ -762,14 +700,12 @@ static void cfq_merged_request(request_queue_t *q, struct request *req) | |||
762 | cfq_del_crq_hash(crq); | 700 | cfq_del_crq_hash(crq); |
763 | cfq_add_crq_hash(cfqd, crq); | 701 | cfq_add_crq_hash(cfqd, crq); |
764 | 702 | ||
765 | if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { | 703 | if (rq_rb_key(req) != crq->rb_key) { |
766 | struct cfq_queue *cfqq = crq->cfq_queue; | 704 | struct cfq_queue *cfqq = crq->cfq_queue; |
767 | 705 | ||
768 | cfq_update_next_crq(crq); | 706 | cfq_update_next_crq(crq); |
769 | cfq_reposition_crq_rb(cfqq, crq); | 707 | cfq_reposition_crq_rb(cfqq, crq); |
770 | } | 708 | } |
771 | |||
772 | q->last_merge = req; | ||
773 | } | 709 | } |
774 | 710 | ||
775 | static void | 711 | static void |
@@ -785,7 +721,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq, | |||
785 | time_before(next->start_time, rq->start_time)) | 721 | time_before(next->start_time, rq->start_time)) |
786 | list_move(&rq->queuelist, &next->queuelist); | 722 | list_move(&rq->queuelist, &next->queuelist); |
787 | 723 | ||
788 | cfq_remove_request(q, next); | 724 | cfq_remove_request(next); |
789 | } | 725 | } |
790 | 726 | ||
791 | static inline void | 727 | static inline void |
@@ -992,53 +928,15 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
992 | return 1; | 928 | return 1; |
993 | } | 929 | } |
994 | 930 | ||
995 | /* | 931 | static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq) |
996 | * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues, | ||
997 | * this function sector sorts the selected request to minimize seeks. we start | ||
998 | * at cfqd->last_sector, not 0. | ||
999 | */ | ||
1000 | static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq) | ||
1001 | { | 932 | { |
1002 | struct cfq_data *cfqd = q->elevator->elevator_data; | 933 | struct cfq_data *cfqd = q->elevator->elevator_data; |
1003 | struct cfq_queue *cfqq = crq->cfq_queue; | 934 | struct cfq_queue *cfqq = crq->cfq_queue; |
1004 | struct list_head *head = &q->queue_head, *entry = head; | ||
1005 | struct request *__rq; | ||
1006 | sector_t last; | ||
1007 | |||
1008 | list_del(&crq->request->queuelist); | ||
1009 | |||
1010 | last = cfqd->last_sector; | ||
1011 | list_for_each_entry_reverse(__rq, head, queuelist) { | ||
1012 | struct cfq_rq *__crq = RQ_DATA(__rq); | ||
1013 | |||
1014 | if (blk_barrier_rq(__rq)) | ||
1015 | break; | ||
1016 | if (!blk_fs_request(__rq)) | ||
1017 | break; | ||
1018 | if (cfq_crq_requeued(__crq)) | ||
1019 | break; | ||
1020 | |||
1021 | if (__rq->sector <= crq->request->sector) | ||
1022 | break; | ||
1023 | if (__rq->sector > last && crq->request->sector < last) { | ||
1024 | last = crq->request->sector + crq->request->nr_sectors; | ||
1025 | break; | ||
1026 | } | ||
1027 | entry = &__rq->queuelist; | ||
1028 | } | ||
1029 | |||
1030 | cfqd->last_sector = last; | ||
1031 | 935 | ||
1032 | cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq); | 936 | cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq); |
1033 | 937 | cfq_remove_request(crq->request); | |
1034 | cfq_del_crq_rb(crq); | ||
1035 | cfq_remove_merge_hints(q, crq); | ||
1036 | |||
1037 | cfq_mark_crq_in_flight(crq); | ||
1038 | cfq_clear_crq_requeued(crq); | ||
1039 | |||
1040 | cfqq->on_dispatch[cfq_crq_is_sync(crq)]++; | 938 | cfqq->on_dispatch[cfq_crq_is_sync(crq)]++; |
1041 | list_add_tail(&crq->request->queuelist, entry); | 939 | elv_dispatch_sort(q, crq->request); |
1042 | } | 940 | } |
1043 | 941 | ||
1044 | /* | 942 | /* |
@@ -1159,7 +1057,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1159 | /* | 1057 | /* |
1160 | * finally, insert request into driver dispatch list | 1058 | * finally, insert request into driver dispatch list |
1161 | */ | 1059 | */ |
1162 | cfq_dispatch_sort(cfqd->queue, crq); | 1060 | cfq_dispatch_insert(cfqd->queue, crq); |
1163 | 1061 | ||
1164 | cfqd->dispatch_slice++; | 1062 | cfqd->dispatch_slice++; |
1165 | dispatched++; | 1063 | dispatched++; |
@@ -1194,7 +1092,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1194 | } | 1092 | } |
1195 | 1093 | ||
1196 | static int | 1094 | static int |
1197 | cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) | 1095 | cfq_dispatch_requests(request_queue_t *q, int force) |
1198 | { | 1096 | { |
1199 | struct cfq_data *cfqd = q->elevator->elevator_data; | 1097 | struct cfq_data *cfqd = q->elevator->elevator_data; |
1200 | struct cfq_queue *cfqq; | 1098 | struct cfq_queue *cfqq; |
@@ -1204,12 +1102,25 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) | |||
1204 | 1102 | ||
1205 | cfqq = cfq_select_queue(cfqd, force); | 1103 | cfqq = cfq_select_queue(cfqd, force); |
1206 | if (cfqq) { | 1104 | if (cfqq) { |
1105 | int max_dispatch; | ||
1106 | |||
1107 | /* | ||
1108 | * if idle window is disabled, allow queue buildup | ||
1109 | */ | ||
1110 | if (!cfq_cfqq_idle_window(cfqq) && | ||
1111 | cfqd->rq_in_driver >= cfqd->cfq_max_depth) | ||
1112 | return 0; | ||
1113 | |||
1207 | cfq_clear_cfqq_must_dispatch(cfqq); | 1114 | cfq_clear_cfqq_must_dispatch(cfqq); |
1208 | cfq_clear_cfqq_wait_request(cfqq); | 1115 | cfq_clear_cfqq_wait_request(cfqq); |
1209 | del_timer(&cfqd->idle_slice_timer); | 1116 | del_timer(&cfqd->idle_slice_timer); |
1210 | 1117 | ||
1211 | if (cfq_class_idle(cfqq)) | 1118 | if (!force) { |
1212 | max_dispatch = 1; | 1119 | max_dispatch = cfqd->cfq_quantum; |
1120 | if (cfq_class_idle(cfqq)) | ||
1121 | max_dispatch = 1; | ||
1122 | } else | ||
1123 | max_dispatch = INT_MAX; | ||
1213 | 1124 | ||
1214 | return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); | 1125 | return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); |
1215 | } | 1126 | } |
@@ -1217,93 +1128,6 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force) | |||
1217 | return 0; | 1128 | return 0; |
1218 | } | 1129 | } |
1219 | 1130 | ||
1220 | static inline void cfq_account_dispatch(struct cfq_rq *crq) | ||
1221 | { | ||
1222 | struct cfq_queue *cfqq = crq->cfq_queue; | ||
1223 | struct cfq_data *cfqd = cfqq->cfqd; | ||
1224 | |||
1225 | if (unlikely(!blk_fs_request(crq->request))) | ||
1226 | return; | ||
1227 | |||
1228 | /* | ||
1229 | * accounted bit is necessary since some drivers will call | ||
1230 | * elv_next_request() many times for the same request (eg ide) | ||
1231 | */ | ||
1232 | if (cfq_crq_in_driver(crq)) | ||
1233 | return; | ||
1234 | |||
1235 | cfq_mark_crq_in_driver(crq); | ||
1236 | cfqd->rq_in_driver++; | ||
1237 | } | ||
1238 | |||
1239 | static inline void | ||
1240 | cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq) | ||
1241 | { | ||
1242 | struct cfq_data *cfqd = cfqq->cfqd; | ||
1243 | unsigned long now; | ||
1244 | |||
1245 | if (!cfq_crq_in_driver(crq)) | ||
1246 | return; | ||
1247 | |||
1248 | now = jiffies; | ||
1249 | |||
1250 | WARN_ON(!cfqd->rq_in_driver); | ||
1251 | cfqd->rq_in_driver--; | ||
1252 | |||
1253 | if (!cfq_class_idle(cfqq)) | ||
1254 | cfqd->last_end_request = now; | ||
1255 | |||
1256 | if (!cfq_cfqq_dispatched(cfqq)) { | ||
1257 | if (cfq_cfqq_on_rr(cfqq)) { | ||
1258 | cfqq->service_last = now; | ||
1259 | cfq_resort_rr_list(cfqq, 0); | ||
1260 | } | ||
1261 | if (cfq_cfqq_expired(cfqq)) { | ||
1262 | __cfq_slice_expired(cfqd, cfqq, 0); | ||
1263 | cfq_schedule_dispatch(cfqd); | ||
1264 | } | ||
1265 | } | ||
1266 | |||
1267 | if (cfq_crq_is_sync(crq)) | ||
1268 | crq->io_context->last_end_request = now; | ||
1269 | } | ||
1270 | |||
1271 | static struct request *cfq_next_request(request_queue_t *q) | ||
1272 | { | ||
1273 | struct cfq_data *cfqd = q->elevator->elevator_data; | ||
1274 | struct request *rq; | ||
1275 | |||
1276 | if (!list_empty(&q->queue_head)) { | ||
1277 | struct cfq_rq *crq; | ||
1278 | dispatch: | ||
1279 | rq = list_entry_rq(q->queue_head.next); | ||
1280 | |||
1281 | crq = RQ_DATA(rq); | ||
1282 | if (crq) { | ||
1283 | struct cfq_queue *cfqq = crq->cfq_queue; | ||
1284 | |||
1285 | /* | ||
1286 | * if idle window is disabled, allow queue buildup | ||
1287 | */ | ||
1288 | if (!cfq_crq_in_driver(crq) && | ||
1289 | !cfq_cfqq_idle_window(cfqq) && | ||
1290 | !blk_barrier_rq(rq) && | ||
1291 | cfqd->rq_in_driver >= cfqd->cfq_max_depth) | ||
1292 | return NULL; | ||
1293 | |||
1294 | cfq_remove_merge_hints(q, crq); | ||
1295 | cfq_account_dispatch(crq); | ||
1296 | } | ||
1297 | |||
1298 | return rq; | ||
1299 | } | ||
1300 | |||
1301 | if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0)) | ||
1302 | goto dispatch; | ||
1303 | |||
1304 | return NULL; | ||
1305 | } | ||
1306 | |||
1307 | /* | 1131 | /* |
1308 | * task holds one reference to the queue, dropped when task exits. each crq | 1132 | * task holds one reference to the queue, dropped when task exits. each crq |
1309 | * in-flight on this queue also holds a reference, dropped when crq is freed. | 1133 | * in-flight on this queue also holds a reference, dropped when crq is freed. |
@@ -1422,7 +1246,7 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) | |||
1422 | } | 1246 | } |
1423 | 1247 | ||
1424 | static struct cfq_io_context * | 1248 | static struct cfq_io_context * |
1425 | cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask) | 1249 | cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) |
1426 | { | 1250 | { |
1427 | struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); | 1251 | struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); |
1428 | 1252 | ||
@@ -1517,7 +1341,7 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) | |||
1517 | 1341 | ||
1518 | static struct cfq_queue * | 1342 | static struct cfq_queue * |
1519 | cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, | 1343 | cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, |
1520 | int gfp_mask) | 1344 | gfp_t gfp_mask) |
1521 | { | 1345 | { |
1522 | const int hashval = hash_long(key, CFQ_QHASH_SHIFT); | 1346 | const int hashval = hash_long(key, CFQ_QHASH_SHIFT); |
1523 | struct cfq_queue *cfqq, *new_cfqq = NULL; | 1347 | struct cfq_queue *cfqq, *new_cfqq = NULL; |
@@ -1578,7 +1402,7 @@ out: | |||
1578 | * cfqq, so we don't need to worry about it disappearing | 1402 | * cfqq, so we don't need to worry about it disappearing |
1579 | */ | 1403 | */ |
1580 | static struct cfq_io_context * | 1404 | static struct cfq_io_context * |
1581 | cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask) | 1405 | cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) |
1582 | { | 1406 | { |
1583 | struct io_context *ioc = NULL; | 1407 | struct io_context *ioc = NULL; |
1584 | struct cfq_io_context *cic; | 1408 | struct cfq_io_context *cic; |
@@ -1816,8 +1640,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1816 | } | 1640 | } |
1817 | } | 1641 | } |
1818 | 1642 | ||
1819 | static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) | 1643 | static void cfq_insert_request(request_queue_t *q, struct request *rq) |
1820 | { | 1644 | { |
1645 | struct cfq_data *cfqd = q->elevator->elevator_data; | ||
1821 | struct cfq_rq *crq = RQ_DATA(rq); | 1646 | struct cfq_rq *crq = RQ_DATA(rq); |
1822 | struct cfq_queue *cfqq = crq->cfq_queue; | 1647 | struct cfq_queue *cfqq = crq->cfq_queue; |
1823 | 1648 | ||
@@ -1827,66 +1652,43 @@ static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq) | |||
1827 | 1652 | ||
1828 | list_add_tail(&rq->queuelist, &cfqq->fifo); | 1653 | list_add_tail(&rq->queuelist, &cfqq->fifo); |
1829 | 1654 | ||
1830 | if (rq_mergeable(rq)) { | 1655 | if (rq_mergeable(rq)) |
1831 | cfq_add_crq_hash(cfqd, crq); | 1656 | cfq_add_crq_hash(cfqd, crq); |
1832 | 1657 | ||
1833 | if (!cfqd->queue->last_merge) | ||
1834 | cfqd->queue->last_merge = rq; | ||
1835 | } | ||
1836 | |||
1837 | cfq_crq_enqueued(cfqd, cfqq, crq); | 1658 | cfq_crq_enqueued(cfqd, cfqq, crq); |
1838 | } | 1659 | } |
1839 | 1660 | ||
1840 | static void | ||
1841 | cfq_insert_request(request_queue_t *q, struct request *rq, int where) | ||
1842 | { | ||
1843 | struct cfq_data *cfqd = q->elevator->elevator_data; | ||
1844 | |||
1845 | switch (where) { | ||
1846 | case ELEVATOR_INSERT_BACK: | ||
1847 | while (cfq_dispatch_requests(q, INT_MAX, 1)) | ||
1848 | ; | ||
1849 | list_add_tail(&rq->queuelist, &q->queue_head); | ||
1850 | /* | ||
1851 | * If we were idling with pending requests on | ||
1852 | * inactive cfqqs, force dispatching will | ||
1853 | * remove the idle timer and the queue won't | ||
1854 | * be kicked by __make_request() afterward. | ||
1855 | * Kick it here. | ||
1856 | */ | ||
1857 | cfq_schedule_dispatch(cfqd); | ||
1858 | break; | ||
1859 | case ELEVATOR_INSERT_FRONT: | ||
1860 | list_add(&rq->queuelist, &q->queue_head); | ||
1861 | break; | ||
1862 | case ELEVATOR_INSERT_SORT: | ||
1863 | BUG_ON(!blk_fs_request(rq)); | ||
1864 | cfq_enqueue(cfqd, rq); | ||
1865 | break; | ||
1866 | default: | ||
1867 | printk("%s: bad insert point %d\n", __FUNCTION__,where); | ||
1868 | return; | ||
1869 | } | ||
1870 | } | ||
1871 | |||
1872 | static void cfq_completed_request(request_queue_t *q, struct request *rq) | 1661 | static void cfq_completed_request(request_queue_t *q, struct request *rq) |
1873 | { | 1662 | { |
1874 | struct cfq_rq *crq = RQ_DATA(rq); | 1663 | struct cfq_rq *crq = RQ_DATA(rq); |
1875 | struct cfq_queue *cfqq; | 1664 | struct cfq_queue *cfqq = crq->cfq_queue; |
1665 | struct cfq_data *cfqd = cfqq->cfqd; | ||
1666 | const int sync = cfq_crq_is_sync(crq); | ||
1667 | unsigned long now; | ||
1876 | 1668 | ||
1877 | if (unlikely(!blk_fs_request(rq))) | 1669 | now = jiffies; |
1878 | return; | ||
1879 | 1670 | ||
1880 | cfqq = crq->cfq_queue; | 1671 | WARN_ON(!cfqd->rq_in_driver); |
1672 | WARN_ON(!cfqq->on_dispatch[sync]); | ||
1673 | cfqd->rq_in_driver--; | ||
1674 | cfqq->on_dispatch[sync]--; | ||
1881 | 1675 | ||
1882 | if (cfq_crq_in_flight(crq)) { | 1676 | if (!cfq_class_idle(cfqq)) |
1883 | const int sync = cfq_crq_is_sync(crq); | 1677 | cfqd->last_end_request = now; |
1884 | 1678 | ||
1885 | WARN_ON(!cfqq->on_dispatch[sync]); | 1679 | if (!cfq_cfqq_dispatched(cfqq)) { |
1886 | cfqq->on_dispatch[sync]--; | 1680 | if (cfq_cfqq_on_rr(cfqq)) { |
1681 | cfqq->service_last = now; | ||
1682 | cfq_resort_rr_list(cfqq, 0); | ||
1683 | } | ||
1684 | if (cfq_cfqq_expired(cfqq)) { | ||
1685 | __cfq_slice_expired(cfqd, cfqq, 0); | ||
1686 | cfq_schedule_dispatch(cfqd); | ||
1687 | } | ||
1887 | } | 1688 | } |
1888 | 1689 | ||
1889 | cfq_account_completion(cfqq, crq); | 1690 | if (cfq_crq_is_sync(crq)) |
1691 | crq->io_context->last_end_request = now; | ||
1890 | } | 1692 | } |
1891 | 1693 | ||
1892 | static struct request * | 1694 | static struct request * |
@@ -2075,7 +1877,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq) | |||
2075 | */ | 1877 | */ |
2076 | static int | 1878 | static int |
2077 | cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | 1879 | cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, |
2078 | int gfp_mask) | 1880 | gfp_t gfp_mask) |
2079 | { | 1881 | { |
2080 | struct cfq_data *cfqd = q->elevator->elevator_data; | 1882 | struct cfq_data *cfqd = q->elevator->elevator_data; |
2081 | struct task_struct *tsk = current; | 1883 | struct task_struct *tsk = current; |
@@ -2118,9 +1920,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
2118 | INIT_HLIST_NODE(&crq->hash); | 1920 | INIT_HLIST_NODE(&crq->hash); |
2119 | crq->cfq_queue = cfqq; | 1921 | crq->cfq_queue = cfqq; |
2120 | crq->io_context = cic; | 1922 | crq->io_context = cic; |
2121 | cfq_clear_crq_in_flight(crq); | ||
2122 | cfq_clear_crq_in_driver(crq); | ||
2123 | cfq_clear_crq_requeued(crq); | ||
2124 | 1923 | ||
2125 | if (rw == READ || process_sync(tsk)) | 1924 | if (rw == READ || process_sync(tsk)) |
2126 | cfq_mark_crq_is_sync(crq); | 1925 | cfq_mark_crq_is_sync(crq); |
@@ -2201,7 +2000,7 @@ static void cfq_idle_slice_timer(unsigned long data) | |||
2201 | * only expire and reinvoke request handler, if there are | 2000 | * only expire and reinvoke request handler, if there are |
2202 | * other queues with pending requests | 2001 | * other queues with pending requests |
2203 | */ | 2002 | */ |
2204 | if (!cfq_pending_requests(cfqd)) { | 2003 | if (!cfqd->busy_queues) { |
2205 | cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end); | 2004 | cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end); |
2206 | add_timer(&cfqd->idle_slice_timer); | 2005 | add_timer(&cfqd->idle_slice_timer); |
2207 | goto out_cont; | 2006 | goto out_cont; |
@@ -2576,10 +2375,9 @@ static struct elevator_type iosched_cfq = { | |||
2576 | .elevator_merge_fn = cfq_merge, | 2375 | .elevator_merge_fn = cfq_merge, |
2577 | .elevator_merged_fn = cfq_merged_request, | 2376 | .elevator_merged_fn = cfq_merged_request, |
2578 | .elevator_merge_req_fn = cfq_merged_requests, | 2377 | .elevator_merge_req_fn = cfq_merged_requests, |
2579 | .elevator_next_req_fn = cfq_next_request, | 2378 | .elevator_dispatch_fn = cfq_dispatch_requests, |
2580 | .elevator_add_req_fn = cfq_insert_request, | 2379 | .elevator_add_req_fn = cfq_insert_request, |
2581 | .elevator_remove_req_fn = cfq_remove_request, | 2380 | .elevator_activate_req_fn = cfq_activate_request, |
2582 | .elevator_requeue_req_fn = cfq_requeue_request, | ||
2583 | .elevator_deactivate_req_fn = cfq_deactivate_request, | 2381 | .elevator_deactivate_req_fn = cfq_deactivate_request, |
2584 | .elevator_queue_empty_fn = cfq_queue_empty, | 2382 | .elevator_queue_empty_fn = cfq_queue_empty, |
2585 | .elevator_completed_req_fn = cfq_completed_request, | 2383 | .elevator_completed_req_fn = cfq_completed_request, |