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, |
