diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index d01b411c72f0..1e2aff812ee2 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/elevator.h> | 11 | #include <linux/elevator.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/ioprio.h> | 13 | #include <linux/ioprio.h> |
14 | #include <linux/blktrace_api.h> | ||
14 | 15 | ||
15 | /* | 16 | /* |
16 | * tunables | 17 | * tunables |
@@ -41,13 +42,14 @@ static int cfq_slice_idle = HZ / 125; | |||
41 | 42 | ||
42 | #define RQ_CIC(rq) \ | 43 | #define RQ_CIC(rq) \ |
43 | ((struct cfq_io_context *) (rq)->elevator_private) | 44 | ((struct cfq_io_context *) (rq)->elevator_private) |
44 | #define RQ_CFQQ(rq) ((rq)->elevator_private2) | 45 | #define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private2) |
45 | 46 | ||
46 | static struct kmem_cache *cfq_pool; | 47 | static struct kmem_cache *cfq_pool; |
47 | static struct kmem_cache *cfq_ioc_pool; | 48 | static struct kmem_cache *cfq_ioc_pool; |
48 | 49 | ||
49 | static DEFINE_PER_CPU(unsigned long, ioc_count); | 50 | static DEFINE_PER_CPU(unsigned long, ioc_count); |
50 | static struct completion *ioc_gone; | 51 | static struct completion *ioc_gone; |
52 | static DEFINE_SPINLOCK(ioc_gone_lock); | ||
51 | 53 | ||
52 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR | 54 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR |
53 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) | 55 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) |
@@ -155,6 +157,7 @@ struct cfq_queue { | |||
155 | unsigned short ioprio, org_ioprio; | 157 | unsigned short ioprio, org_ioprio; |
156 | unsigned short ioprio_class, org_ioprio_class; | 158 | unsigned short ioprio_class, org_ioprio_class; |
157 | 159 | ||
160 | pid_t pid; | ||
158 | }; | 161 | }; |
159 | 162 | ||
160 | enum cfqq_state_flags { | 163 | enum cfqq_state_flags { |
@@ -198,6 +201,11 @@ CFQ_CFQQ_FNS(slice_new); | |||
198 | CFQ_CFQQ_FNS(sync); | 201 | CFQ_CFQQ_FNS(sync); |
199 | #undef CFQ_CFQQ_FNS | 202 | #undef CFQ_CFQQ_FNS |
200 | 203 | ||
204 | #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ | ||
205 | blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) | ||
206 | #define cfq_log(cfqd, fmt, args...) \ | ||
207 | blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) | ||
208 | |||
201 | static void cfq_dispatch_insert(struct request_queue *, struct request *); | 209 | static void cfq_dispatch_insert(struct request_queue *, struct request *); |
202 | static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, | 210 | static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, |
203 | struct io_context *, gfp_t); | 211 | struct io_context *, gfp_t); |
@@ -234,8 +242,10 @@ static inline int cfq_bio_sync(struct bio *bio) | |||
234 | */ | 242 | */ |
235 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) | 243 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) |
236 | { | 244 | { |
237 | if (cfqd->busy_queues) | 245 | if (cfqd->busy_queues) { |
246 | cfq_log(cfqd, "schedule dispatch"); | ||
238 | kblockd_schedule_work(&cfqd->unplug_work); | 247 | kblockd_schedule_work(&cfqd->unplug_work); |
248 | } | ||
239 | } | 249 | } |
240 | 250 | ||
241 | static int cfq_queue_empty(struct request_queue *q) | 251 | static int cfq_queue_empty(struct request_queue *q) |
@@ -270,6 +280,7 @@ static inline void | |||
270 | cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 280 | cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
271 | { | 281 | { |
272 | cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; | 282 | cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; |
283 | cfq_log_cfqq(cfqd, cfqq, "set_slice=%lu", cfqq->slice_end - jiffies); | ||
273 | } | 284 | } |
274 | 285 | ||
275 | /* | 286 | /* |
@@ -539,6 +550,7 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
539 | */ | 550 | */ |
540 | static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 551 | static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
541 | { | 552 | { |
553 | cfq_log_cfqq(cfqd, cfqq, "add_to_rr"); | ||
542 | BUG_ON(cfq_cfqq_on_rr(cfqq)); | 554 | BUG_ON(cfq_cfqq_on_rr(cfqq)); |
543 | cfq_mark_cfqq_on_rr(cfqq); | 555 | cfq_mark_cfqq_on_rr(cfqq); |
544 | cfqd->busy_queues++; | 556 | cfqd->busy_queues++; |
@@ -552,6 +564,7 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
552 | */ | 564 | */ |
553 | static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 565 | static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
554 | { | 566 | { |
567 | cfq_log_cfqq(cfqd, cfqq, "del_from_rr"); | ||
555 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); | 568 | BUG_ON(!cfq_cfqq_on_rr(cfqq)); |
556 | cfq_clear_cfqq_on_rr(cfqq); | 569 | cfq_clear_cfqq_on_rr(cfqq); |
557 | 570 | ||
@@ -638,6 +651,8 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq) | |||
638 | struct cfq_data *cfqd = q->elevator->elevator_data; | 651 | struct cfq_data *cfqd = q->elevator->elevator_data; |
639 | 652 | ||
640 | cfqd->rq_in_driver++; | 653 | cfqd->rq_in_driver++; |
654 | cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", | ||
655 | cfqd->rq_in_driver); | ||
641 | 656 | ||
642 | /* | 657 | /* |
643 | * If the depth is larger 1, it really could be queueing. But lets | 658 | * If the depth is larger 1, it really could be queueing. But lets |
@@ -657,6 +672,8 @@ static void cfq_deactivate_request(struct request_queue *q, struct request *rq) | |||
657 | 672 | ||
658 | WARN_ON(!cfqd->rq_in_driver); | 673 | WARN_ON(!cfqd->rq_in_driver); |
659 | cfqd->rq_in_driver--; | 674 | cfqd->rq_in_driver--; |
675 | cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d", | ||
676 | cfqd->rq_in_driver); | ||
660 | } | 677 | } |
661 | 678 | ||
662 | static void cfq_remove_request(struct request *rq) | 679 | static void cfq_remove_request(struct request *rq) |
@@ -746,6 +763,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, | |||
746 | struct cfq_queue *cfqq) | 763 | struct cfq_queue *cfqq) |
747 | { | 764 | { |
748 | if (cfqq) { | 765 | if (cfqq) { |
766 | cfq_log_cfqq(cfqd, cfqq, "set_active"); | ||
749 | cfqq->slice_end = 0; | 767 | cfqq->slice_end = 0; |
750 | cfq_clear_cfqq_must_alloc_slice(cfqq); | 768 | cfq_clear_cfqq_must_alloc_slice(cfqq); |
751 | cfq_clear_cfqq_fifo_expire(cfqq); | 769 | cfq_clear_cfqq_fifo_expire(cfqq); |
@@ -763,6 +781,8 @@ static void | |||
763 | __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, | 781 | __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, |
764 | int timed_out) | 782 | int timed_out) |
765 | { | 783 | { |
784 | cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out); | ||
785 | |||
766 | if (cfq_cfqq_wait_request(cfqq)) | 786 | if (cfq_cfqq_wait_request(cfqq)) |
767 | del_timer(&cfqd->idle_slice_timer); | 787 | del_timer(&cfqd->idle_slice_timer); |
768 | 788 | ||
@@ -772,8 +792,10 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
772 | /* | 792 | /* |
773 | * store what was left of this slice, if the queue idled/timed out | 793 | * store what was left of this slice, if the queue idled/timed out |
774 | */ | 794 | */ |
775 | if (timed_out && !cfq_cfqq_slice_new(cfqq)) | 795 | if (timed_out && !cfq_cfqq_slice_new(cfqq)) { |
776 | cfqq->slice_resid = cfqq->slice_end - jiffies; | 796 | cfqq->slice_resid = cfqq->slice_end - jiffies; |
797 | cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); | ||
798 | } | ||
777 | 799 | ||
778 | cfq_resort_rr_list(cfqd, cfqq); | 800 | cfq_resort_rr_list(cfqd, cfqq); |
779 | 801 | ||
@@ -866,6 +888,12 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) | |||
866 | return; | 888 | return; |
867 | 889 | ||
868 | /* | 890 | /* |
891 | * still requests with the driver, don't idle | ||
892 | */ | ||
893 | if (cfqd->rq_in_driver) | ||
894 | return; | ||
895 | |||
896 | /* | ||
869 | * task has exited, don't wait | 897 | * task has exited, don't wait |
870 | */ | 898 | */ |
871 | cic = cfqd->active_cic; | 899 | cic = cfqd->active_cic; |
@@ -892,6 +920,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) | |||
892 | sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT)); | 920 | sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT)); |
893 | 921 | ||
894 | mod_timer(&cfqd->idle_slice_timer, jiffies + sl); | 922 | mod_timer(&cfqd->idle_slice_timer, jiffies + sl); |
923 | cfq_log(cfqd, "arm_idle: %lu", sl); | ||
895 | } | 924 | } |
896 | 925 | ||
897 | /* | 926 | /* |
@@ -902,6 +931,8 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) | |||
902 | struct cfq_data *cfqd = q->elevator->elevator_data; | 931 | struct cfq_data *cfqd = q->elevator->elevator_data; |
903 | struct cfq_queue *cfqq = RQ_CFQQ(rq); | 932 | struct cfq_queue *cfqq = RQ_CFQQ(rq); |
904 | 933 | ||
934 | cfq_log_cfqq(cfqd, cfqq, "dispatch_insert"); | ||
935 | |||
905 | cfq_remove_request(rq); | 936 | cfq_remove_request(rq); |
906 | cfqq->dispatched++; | 937 | cfqq->dispatched++; |
907 | elv_dispatch_sort(q, rq); | 938 | elv_dispatch_sort(q, rq); |
@@ -931,8 +962,9 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq) | |||
931 | rq = rq_entry_fifo(cfqq->fifo.next); | 962 | rq = rq_entry_fifo(cfqq->fifo.next); |
932 | 963 | ||
933 | if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) | 964 | if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) |
934 | return NULL; | 965 | rq = NULL; |
935 | 966 | ||
967 | cfq_log_cfqq(cfqd, cfqq, "fifo=%p", rq); | ||
936 | return rq; | 968 | return rq; |
937 | } | 969 | } |
938 | 970 | ||
@@ -1072,6 +1104,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) | |||
1072 | 1104 | ||
1073 | BUG_ON(cfqd->busy_queues); | 1105 | BUG_ON(cfqd->busy_queues); |
1074 | 1106 | ||
1107 | cfq_log(cfqd, "forced_dispatch=%d\n", dispatched); | ||
1075 | return dispatched; | 1108 | return dispatched; |
1076 | } | 1109 | } |
1077 | 1110 | ||
@@ -1112,6 +1145,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) | |||
1112 | dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); | 1145 | dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); |
1113 | } | 1146 | } |
1114 | 1147 | ||
1148 | cfq_log(cfqd, "dispatched=%d", dispatched); | ||
1115 | return dispatched; | 1149 | return dispatched; |
1116 | } | 1150 | } |
1117 | 1151 | ||
@@ -1130,6 +1164,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
1130 | if (!atomic_dec_and_test(&cfqq->ref)) | 1164 | if (!atomic_dec_and_test(&cfqq->ref)) |
1131 | return; | 1165 | return; |
1132 | 1166 | ||
1167 | cfq_log_cfqq(cfqd, cfqq, "put_queue"); | ||
1133 | BUG_ON(rb_first(&cfqq->sort_list)); | 1168 | BUG_ON(rb_first(&cfqq->sort_list)); |
1134 | BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); | 1169 | BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); |
1135 | BUG_ON(cfq_cfqq_on_rr(cfqq)); | 1170 | BUG_ON(cfq_cfqq_on_rr(cfqq)); |
@@ -1177,8 +1212,19 @@ static void cfq_cic_free_rcu(struct rcu_head *head) | |||
1177 | kmem_cache_free(cfq_ioc_pool, cic); | 1212 | kmem_cache_free(cfq_ioc_pool, cic); |
1178 | elv_ioc_count_dec(ioc_count); | 1213 | elv_ioc_count_dec(ioc_count); |
1179 | 1214 | ||
1180 | if (ioc_gone && !elv_ioc_count_read(ioc_count)) | 1215 | if (ioc_gone) { |
1181 | complete(ioc_gone); | 1216 | /* |
1217 | * CFQ scheduler is exiting, grab exit lock and check | ||
1218 | * the pending io context count. If it hits zero, | ||
1219 | * complete ioc_gone and set it back to NULL | ||
1220 | */ | ||
1221 | spin_lock(&ioc_gone_lock); | ||
1222 | if (ioc_gone && !elv_ioc_count_read(ioc_count)) { | ||
1223 | complete(ioc_gone); | ||
1224 | ioc_gone = NULL; | ||
1225 | } | ||
1226 | spin_unlock(&ioc_gone_lock); | ||
1227 | } | ||
1182 | } | 1228 | } |
1183 | 1229 | ||
1184 | static void cfq_cic_free(struct cfq_io_context *cic) | 1230 | static void cfq_cic_free(struct cfq_io_context *cic) |
@@ -1427,6 +1473,8 @@ retry: | |||
1427 | cfq_mark_cfqq_idle_window(cfqq); | 1473 | cfq_mark_cfqq_idle_window(cfqq); |
1428 | cfq_mark_cfqq_sync(cfqq); | 1474 | cfq_mark_cfqq_sync(cfqq); |
1429 | } | 1475 | } |
1476 | cfqq->pid = current->pid; | ||
1477 | cfq_log_cfqq(cfqd, cfqq, "alloced"); | ||
1430 | } | 1478 | } |
1431 | 1479 | ||
1432 | if (new_cfqq) | 1480 | if (new_cfqq) |
@@ -1675,7 +1723,7 @@ static void | |||
1675 | cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, | 1723 | cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, |
1676 | struct cfq_io_context *cic) | 1724 | struct cfq_io_context *cic) |
1677 | { | 1725 | { |
1678 | int enable_idle; | 1726 | int old_idle, enable_idle; |
1679 | 1727 | ||
1680 | /* | 1728 | /* |
1681 | * Don't idle for async or idle io prio class | 1729 | * Don't idle for async or idle io prio class |
@@ -1683,7 +1731,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1683 | if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) | 1731 | if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) |
1684 | return; | 1732 | return; |
1685 | 1733 | ||
1686 | enable_idle = cfq_cfqq_idle_window(cfqq); | 1734 | enable_idle = old_idle = cfq_cfqq_idle_window(cfqq); |
1687 | 1735 | ||
1688 | if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle || | 1736 | if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle || |
1689 | (cfqd->hw_tag && CIC_SEEKY(cic))) | 1737 | (cfqd->hw_tag && CIC_SEEKY(cic))) |
@@ -1695,10 +1743,13 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1695 | enable_idle = 1; | 1743 | enable_idle = 1; |
1696 | } | 1744 | } |
1697 | 1745 | ||
1698 | if (enable_idle) | 1746 | if (old_idle != enable_idle) { |
1699 | cfq_mark_cfqq_idle_window(cfqq); | 1747 | cfq_log_cfqq(cfqd, cfqq, "idle=%d", enable_idle); |
1700 | else | 1748 | if (enable_idle) |
1701 | cfq_clear_cfqq_idle_window(cfqq); | 1749 | cfq_mark_cfqq_idle_window(cfqq); |
1750 | else | ||
1751 | cfq_clear_cfqq_idle_window(cfqq); | ||
1752 | } | ||
1702 | } | 1753 | } |
1703 | 1754 | ||
1704 | /* | 1755 | /* |
@@ -1757,6 +1808,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, | |||
1757 | */ | 1808 | */ |
1758 | static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 1809 | static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
1759 | { | 1810 | { |
1811 | cfq_log_cfqq(cfqd, cfqq, "preempt"); | ||
1760 | cfq_slice_expired(cfqd, 1); | 1812 | cfq_slice_expired(cfqd, 1); |
1761 | 1813 | ||
1762 | /* | 1814 | /* |
@@ -1818,6 +1870,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) | |||
1818 | struct cfq_data *cfqd = q->elevator->elevator_data; | 1870 | struct cfq_data *cfqd = q->elevator->elevator_data; |
1819 | struct cfq_queue *cfqq = RQ_CFQQ(rq); | 1871 | struct cfq_queue *cfqq = RQ_CFQQ(rq); |
1820 | 1872 | ||
1873 | cfq_log_cfqq(cfqd, cfqq, "insert_request"); | ||
1821 | cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc); | 1874 | cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc); |
1822 | 1875 | ||
1823 | cfq_add_rq_rb(rq); | 1876 | cfq_add_rq_rb(rq); |
@@ -1835,6 +1888,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) | |||
1835 | unsigned long now; | 1888 | unsigned long now; |
1836 | 1889 | ||
1837 | now = jiffies; | 1890 | now = jiffies; |
1891 | cfq_log_cfqq(cfqd, cfqq, "complete"); | ||
1838 | 1892 | ||
1839 | WARN_ON(!cfqd->rq_in_driver); | 1893 | WARN_ON(!cfqd->rq_in_driver); |
1840 | WARN_ON(!cfqq->dispatched); | 1894 | WARN_ON(!cfqq->dispatched); |
@@ -2004,6 +2058,7 @@ queue_fail: | |||
2004 | 2058 | ||
2005 | cfq_schedule_dispatch(cfqd); | 2059 | cfq_schedule_dispatch(cfqd); |
2006 | spin_unlock_irqrestore(q->queue_lock, flags); | 2060 | spin_unlock_irqrestore(q->queue_lock, flags); |
2061 | cfq_log(cfqd, "set_request fail"); | ||
2007 | return 1; | 2062 | return 1; |
2008 | } | 2063 | } |
2009 | 2064 | ||
@@ -2029,6 +2084,8 @@ static void cfq_idle_slice_timer(unsigned long data) | |||
2029 | unsigned long flags; | 2084 | unsigned long flags; |
2030 | int timed_out = 1; | 2085 | int timed_out = 1; |
2031 | 2086 | ||
2087 | cfq_log(cfqd, "idle timer fired"); | ||
2088 | |||
2032 | spin_lock_irqsave(cfqd->queue->queue_lock, flags); | 2089 | spin_lock_irqsave(cfqd->queue->queue_lock, flags); |
2033 | 2090 | ||
2034 | cfqq = cfqd->active_queue; | 2091 | cfqq = cfqd->active_queue; |
@@ -2317,7 +2374,7 @@ static void __exit cfq_exit(void) | |||
2317 | * pending RCU callbacks | 2374 | * pending RCU callbacks |
2318 | */ | 2375 | */ |
2319 | if (elv_ioc_count_read(ioc_count)) | 2376 | if (elv_ioc_count_read(ioc_count)) |
2320 | wait_for_completion(ioc_gone); | 2377 | wait_for_completion(&all_gone); |
2321 | cfq_slab_kill(); | 2378 | cfq_slab_kill(); |
2322 | } | 2379 | } |
2323 | 2380 | ||