diff options
-rw-r--r-- | block/cfq-iosched.c | 87 |
1 files changed, 32 insertions, 55 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 4a0397022f5b..a8437042e28a 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -45,9 +45,6 @@ static int cfq_slice_idle = HZ / 125; | |||
45 | */ | 45 | */ |
46 | #define CFQ_QHASH_SHIFT 6 | 46 | #define CFQ_QHASH_SHIFT 6 |
47 | #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) | 47 | #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) |
48 | #define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash) | ||
49 | |||
50 | #define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) | ||
51 | 48 | ||
52 | #define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) | 49 | #define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) |
53 | #define RQ_CFQQ(rq) ((rq)->elevator_private2) | 50 | #define RQ_CFQQ(rq) ((rq)->elevator_private2) |
@@ -91,7 +88,6 @@ struct cfq_data { | |||
91 | * rr list of queues with requests and the count of them | 88 | * rr list of queues with requests and the count of them |
92 | */ | 89 | */ |
93 | struct cfq_rb_root service_tree; | 90 | struct cfq_rb_root service_tree; |
94 | struct list_head cur_rr; | ||
95 | unsigned int busy_queues; | 91 | unsigned int busy_queues; |
96 | 92 | ||
97 | /* | 93 | /* |
@@ -146,8 +142,6 @@ struct cfq_queue { | |||
146 | struct hlist_node cfq_hash; | 142 | struct hlist_node cfq_hash; |
147 | /* hash key */ | 143 | /* hash key */ |
148 | unsigned int key; | 144 | unsigned int key; |
149 | /* member of the rr/busy/cur/idle cfqd list */ | ||
150 | struct list_head cfq_list; | ||
151 | /* service_tree member */ | 145 | /* service_tree member */ |
152 | struct rb_node rb_node; | 146 | struct rb_node rb_node; |
153 | /* service_tree key */ | 147 | /* service_tree key */ |
@@ -452,16 +446,19 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd, | |||
452 | * we will service the queues. | 446 | * we will service the queues. |
453 | */ | 447 | */ |
454 | static void cfq_service_tree_add(struct cfq_data *cfqd, | 448 | static void cfq_service_tree_add(struct cfq_data *cfqd, |
455 | struct cfq_queue *cfqq) | 449 | struct cfq_queue *cfqq, int add_front) |
456 | { | 450 | { |
457 | struct rb_node **p = &cfqd->service_tree.rb.rb_node; | 451 | struct rb_node **p = &cfqd->service_tree.rb.rb_node; |
458 | struct rb_node *parent = NULL; | 452 | struct rb_node *parent = NULL; |
459 | unsigned long rb_key; | 453 | unsigned long rb_key; |
460 | int left; | 454 | int left; |
461 | 455 | ||
462 | rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; | 456 | if (!add_front) { |
463 | rb_key += cfqq->slice_resid; | 457 | rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; |
464 | cfqq->slice_resid = 0; | 458 | rb_key += cfqq->slice_resid; |
459 | cfqq->slice_resid = 0; | ||
460 | } else | ||
461 | rb_key = 0; | ||
465 | 462 | ||
466 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) { | 463 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) { |
467 | /* | 464 | /* |
@@ -516,13 +513,13 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, | |||
516 | /* | 513 | /* |
517 | * Update cfqq's position in the service tree. | 514 | * Update cfqq's position in the service tree. |
518 | */ | 515 | */ |
519 | static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) | 516 | static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
520 | { | 517 | { |
521 | /* | 518 | /* |
522 | * Resorting requires the cfqq to be on the RR list already. | 519 | * Resorting requires the cfqq to be on the RR list already. |
523 | */ | 520 | */ |
524 | if (cfq_cfqq_on_rr(cfqq)) | 521 | if (cfq_cfqq_on_rr(cfqq)) |
525 | cfq_service_tree_add(cfqq->cfqd, cfqq); | 522 | cfq_service_tree_add(cfqd, cfqq, 0); |
526 | } | 523 | } |
527 | 524 | ||
528 | /* | 525 | /* |
@@ -536,7 +533,7 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
536 | cfq_mark_cfqq_on_rr(cfqq); | 533 | cfq_mark_cfqq_on_rr(cfqq); |
537 | cfqd->busy_queues++; | 534 | cfqd->busy_queues++; |
538 | 535 | ||
539 | cfq_resort_rr_list(cfqq, 0); | 536 | cfq_resort_rr_list(cfqd, cfqq); |
540 | } | 537 | } |
541 | 538 | ||
542 | /* | 539 | /* |
@@ -548,7 +545,6 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
548 | { | 545 | { |
549 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); | 546 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); |
550 | cfq_clear_cfqq_on_rr(cfqq); | 547 | cfq_clear_cfqq_on_rr(cfqq); |
551 | list_del_init(&cfqq->cfq_list); | ||
552 | 548 | ||
553 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) | 549 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) |
554 | cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); | 550 | cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); |
@@ -771,7 +767,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
771 | if (timed_out && !cfq_cfqq_slice_new(cfqq)) | 767 | if (timed_out && !cfq_cfqq_slice_new(cfqq)) |
772 | cfqq->slice_resid = cfqq->slice_end - jiffies; | 768 | cfqq->slice_resid = cfqq->slice_end - jiffies; |
773 | 769 | ||
774 | cfq_resort_rr_list(cfqq, preempted); | 770 | cfq_resort_rr_list(cfqd, cfqq); |
775 | 771 | ||
776 | if (cfqq == cfqd->active_queue) | 772 | if (cfqq == cfqd->active_queue) |
777 | cfqd->active_queue = NULL; | 773 | cfqd->active_queue = NULL; |
@@ -799,31 +795,28 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted, | |||
799 | */ | 795 | */ |
800 | static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) | 796 | static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) |
801 | { | 797 | { |
802 | struct cfq_queue *cfqq = NULL; | 798 | struct cfq_queue *cfqq; |
799 | struct rb_node *n; | ||
803 | 800 | ||
804 | if (!list_empty(&cfqd->cur_rr)) { | 801 | if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) |
805 | /* | 802 | return NULL; |
806 | * if current list is non-empty, grab first entry. | ||
807 | */ | ||
808 | cfqq = list_entry_cfqq(cfqd->cur_rr.next); | ||
809 | } else if (!RB_EMPTY_ROOT(&cfqd->service_tree.rb)) { | ||
810 | struct rb_node *n = cfq_rb_first(&cfqd->service_tree); | ||
811 | 803 | ||
812 | cfqq = rb_entry(n, struct cfq_queue, rb_node); | 804 | n = cfq_rb_first(&cfqd->service_tree); |
813 | if (cfq_class_idle(cfqq)) { | 805 | cfqq = rb_entry(n, struct cfq_queue, rb_node); |
814 | unsigned long end; | ||
815 | 806 | ||
816 | /* | 807 | if (cfq_class_idle(cfqq)) { |
817 | * if we have idle queues and no rt or be queues had | 808 | unsigned long end; |
818 | * pending requests, either allow immediate service if | 809 | |
819 | * the grace period has passed or arm the idle grace | 810 | /* |
820 | * timer | 811 | * if we have idle queues and no rt or be queues had |
821 | */ | 812 | * pending requests, either allow immediate service if |
822 | end = cfqd->last_end_request + CFQ_IDLE_GRACE; | 813 | * the grace period has passed or arm the idle grace |
823 | if (time_before(jiffies, end)) { | 814 | * timer |
824 | mod_timer(&cfqd->idle_class_timer, end); | 815 | */ |
825 | cfqq = NULL; | 816 | end = cfqd->last_end_request + CFQ_IDLE_GRACE; |
826 | } | 817 | if (time_before(jiffies, end)) { |
818 | mod_timer(&cfqd->idle_class_timer, end); | ||
819 | cfqq = NULL; | ||
827 | } | 820 | } |
828 | } | 821 | } |
829 | 822 | ||
@@ -1075,18 +1068,6 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) | |||
1075 | return dispatched; | 1068 | return dispatched; |
1076 | } | 1069 | } |
1077 | 1070 | ||
1078 | static int cfq_forced_dispatch_cfqqs(struct list_head *list) | ||
1079 | { | ||
1080 | struct cfq_queue *cfqq, *next; | ||
1081 | int dispatched; | ||
1082 | |||
1083 | dispatched = 0; | ||
1084 | list_for_each_entry_safe(cfqq, next, list, cfq_list) | ||
1085 | dispatched += __cfq_forced_dispatch_cfqq(cfqq); | ||
1086 | |||
1087 | return dispatched; | ||
1088 | } | ||
1089 | |||
1090 | /* | 1071 | /* |
1091 | * Drain our current requests. Used for barriers and when switching | 1072 | * Drain our current requests. Used for barriers and when switching |
1092 | * io schedulers on-the-fly. | 1073 | * io schedulers on-the-fly. |
@@ -1102,8 +1083,6 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) | |||
1102 | dispatched += __cfq_forced_dispatch_cfqq(cfqq); | 1083 | dispatched += __cfq_forced_dispatch_cfqq(cfqq); |
1103 | } | 1084 | } |
1104 | 1085 | ||
1105 | dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr); | ||
1106 | |||
1107 | cfq_slice_expired(cfqd, 0, 0); | 1086 | cfq_slice_expired(cfqd, 0, 0); |
1108 | 1087 | ||
1109 | BUG_ON(cfqd->busy_queues); | 1088 | BUG_ON(cfqd->busy_queues); |
@@ -1433,7 +1412,6 @@ retry: | |||
1433 | memset(cfqq, 0, sizeof(*cfqq)); | 1412 | memset(cfqq, 0, sizeof(*cfqq)); |
1434 | 1413 | ||
1435 | INIT_HLIST_NODE(&cfqq->cfq_hash); | 1414 | INIT_HLIST_NODE(&cfqq->cfq_hash); |
1436 | INIT_LIST_HEAD(&cfqq->cfq_list); | ||
1437 | RB_CLEAR_NODE(&cfqq->rb_node); | 1415 | RB_CLEAR_NODE(&cfqq->rb_node); |
1438 | INIT_LIST_HEAD(&cfqq->fifo); | 1416 | INIT_LIST_HEAD(&cfqq->fifo); |
1439 | 1417 | ||
@@ -1712,8 +1690,8 @@ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
1712 | * so we know that it will be selected next. | 1690 | * so we know that it will be selected next. |
1713 | */ | 1691 | */ |
1714 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); | 1692 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); |
1715 | list_del_init(&cfqq->cfq_list); | 1693 | |
1716 | list_add(&cfqq->cfq_list, &cfqd->cur_rr); | 1694 | cfq_service_tree_add(cfqd, cfqq, 1); |
1717 | 1695 | ||
1718 | cfqq->slice_end = 0; | 1696 | cfqq->slice_end = 0; |
1719 | cfq_mark_cfqq_slice_new(cfqq); | 1697 | cfq_mark_cfqq_slice_new(cfqq); |
@@ -2077,7 +2055,6 @@ static void *cfq_init_queue(request_queue_t *q) | |||
2077 | memset(cfqd, 0, sizeof(*cfqd)); | 2055 | memset(cfqd, 0, sizeof(*cfqd)); |
2078 | 2056 | ||
2079 | cfqd->service_tree = CFQ_RB_ROOT; | 2057 | cfqd->service_tree = CFQ_RB_ROOT; |
2080 | INIT_LIST_HEAD(&cfqd->cur_rr); | ||
2081 | INIT_LIST_HEAD(&cfqd->cic_list); | 2058 | INIT_LIST_HEAD(&cfqd->cic_list); |
2082 | 2059 | ||
2083 | cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node); | 2060 | cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node); |