aboutsummaryrefslogtreecommitdiffstats
path: root/block/cfq-iosched.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r--block/cfq-iosched.c124
1 files changed, 43 insertions, 81 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index e2f80463ed0d..023f4e69a337 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -42,16 +42,13 @@ static const int cfq_hist_divisor = 4;
42 */ 42 */
43#define CFQ_MIN_TT (2) 43#define CFQ_MIN_TT (2)
44 44
45/*
46 * Allow merged cfqqs to perform this amount of seeky I/O before
47 * deciding to break the queues up again.
48 */
49#define CFQQ_COOP_TOUT (HZ)
50
51#define CFQ_SLICE_SCALE (5) 45#define CFQ_SLICE_SCALE (5)
52#define CFQ_HW_QUEUE_MIN (5) 46#define CFQ_HW_QUEUE_MIN (5)
53#define CFQ_SERVICE_SHIFT 12 47#define CFQ_SERVICE_SHIFT 12
54 48
49#define CFQQ_SEEK_THR 8 * 1024
50#define CFQQ_SEEKY(cfqq) ((cfqq)->seek_mean > CFQQ_SEEK_THR)
51
55#define RQ_CIC(rq) \ 52#define RQ_CIC(rq) \
56 ((struct cfq_io_context *) (rq)->elevator_private) 53 ((struct cfq_io_context *) (rq)->elevator_private)
57#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private2) 54#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private2)
@@ -137,7 +134,6 @@ struct cfq_queue {
137 u64 seek_total; 134 u64 seek_total;
138 sector_t seek_mean; 135 sector_t seek_mean;
139 sector_t last_request_pos; 136 sector_t last_request_pos;
140 unsigned long seeky_start;
141 137
142 pid_t pid; 138 pid_t pid;
143 139
@@ -208,8 +204,6 @@ struct cfq_data {
208 /* Root service tree for cfq_groups */ 204 /* Root service tree for cfq_groups */
209 struct cfq_rb_root grp_service_tree; 205 struct cfq_rb_root grp_service_tree;
210 struct cfq_group root_group; 206 struct cfq_group root_group;
211 /* Number of active cfq groups on group service tree */
212 int nr_groups;
213 207
214 /* 208 /*
215 * The priority currently being served 209 * The priority currently being served
@@ -294,8 +288,7 @@ static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd);
294 288
295static struct cfq_rb_root *service_tree_for(struct cfq_group *cfqg, 289static struct cfq_rb_root *service_tree_for(struct cfq_group *cfqg,
296 enum wl_prio_t prio, 290 enum wl_prio_t prio,
297 enum wl_type_t type, 291 enum wl_type_t type)
298 struct cfq_data *cfqd)
299{ 292{
300 if (!cfqg) 293 if (!cfqg)
301 return NULL; 294 return NULL;
@@ -317,6 +310,7 @@ enum cfqq_state_flags {
317 CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ 310 CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */
318 CFQ_CFQQ_FLAG_sync, /* synchronous queue */ 311 CFQ_CFQQ_FLAG_sync, /* synchronous queue */
319 CFQ_CFQQ_FLAG_coop, /* cfqq is shared */ 312 CFQ_CFQQ_FLAG_coop, /* cfqq is shared */
313 CFQ_CFQQ_FLAG_split_coop, /* shared cfqq will be splitted */
320 CFQ_CFQQ_FLAG_deep, /* sync cfqq experienced large depth */ 314 CFQ_CFQQ_FLAG_deep, /* sync cfqq experienced large depth */
321 CFQ_CFQQ_FLAG_wait_busy, /* Waiting for next request */ 315 CFQ_CFQQ_FLAG_wait_busy, /* Waiting for next request */
322}; 316};
@@ -345,6 +339,7 @@ CFQ_CFQQ_FNS(prio_changed);
345CFQ_CFQQ_FNS(slice_new); 339CFQ_CFQQ_FNS(slice_new);
346CFQ_CFQQ_FNS(sync); 340CFQ_CFQQ_FNS(sync);
347CFQ_CFQQ_FNS(coop); 341CFQ_CFQQ_FNS(coop);
342CFQ_CFQQ_FNS(split_coop);
348CFQ_CFQQ_FNS(deep); 343CFQ_CFQQ_FNS(deep);
349CFQ_CFQQ_FNS(wait_busy); 344CFQ_CFQQ_FNS(wait_busy);
350#undef CFQ_CFQQ_FNS 345#undef CFQ_CFQQ_FNS
@@ -842,7 +837,6 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
842 837
843 __cfq_group_service_tree_add(st, cfqg); 838 __cfq_group_service_tree_add(st, cfqg);
844 cfqg->on_st = true; 839 cfqg->on_st = true;
845 cfqd->nr_groups++;
846 st->total_weight += cfqg->weight; 840 st->total_weight += cfqg->weight;
847} 841}
848 842
@@ -863,7 +857,6 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
863 857
864 cfq_log_cfqg(cfqd, cfqg, "del_from_rr group"); 858 cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
865 cfqg->on_st = false; 859 cfqg->on_st = false;
866 cfqd->nr_groups--;
867 st->total_weight -= cfqg->weight; 860 st->total_weight -= cfqg->weight;
868 if (!RB_EMPTY_NODE(&cfqg->rb_node)) 861 if (!RB_EMPTY_NODE(&cfqg->rb_node))
869 cfq_rb_erase(&cfqg->rb_node, st); 862 cfq_rb_erase(&cfqg->rb_node, st);
@@ -1150,7 +1143,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1150#endif 1143#endif
1151 1144
1152 service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq), 1145 service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
1153 cfqq_type(cfqq), cfqd); 1146 cfqq_type(cfqq));
1154 if (cfq_class_idle(cfqq)) { 1147 if (cfq_class_idle(cfqq)) {
1155 rb_key = CFQ_IDLE_DELAY; 1148 rb_key = CFQ_IDLE_DELAY;
1156 parent = rb_last(&service_tree->rb); 1149 parent = rb_last(&service_tree->rb);
@@ -1513,9 +1506,6 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
1513 struct cfq_io_context *cic; 1506 struct cfq_io_context *cic;
1514 struct cfq_queue *cfqq; 1507 struct cfq_queue *cfqq;
1515 1508
1516 /* Deny merge if bio and rq don't belong to same cfq group */
1517 if ((RQ_CFQQ(rq))->cfqg != cfq_get_cfqg(cfqd, 0))
1518 return false;
1519 /* 1509 /*
1520 * Disallow merge of a sync bio into an async request. 1510 * Disallow merge of a sync bio into an async request.
1521 */ 1511 */
@@ -1574,6 +1564,15 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1574 cfq_clear_cfqq_wait_busy(cfqq); 1564 cfq_clear_cfqq_wait_busy(cfqq);
1575 1565
1576 /* 1566 /*
1567 * If this cfqq is shared between multiple processes, check to
1568 * make sure that those processes are still issuing I/Os within
1569 * the mean seek distance. If not, it may be time to break the
1570 * queues apart again.
1571 */
1572 if (cfq_cfqq_coop(cfqq) && CFQQ_SEEKY(cfqq))
1573 cfq_mark_cfqq_split_coop(cfqq);
1574
1575 /*
1577 * store what was left of this slice, if the queue idled/timed out 1576 * store what was left of this slice, if the queue idled/timed out
1578 */ 1577 */
1579 if (timed_out && !cfq_cfqq_slice_new(cfqq)) { 1578 if (timed_out && !cfq_cfqq_slice_new(cfqq)) {
@@ -1616,7 +1615,7 @@ static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
1616{ 1615{
1617 struct cfq_rb_root *service_tree = 1616 struct cfq_rb_root *service_tree =
1618 service_tree_for(cfqd->serving_group, cfqd->serving_prio, 1617 service_tree_for(cfqd->serving_group, cfqd->serving_prio,
1619 cfqd->serving_type, cfqd); 1618 cfqd->serving_type);
1620 1619
1621 if (!cfqd->rq_queued) 1620 if (!cfqd->rq_queued)
1622 return NULL; 1621 return NULL;
@@ -1671,17 +1670,18 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
1671 return cfqd->last_position - blk_rq_pos(rq); 1670 return cfqd->last_position - blk_rq_pos(rq);
1672} 1671}
1673 1672
1674#define CFQQ_SEEK_THR 8 * 1024
1675#define CFQQ_SEEKY(cfqq) ((cfqq)->seek_mean > CFQQ_SEEK_THR)
1676
1677static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq, 1673static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1678 struct request *rq) 1674 struct request *rq, bool for_preempt)
1679{ 1675{
1680 sector_t sdist = cfqq->seek_mean; 1676 sector_t sdist = cfqq->seek_mean;
1681 1677
1682 if (!sample_valid(cfqq->seek_samples)) 1678 if (!sample_valid(cfqq->seek_samples))
1683 sdist = CFQQ_SEEK_THR; 1679 sdist = CFQQ_SEEK_THR;
1684 1680
1681 /* if seek_mean is big, using it as close criteria is meaningless */
1682 if (sdist > CFQQ_SEEK_THR && !for_preempt)
1683 sdist = CFQQ_SEEK_THR;
1684
1685 return cfq_dist_from_last(cfqd, rq) <= sdist; 1685 return cfq_dist_from_last(cfqd, rq) <= sdist;
1686} 1686}
1687 1687
@@ -1709,7 +1709,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
1709 * will contain the closest sector. 1709 * will contain the closest sector.
1710 */ 1710 */
1711 __cfqq = rb_entry(parent, struct cfq_queue, p_node); 1711 __cfqq = rb_entry(parent, struct cfq_queue, p_node);
1712 if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq)) 1712 if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
1713 return __cfqq; 1713 return __cfqq;
1714 1714
1715 if (blk_rq_pos(__cfqq->next_rq) < sector) 1715 if (blk_rq_pos(__cfqq->next_rq) < sector)
@@ -1720,7 +1720,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
1720 return NULL; 1720 return NULL;
1721 1721
1722 __cfqq = rb_entry(node, struct cfq_queue, p_node); 1722 __cfqq = rb_entry(node, struct cfq_queue, p_node);
1723 if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq)) 1723 if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
1724 return __cfqq; 1724 return __cfqq;
1725 1725
1726 return NULL; 1726 return NULL;
@@ -1807,7 +1807,7 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
1807 * Otherwise, we do only if they are the last ones 1807 * Otherwise, we do only if they are the last ones
1808 * in their service tree. 1808 * in their service tree.
1809 */ 1809 */
1810 return service_tree->count == 1; 1810 return service_tree->count == 1 && cfq_cfqq_sync(cfqq);
1811} 1811}
1812 1812
1813static void cfq_arm_slice_timer(struct cfq_data *cfqd) 1813static void cfq_arm_slice_timer(struct cfq_data *cfqd)
@@ -1963,8 +1963,7 @@ static void cfq_setup_merge(struct cfq_queue *cfqq, struct cfq_queue *new_cfqq)
1963} 1963}
1964 1964
1965static enum wl_type_t cfq_choose_wl(struct cfq_data *cfqd, 1965static enum wl_type_t cfq_choose_wl(struct cfq_data *cfqd,
1966 struct cfq_group *cfqg, enum wl_prio_t prio, 1966 struct cfq_group *cfqg, enum wl_prio_t prio)
1967 bool prio_changed)
1968{ 1967{
1969 struct cfq_queue *queue; 1968 struct cfq_queue *queue;
1970 int i; 1969 int i;
@@ -1972,24 +1971,9 @@ static enum wl_type_t cfq_choose_wl(struct cfq_data *cfqd,
1972 unsigned long lowest_key = 0; 1971 unsigned long lowest_key = 0;
1973 enum wl_type_t cur_best = SYNC_NOIDLE_WORKLOAD; 1972 enum wl_type_t cur_best = SYNC_NOIDLE_WORKLOAD;
1974 1973
1975 if (prio_changed) { 1974 for (i = 0; i <= SYNC_WORKLOAD; ++i) {
1976 /* 1975 /* select the one with lowest rb_key */
1977 * When priorities switched, we prefer starting 1976 queue = cfq_rb_first(service_tree_for(cfqg, prio, i));
1978 * from SYNC_NOIDLE (first choice), or just SYNC
1979 * over ASYNC
1980 */
1981 if (service_tree_for(cfqg, prio, cur_best, cfqd)->count)
1982 return cur_best;
1983 cur_best = SYNC_WORKLOAD;
1984 if (service_tree_for(cfqg, prio, cur_best, cfqd)->count)
1985 return cur_best;
1986
1987 return ASYNC_WORKLOAD;
1988 }
1989
1990 for (i = 0; i < 3; ++i) {
1991 /* otherwise, select the one with lowest rb_key */
1992 queue = cfq_rb_first(service_tree_for(cfqg, prio, i, cfqd));
1993 if (queue && 1977 if (queue &&
1994 (!key_valid || time_before(queue->rb_key, lowest_key))) { 1978 (!key_valid || time_before(queue->rb_key, lowest_key))) {
1995 lowest_key = queue->rb_key; 1979 lowest_key = queue->rb_key;
@@ -2003,8 +1987,6 @@ static enum wl_type_t cfq_choose_wl(struct cfq_data *cfqd,
2003 1987
2004static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg) 1988static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
2005{ 1989{
2006 enum wl_prio_t previous_prio = cfqd->serving_prio;
2007 bool prio_changed;
2008 unsigned slice; 1990 unsigned slice;
2009 unsigned count; 1991 unsigned count;
2010 struct cfq_rb_root *st; 1992 struct cfq_rb_root *st;
@@ -2032,24 +2014,19 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
2032 * (SYNC, SYNC_NOIDLE, ASYNC), and to compute a workload 2014 * (SYNC, SYNC_NOIDLE, ASYNC), and to compute a workload
2033 * expiration time 2015 * expiration time
2034 */ 2016 */
2035 prio_changed = (cfqd->serving_prio != previous_prio); 2017 st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type);
2036 st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type,
2037 cfqd);
2038 count = st->count; 2018 count = st->count;
2039 2019
2040 /* 2020 /*
2041 * If priority didn't change, check workload expiration, 2021 * check workload expiration, and that we still have other queues ready
2042 * and that we still have other queues ready
2043 */ 2022 */
2044 if (!prio_changed && count && 2023 if (count && !time_after(jiffies, cfqd->workload_expires))
2045 !time_after(jiffies, cfqd->workload_expires))
2046 return; 2024 return;
2047 2025
2048 /* otherwise select new workload type */ 2026 /* otherwise select new workload type */
2049 cfqd->serving_type = 2027 cfqd->serving_type =
2050 cfq_choose_wl(cfqd, cfqg, cfqd->serving_prio, prio_changed); 2028 cfq_choose_wl(cfqd, cfqg, cfqd->serving_prio);
2051 st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type, 2029 st = service_tree_for(cfqg, cfqd->serving_prio, cfqd->serving_type);
2052 cfqd);
2053 count = st->count; 2030 count = st->count;
2054 2031
2055 /* 2032 /*
@@ -3027,19 +3004,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
3027 total = cfqq->seek_total + (cfqq->seek_samples/2); 3004 total = cfqq->seek_total + (cfqq->seek_samples/2);
3028 do_div(total, cfqq->seek_samples); 3005 do_div(total, cfqq->seek_samples);
3029 cfqq->seek_mean = (sector_t)total; 3006 cfqq->seek_mean = (sector_t)total;
3030
3031 /*
3032 * If this cfqq is shared between multiple processes, check to
3033 * make sure that those processes are still issuing I/Os within
3034 * the mean seek distance. If not, it may be time to break the
3035 * queues apart again.
3036 */
3037 if (cfq_cfqq_coop(cfqq)) {
3038 if (CFQQ_SEEKY(cfqq) && !cfqq->seeky_start)
3039 cfqq->seeky_start = jiffies;
3040 else if (!CFQQ_SEEKY(cfqq))
3041 cfqq->seeky_start = 0;
3042 }
3043} 3007}
3044 3008
3045/* 3009/*
@@ -3104,6 +3068,12 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
3104 return true; 3068 return true;
3105 3069
3106 /* 3070 /*
3071 * Don't allow a non-RT request to preempt an ongoing RT cfqq timeslice.
3072 */
3073 if (cfq_class_rt(cfqq) && !cfq_class_rt(new_cfqq))
3074 return false;
3075
3076 /*
3107 * if the new request is sync, but the currently running queue is 3077 * if the new request is sync, but the currently running queue is
3108 * not, let the sync request have priority. 3078 * not, let the sync request have priority.
3109 */ 3079 */
@@ -3143,7 +3113,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
3143 * if this request is as-good as one we would expect from the 3113 * if this request is as-good as one we would expect from the
3144 * current cfqq, let it preempt 3114 * current cfqq, let it preempt
3145 */ 3115 */
3146 if (cfq_rq_close(cfqd, cfqq, rq)) 3116 if (cfq_rq_close(cfqd, cfqq, rq, true))
3147 return true; 3117 return true;
3148 3118
3149 return false; 3119 return false;
@@ -3474,14 +3444,6 @@ cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic,
3474 return cic_to_cfqq(cic, 1); 3444 return cic_to_cfqq(cic, 1);
3475} 3445}
3476 3446
3477static int should_split_cfqq(struct cfq_queue *cfqq)
3478{
3479 if (cfqq->seeky_start &&
3480 time_after(jiffies, cfqq->seeky_start + CFQQ_COOP_TOUT))
3481 return 1;
3482 return 0;
3483}
3484
3485/* 3447/*
3486 * Returns NULL if a new cfqq should be allocated, or the old cfqq if this 3448 * Returns NULL if a new cfqq should be allocated, or the old cfqq if this
3487 * was the last process referring to said cfqq. 3449 * was the last process referring to said cfqq.
@@ -3490,9 +3452,9 @@ static struct cfq_queue *
3490split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq) 3452split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq)
3491{ 3453{
3492 if (cfqq_process_refs(cfqq) == 1) { 3454 if (cfqq_process_refs(cfqq) == 1) {
3493 cfqq->seeky_start = 0;
3494 cfqq->pid = current->pid; 3455 cfqq->pid = current->pid;
3495 cfq_clear_cfqq_coop(cfqq); 3456 cfq_clear_cfqq_coop(cfqq);
3457 cfq_clear_cfqq_split_coop(cfqq);
3496 return cfqq; 3458 return cfqq;
3497 } 3459 }
3498 3460
@@ -3531,7 +3493,7 @@ new_queue:
3531 /* 3493 /*
3532 * If the queue was seeky for too long, break it apart. 3494 * If the queue was seeky for too long, break it apart.
3533 */ 3495 */
3534 if (cfq_cfqq_coop(cfqq) && should_split_cfqq(cfqq)) { 3496 if (cfq_cfqq_coop(cfqq) && cfq_cfqq_split_coop(cfqq)) {
3535 cfq_log_cfqq(cfqd, cfqq, "breaking apart cfqq"); 3497 cfq_log_cfqq(cfqd, cfqq, "breaking apart cfqq");
3536 cfqq = split_cfqq(cic, cfqq); 3498 cfqq = split_cfqq(cic, cfqq);
3537 if (!cfqq) 3499 if (!cfqq)