diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/cfq-iosched.c | 117 |
1 files changed, 34 insertions, 83 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 8830893e062f..8fe1a0ddb511 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -26,9 +26,9 @@ static const int cfq_slice_async_rq = 2; | |||
26 | static int cfq_slice_idle = HZ / 125; | 26 | static int cfq_slice_idle = HZ / 125; |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * grace period before allowing idle class to get disk access | 29 | * offset from end of service tree |
30 | */ | 30 | */ |
31 | #define CFQ_IDLE_GRACE (HZ / 10) | 31 | #define CFQ_IDLE_DELAY (HZ / 5) |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * below this threshold, we consider thinktime immediate | 34 | * below this threshold, we consider thinktime immediate |
@@ -98,8 +98,6 @@ struct cfq_data { | |||
98 | struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; | 98 | struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; |
99 | struct cfq_queue *async_idle_cfqq; | 99 | struct cfq_queue *async_idle_cfqq; |
100 | 100 | ||
101 | struct timer_list idle_class_timer; | ||
102 | |||
103 | sector_t last_position; | 101 | sector_t last_position; |
104 | unsigned long last_end_request; | 102 | unsigned long last_end_request; |
105 | 103 | ||
@@ -384,12 +382,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2) | |||
384 | /* | 382 | /* |
385 | * The below is leftmost cache rbtree addon | 383 | * The below is leftmost cache rbtree addon |
386 | */ | 384 | */ |
387 | static struct rb_node *cfq_rb_first(struct cfq_rb_root *root) | 385 | static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root) |
388 | { | 386 | { |
389 | if (!root->left) | 387 | if (!root->left) |
390 | root->left = rb_first(&root->rb); | 388 | root->left = rb_first(&root->rb); |
391 | 389 | ||
392 | return root->left; | 390 | if (root->left) |
391 | return rb_entry(root->left, struct cfq_queue, rb_node); | ||
392 | |||
393 | return NULL; | ||
393 | } | 394 | } |
394 | 395 | ||
395 | static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root) | 396 | static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root) |
@@ -446,12 +447,20 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd, | |||
446 | static void cfq_service_tree_add(struct cfq_data *cfqd, | 447 | static void cfq_service_tree_add(struct cfq_data *cfqd, |
447 | struct cfq_queue *cfqq, int add_front) | 448 | struct cfq_queue *cfqq, int add_front) |
448 | { | 449 | { |
449 | struct rb_node **p = &cfqd->service_tree.rb.rb_node; | 450 | struct rb_node **p, *parent; |
450 | struct rb_node *parent = NULL; | 451 | struct cfq_queue *__cfqq; |
451 | unsigned long rb_key; | 452 | unsigned long rb_key; |
452 | int left; | 453 | int left; |
453 | 454 | ||
454 | if (!add_front) { | 455 | if (cfq_class_idle(cfqq)) { |
456 | rb_key = CFQ_IDLE_DELAY; | ||
457 | parent = rb_last(&cfqd->service_tree.rb); | ||
458 | if (parent && parent != &cfqq->rb_node) { | ||
459 | __cfqq = rb_entry(parent, struct cfq_queue, rb_node); | ||
460 | rb_key += __cfqq->rb_key; | ||
461 | } else | ||
462 | rb_key += jiffies; | ||
463 | } else if (!add_front) { | ||
455 | rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; | 464 | rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; |
456 | rb_key += cfqq->slice_resid; | 465 | rb_key += cfqq->slice_resid; |
457 | cfqq->slice_resid = 0; | 466 | cfqq->slice_resid = 0; |
@@ -469,8 +478,9 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, | |||
469 | } | 478 | } |
470 | 479 | ||
471 | left = 1; | 480 | left = 1; |
481 | parent = NULL; | ||
482 | p = &cfqd->service_tree.rb.rb_node; | ||
472 | while (*p) { | 483 | while (*p) { |
473 | struct cfq_queue *__cfqq; | ||
474 | struct rb_node **n; | 484 | struct rb_node **n; |
475 | 485 | ||
476 | parent = *p; | 486 | parent = *p; |
@@ -736,11 +746,6 @@ static inline void | |||
736 | __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 746 | __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
737 | { | 747 | { |
738 | if (cfqq) { | 748 | if (cfqq) { |
739 | /* | ||
740 | * stop potential idle class queues waiting service | ||
741 | */ | ||
742 | del_timer(&cfqd->idle_class_timer); | ||
743 | |||
744 | cfqq->slice_end = 0; | 749 | cfqq->slice_end = 0; |
745 | cfq_clear_cfqq_must_alloc_slice(cfqq); | 750 | cfq_clear_cfqq_must_alloc_slice(cfqq); |
746 | cfq_clear_cfqq_fifo_expire(cfqq); | 751 | cfq_clear_cfqq_fifo_expire(cfqq); |
@@ -789,47 +794,16 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out) | |||
789 | __cfq_slice_expired(cfqd, cfqq, timed_out); | 794 | __cfq_slice_expired(cfqd, cfqq, timed_out); |
790 | } | 795 | } |
791 | 796 | ||
792 | static int start_idle_class_timer(struct cfq_data *cfqd) | ||
793 | { | ||
794 | unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE; | ||
795 | unsigned long now = jiffies; | ||
796 | |||
797 | if (time_before(now, end) && | ||
798 | time_after_eq(now, cfqd->last_end_request)) { | ||
799 | mod_timer(&cfqd->idle_class_timer, end); | ||
800 | return 1; | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | /* | 797 | /* |
807 | * Get next queue for service. Unless we have a queue preemption, | 798 | * Get next queue for service. Unless we have a queue preemption, |
808 | * we'll simply select the first cfqq in the service tree. | 799 | * we'll simply select the first cfqq in the service tree. |
809 | */ | 800 | */ |
810 | static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) | 801 | static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) |
811 | { | 802 | { |
812 | struct cfq_queue *cfqq; | ||
813 | struct rb_node *n; | ||
814 | |||
815 | if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) | 803 | if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) |
816 | return NULL; | 804 | return NULL; |
817 | 805 | ||
818 | n = cfq_rb_first(&cfqd->service_tree); | 806 | return cfq_rb_first(&cfqd->service_tree); |
819 | cfqq = rb_entry(n, struct cfq_queue, rb_node); | ||
820 | |||
821 | if (cfq_class_idle(cfqq)) { | ||
822 | /* | ||
823 | * if we have idle queues and no rt or be queues had | ||
824 | * pending requests, either allow immediate service if | ||
825 | * the grace period has passed or arm the idle grace | ||
826 | * timer | ||
827 | */ | ||
828 | if (start_idle_class_timer(cfqd)) | ||
829 | cfqq = NULL; | ||
830 | } | ||
831 | |||
832 | return cfqq; | ||
833 | } | 807 | } |
834 | 808 | ||
835 | /* | 809 | /* |
@@ -1087,14 +1061,11 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) | |||
1087 | */ | 1061 | */ |
1088 | static int cfq_forced_dispatch(struct cfq_data *cfqd) | 1062 | static int cfq_forced_dispatch(struct cfq_data *cfqd) |
1089 | { | 1063 | { |
1064 | struct cfq_queue *cfqq; | ||
1090 | int dispatched = 0; | 1065 | int dispatched = 0; |
1091 | struct rb_node *n; | ||
1092 | |||
1093 | while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) { | ||
1094 | struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node); | ||
1095 | 1066 | ||
1067 | while ((cfqq = cfq_rb_first(&cfqd->service_tree)) != NULL) | ||
1096 | dispatched += __cfq_forced_dispatch_cfqq(cfqq); | 1068 | dispatched += __cfq_forced_dispatch_cfqq(cfqq); |
1097 | } | ||
1098 | 1069 | ||
1099 | cfq_slice_expired(cfqd, 0); | 1070 | cfq_slice_expired(cfqd, 0); |
1100 | 1071 | ||
@@ -1437,15 +1408,16 @@ retry: | |||
1437 | atomic_set(&cfqq->ref, 0); | 1408 | atomic_set(&cfqq->ref, 0); |
1438 | cfqq->cfqd = cfqd; | 1409 | cfqq->cfqd = cfqd; |
1439 | 1410 | ||
1440 | if (is_sync) { | ||
1441 | cfq_mark_cfqq_idle_window(cfqq); | ||
1442 | cfq_mark_cfqq_sync(cfqq); | ||
1443 | } | ||
1444 | |||
1445 | cfq_mark_cfqq_prio_changed(cfqq); | 1411 | cfq_mark_cfqq_prio_changed(cfqq); |
1446 | cfq_mark_cfqq_queue_new(cfqq); | 1412 | cfq_mark_cfqq_queue_new(cfqq); |
1447 | 1413 | ||
1448 | cfq_init_prio_data(cfqq, ioc); | 1414 | cfq_init_prio_data(cfqq, ioc); |
1415 | |||
1416 | if (is_sync) { | ||
1417 | if (!cfq_class_idle(cfqq)) | ||
1418 | cfq_mark_cfqq_idle_window(cfqq); | ||
1419 | cfq_mark_cfqq_sync(cfqq); | ||
1420 | } | ||
1449 | } | 1421 | } |
1450 | 1422 | ||
1451 | if (new_cfqq) | 1423 | if (new_cfqq) |
@@ -1697,7 +1669,10 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1697 | { | 1669 | { |
1698 | int enable_idle; | 1670 | int enable_idle; |
1699 | 1671 | ||
1700 | if (!cfq_cfqq_sync(cfqq)) | 1672 | /* |
1673 | * Don't idle for async or idle io prio class | ||
1674 | */ | ||
1675 | if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) | ||
1701 | return; | 1676 | return; |
1702 | 1677 | ||
1703 | enable_idle = cfq_cfqq_idle_window(cfqq); | 1678 | enable_idle = cfq_cfqq_idle_window(cfqq); |
@@ -1876,7 +1851,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) | |||
1876 | cfq_set_prio_slice(cfqd, cfqq); | 1851 | cfq_set_prio_slice(cfqd, cfqq); |
1877 | cfq_clear_cfqq_slice_new(cfqq); | 1852 | cfq_clear_cfqq_slice_new(cfqq); |
1878 | } | 1853 | } |
1879 | if (cfq_slice_used(cfqq)) | 1854 | if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq)) |
1880 | cfq_slice_expired(cfqd, 1); | 1855 | cfq_slice_expired(cfqd, 1); |
1881 | else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) | 1856 | else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) |
1882 | cfq_arm_slice_timer(cfqd); | 1857 | cfq_arm_slice_timer(cfqd); |
@@ -2080,29 +2055,9 @@ out_cont: | |||
2080 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); | 2055 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); |
2081 | } | 2056 | } |
2082 | 2057 | ||
2083 | /* | ||
2084 | * Timer running if an idle class queue is waiting for service | ||
2085 | */ | ||
2086 | static void cfq_idle_class_timer(unsigned long data) | ||
2087 | { | ||
2088 | struct cfq_data *cfqd = (struct cfq_data *) data; | ||
2089 | unsigned long flags; | ||
2090 | |||
2091 | spin_lock_irqsave(cfqd->queue->queue_lock, flags); | ||
2092 | |||
2093 | /* | ||
2094 | * race with a non-idle queue, reset timer | ||
2095 | */ | ||
2096 | if (!start_idle_class_timer(cfqd)) | ||
2097 | cfq_schedule_dispatch(cfqd); | ||
2098 | |||
2099 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); | ||
2100 | } | ||
2101 | |||
2102 | static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) | 2058 | static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) |
2103 | { | 2059 | { |
2104 | del_timer_sync(&cfqd->idle_slice_timer); | 2060 | del_timer_sync(&cfqd->idle_slice_timer); |
2105 | del_timer_sync(&cfqd->idle_class_timer); | ||
2106 | kblockd_flush_work(&cfqd->unplug_work); | 2061 | kblockd_flush_work(&cfqd->unplug_work); |
2107 | } | 2062 | } |
2108 | 2063 | ||
@@ -2167,10 +2122,6 @@ static void *cfq_init_queue(struct request_queue *q) | |||
2167 | cfqd->idle_slice_timer.function = cfq_idle_slice_timer; | 2122 | cfqd->idle_slice_timer.function = cfq_idle_slice_timer; |
2168 | cfqd->idle_slice_timer.data = (unsigned long) cfqd; | 2123 | cfqd->idle_slice_timer.data = (unsigned long) cfqd; |
2169 | 2124 | ||
2170 | init_timer(&cfqd->idle_class_timer); | ||
2171 | cfqd->idle_class_timer.function = cfq_idle_class_timer; | ||
2172 | cfqd->idle_class_timer.data = (unsigned long) cfqd; | ||
2173 | |||
2174 | INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); | 2125 | INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); |
2175 | 2126 | ||
2176 | cfqd->last_end_request = jiffies; | 2127 | cfqd->last_end_request = jiffies; |