diff options
author | Tejun Heo <htejun@gmail.com> | 2005-11-10 02:49:19 -0500 |
---|---|---|
committer | Jens Axboe <axboe@nelson.home.kernel.dk> | 2005-11-12 04:55:51 -0500 |
commit | 1b5ed5e1f1315e37380e55102f58bcae3344d2a7 (patch) | |
tree | 785dc9675e2f22b60017030063ba103740c72f16 /block/cfq-iosched.c | |
parent | 407df2aa29a33fe16f6ee4bac8cdfa414783b9f1 (diff) |
[BLOCK] cfq-iosched: cfq forced dispatching fix
cfq forced dispatching might not return all requests on the queue.
This bug can hang elevator switchinig and corrupt request ordering
during flush sequence.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ecacca9c877e..452538644bce 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -999,7 +999,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
999 | /* | 999 | /* |
1000 | * get next queue for service | 1000 | * get next queue for service |
1001 | */ | 1001 | */ |
1002 | static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force) | 1002 | static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) |
1003 | { | 1003 | { |
1004 | unsigned long now = jiffies; | 1004 | unsigned long now = jiffies; |
1005 | struct cfq_queue *cfqq; | 1005 | struct cfq_queue *cfqq; |
@@ -1023,7 +1023,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force) | |||
1023 | */ | 1023 | */ |
1024 | if (!RB_EMPTY(&cfqq->sort_list)) | 1024 | if (!RB_EMPTY(&cfqq->sort_list)) |
1025 | goto keep_queue; | 1025 | goto keep_queue; |
1026 | else if (!force && cfq_cfqq_class_sync(cfqq) && | 1026 | else if (cfq_cfqq_class_sync(cfqq) && |
1027 | time_before(now, cfqq->slice_end)) { | 1027 | time_before(now, cfqq->slice_end)) { |
1028 | if (cfq_arm_slice_timer(cfqd, cfqq)) | 1028 | if (cfq_arm_slice_timer(cfqd, cfqq)) |
1029 | return NULL; | 1029 | return NULL; |
@@ -1092,6 +1092,42 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | static int | 1094 | static int |
1095 | cfq_forced_dispatch_cfqqs(struct list_head *list) | ||
1096 | { | ||
1097 | int dispatched = 0; | ||
1098 | struct cfq_queue *cfqq, *next; | ||
1099 | struct cfq_rq *crq; | ||
1100 | |||
1101 | list_for_each_entry_safe(cfqq, next, list, cfq_list) { | ||
1102 | while ((crq = cfqq->next_crq)) { | ||
1103 | cfq_dispatch_insert(cfqq->cfqd->queue, crq); | ||
1104 | dispatched++; | ||
1105 | } | ||
1106 | BUG_ON(!list_empty(&cfqq->fifo)); | ||
1107 | } | ||
1108 | return dispatched; | ||
1109 | } | ||
1110 | |||
1111 | static int | ||
1112 | cfq_forced_dispatch(struct cfq_data *cfqd) | ||
1113 | { | ||
1114 | int i, dispatched = 0; | ||
1115 | |||
1116 | for (i = 0; i < CFQ_PRIO_LISTS; i++) | ||
1117 | dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]); | ||
1118 | |||
1119 | dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr); | ||
1120 | dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr); | ||
1121 | dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr); | ||
1122 | |||
1123 | cfq_slice_expired(cfqd, 0); | ||
1124 | |||
1125 | BUG_ON(cfqd->busy_queues); | ||
1126 | |||
1127 | return dispatched; | ||
1128 | } | ||
1129 | |||
1130 | static int | ||
1095 | cfq_dispatch_requests(request_queue_t *q, int force) | 1131 | cfq_dispatch_requests(request_queue_t *q, int force) |
1096 | { | 1132 | { |
1097 | struct cfq_data *cfqd = q->elevator->elevator_data; | 1133 | struct cfq_data *cfqd = q->elevator->elevator_data; |
@@ -1100,7 +1136,10 @@ cfq_dispatch_requests(request_queue_t *q, int force) | |||
1100 | if (!cfqd->busy_queues) | 1136 | if (!cfqd->busy_queues) |
1101 | return 0; | 1137 | return 0; |
1102 | 1138 | ||
1103 | cfqq = cfq_select_queue(cfqd, force); | 1139 | if (unlikely(force)) |
1140 | return cfq_forced_dispatch(cfqd); | ||
1141 | |||
1142 | cfqq = cfq_select_queue(cfqd); | ||
1104 | if (cfqq) { | 1143 | if (cfqq) { |
1105 | int max_dispatch; | 1144 | int max_dispatch; |
1106 | 1145 | ||
@@ -1115,12 +1154,9 @@ cfq_dispatch_requests(request_queue_t *q, int force) | |||
1115 | cfq_clear_cfqq_wait_request(cfqq); | 1154 | cfq_clear_cfqq_wait_request(cfqq); |
1116 | del_timer(&cfqd->idle_slice_timer); | 1155 | del_timer(&cfqd->idle_slice_timer); |
1117 | 1156 | ||
1118 | if (!force) { | 1157 | max_dispatch = cfqd->cfq_quantum; |
1119 | max_dispatch = cfqd->cfq_quantum; | 1158 | if (cfq_class_idle(cfqq)) |
1120 | if (cfq_class_idle(cfqq)) | 1159 | max_dispatch = 1; |
1121 | max_dispatch = 1; | ||
1122 | } else | ||
1123 | max_dispatch = INT_MAX; | ||
1124 | 1160 | ||
1125 | return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); | 1161 | return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); |
1126 | } | 1162 | } |