diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 14:06:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 14:06:41 -0400 |
commit | 6a5d263866d699ebf6843105497afc86ee53de5b (patch) | |
tree | 439195e272631908cdc2e3e44abaf7e1c3447157 /block | |
parent | aeeae86859f4319de0a4946b44771d9926eeed54 (diff) | |
parent | ffcd7dca3ab78f9f425971756e5e90024157f6be (diff) |
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block:
loop: mutex already unlocked in loop_clr_fd()
cfq-iosched: don't let idling interfere with plugging
block: remove unused REQ_UNPLUG
cfq-iosched: kill two unused cfqq flags
cfq-iosched: change dispatch logic to deal with single requests at the time
mflash: initial support
cciss: change to discover first memory BAR
cciss: kernel scan thread for MSA2012
cciss: fix residual count for block pc requests
block: fix inconsistency in I/O stat accounting code
block: elevator quiescing helpers
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-core.c | 15 | ||||
-rw-r--r-- | block/blk-merge.c | 29 | ||||
-rw-r--r-- | block/blk-sysfs.c | 4 | ||||
-rw-r--r-- | block/blk.h | 14 | ||||
-rw-r--r-- | block/cfq-iosched.c | 202 | ||||
-rw-r--r-- | block/elevator.c | 42 |
6 files changed, 169 insertions, 137 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 25572802dac2..43fdedc524ee 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -64,12 +64,11 @@ static struct workqueue_struct *kblockd_workqueue; | |||
64 | 64 | ||
65 | static void drive_stat_acct(struct request *rq, int new_io) | 65 | static void drive_stat_acct(struct request *rq, int new_io) |
66 | { | 66 | { |
67 | struct gendisk *disk = rq->rq_disk; | ||
68 | struct hd_struct *part; | 67 | struct hd_struct *part; |
69 | int rw = rq_data_dir(rq); | 68 | int rw = rq_data_dir(rq); |
70 | int cpu; | 69 | int cpu; |
71 | 70 | ||
72 | if (!blk_fs_request(rq) || !disk || !blk_do_io_stat(disk->queue)) | 71 | if (!blk_fs_request(rq) || !blk_do_io_stat(rq)) |
73 | return; | 72 | return; |
74 | 73 | ||
75 | cpu = part_stat_lock(); | 74 | cpu = part_stat_lock(); |
@@ -1124,8 +1123,6 @@ void init_request_from_bio(struct request *req, struct bio *bio) | |||
1124 | 1123 | ||
1125 | if (bio_sync(bio)) | 1124 | if (bio_sync(bio)) |
1126 | req->cmd_flags |= REQ_RW_SYNC; | 1125 | req->cmd_flags |= REQ_RW_SYNC; |
1127 | if (bio_unplug(bio)) | ||
1128 | req->cmd_flags |= REQ_UNPLUG; | ||
1129 | if (bio_rw_meta(bio)) | 1126 | if (bio_rw_meta(bio)) |
1130 | req->cmd_flags |= REQ_RW_META; | 1127 | req->cmd_flags |= REQ_RW_META; |
1131 | if (bio_noidle(bio)) | 1128 | if (bio_noidle(bio)) |
@@ -1675,9 +1672,7 @@ EXPORT_SYMBOL(blkdev_dequeue_request); | |||
1675 | 1672 | ||
1676 | static void blk_account_io_completion(struct request *req, unsigned int bytes) | 1673 | static void blk_account_io_completion(struct request *req, unsigned int bytes) |
1677 | { | 1674 | { |
1678 | struct gendisk *disk = req->rq_disk; | 1675 | if (!blk_do_io_stat(req)) |
1679 | |||
1680 | if (!disk || !blk_do_io_stat(disk->queue)) | ||
1681 | return; | 1676 | return; |
1682 | 1677 | ||
1683 | if (blk_fs_request(req)) { | 1678 | if (blk_fs_request(req)) { |
@@ -1694,9 +1689,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) | |||
1694 | 1689 | ||
1695 | static void blk_account_io_done(struct request *req) | 1690 | static void blk_account_io_done(struct request *req) |
1696 | { | 1691 | { |
1697 | struct gendisk *disk = req->rq_disk; | 1692 | if (!blk_do_io_stat(req)) |
1698 | |||
1699 | if (!disk || !blk_do_io_stat(disk->queue)) | ||
1700 | return; | 1693 | return; |
1701 | 1694 | ||
1702 | /* | 1695 | /* |
@@ -1711,7 +1704,7 @@ static void blk_account_io_done(struct request *req) | |||
1711 | int cpu; | 1704 | int cpu; |
1712 | 1705 | ||
1713 | cpu = part_stat_lock(); | 1706 | cpu = part_stat_lock(); |
1714 | part = disk_map_sector_rcu(disk, req->sector); | 1707 | part = disk_map_sector_rcu(req->rq_disk, req->sector); |
1715 | 1708 | ||
1716 | part_stat_inc(cpu, part, ios[rw]); | 1709 | part_stat_inc(cpu, part, ios[rw]); |
1717 | part_stat_add(cpu, part, ticks[rw], duration); | 1710 | part_stat_add(cpu, part, ticks[rw], duration); |
diff --git a/block/blk-merge.c b/block/blk-merge.c index e39cb24b7679..63760ca3da0f 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -338,6 +338,22 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, | |||
338 | return 1; | 338 | return 1; |
339 | } | 339 | } |
340 | 340 | ||
341 | static void blk_account_io_merge(struct request *req) | ||
342 | { | ||
343 | if (blk_do_io_stat(req)) { | ||
344 | struct hd_struct *part; | ||
345 | int cpu; | ||
346 | |||
347 | cpu = part_stat_lock(); | ||
348 | part = disk_map_sector_rcu(req->rq_disk, req->sector); | ||
349 | |||
350 | part_round_stats(cpu, part); | ||
351 | part_dec_in_flight(part); | ||
352 | |||
353 | part_stat_unlock(); | ||
354 | } | ||
355 | } | ||
356 | |||
341 | /* | 357 | /* |
342 | * Has to be called with the request spinlock acquired | 358 | * Has to be called with the request spinlock acquired |
343 | */ | 359 | */ |
@@ -386,18 +402,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, | |||
386 | 402 | ||
387 | elv_merge_requests(q, req, next); | 403 | elv_merge_requests(q, req, next); |
388 | 404 | ||
389 | if (req->rq_disk) { | 405 | blk_account_io_merge(req); |
390 | struct hd_struct *part; | ||
391 | int cpu; | ||
392 | |||
393 | cpu = part_stat_lock(); | ||
394 | part = disk_map_sector_rcu(req->rq_disk, req->sector); | ||
395 | |||
396 | part_round_stats(cpu, part); | ||
397 | part_dec_in_flight(part); | ||
398 | |||
399 | part_stat_unlock(); | ||
400 | } | ||
401 | 406 | ||
402 | req->ioprio = ioprio_best(req->ioprio, next->ioprio); | 407 | req->ioprio = ioprio_best(req->ioprio, next->ioprio); |
403 | if (blk_rq_cpu_valid(next)) | 408 | if (blk_rq_cpu_valid(next)) |
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3ff9bba3379a..73f36beff5cd 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c | |||
@@ -209,10 +209,14 @@ static ssize_t queue_iostats_store(struct request_queue *q, const char *page, | |||
209 | ssize_t ret = queue_var_store(&stats, page, count); | 209 | ssize_t ret = queue_var_store(&stats, page, count); |
210 | 210 | ||
211 | spin_lock_irq(q->queue_lock); | 211 | spin_lock_irq(q->queue_lock); |
212 | elv_quisce_start(q); | ||
213 | |||
212 | if (stats) | 214 | if (stats) |
213 | queue_flag_set(QUEUE_FLAG_IO_STAT, q); | 215 | queue_flag_set(QUEUE_FLAG_IO_STAT, q); |
214 | else | 216 | else |
215 | queue_flag_clear(QUEUE_FLAG_IO_STAT, q); | 217 | queue_flag_clear(QUEUE_FLAG_IO_STAT, q); |
218 | |||
219 | elv_quisce_end(q); | ||
216 | spin_unlock_irq(q->queue_lock); | 220 | spin_unlock_irq(q->queue_lock); |
217 | 221 | ||
218 | return ret; | 222 | return ret; |
diff --git a/block/blk.h b/block/blk.h index 3ee94358b43d..24fcaeeaf620 100644 --- a/block/blk.h +++ b/block/blk.h | |||
@@ -70,6 +70,10 @@ void blk_queue_congestion_threshold(struct request_queue *q); | |||
70 | 70 | ||
71 | int blk_dev_init(void); | 71 | int blk_dev_init(void); |
72 | 72 | ||
73 | void elv_quisce_start(struct request_queue *q); | ||
74 | void elv_quisce_end(struct request_queue *q); | ||
75 | |||
76 | |||
73 | /* | 77 | /* |
74 | * Return the threshold (number of used requests) at which the queue is | 78 | * Return the threshold (number of used requests) at which the queue is |
75 | * considered to be congested. It include a little hysteresis to keep the | 79 | * considered to be congested. It include a little hysteresis to keep the |
@@ -108,12 +112,14 @@ static inline int blk_cpu_to_group(int cpu) | |||
108 | #endif | 112 | #endif |
109 | } | 113 | } |
110 | 114 | ||
111 | static inline int blk_do_io_stat(struct request_queue *q) | 115 | static inline int blk_do_io_stat(struct request *rq) |
112 | { | 116 | { |
113 | if (q) | 117 | struct gendisk *disk = rq->rq_disk; |
114 | return blk_queue_io_stat(q); | ||
115 | 118 | ||
116 | return 0; | 119 | if (!disk || !disk->queue) |
120 | return 0; | ||
121 | |||
122 | return blk_queue_io_stat(disk->queue) && (rq->cmd_flags & REQ_ELVPRIV); | ||
117 | } | 123 | } |
118 | 124 | ||
119 | #endif | 125 | #endif |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 9e809345f71a..a4809de6fea6 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -160,6 +160,7 @@ struct cfq_queue { | |||
160 | 160 | ||
161 | unsigned long slice_end; | 161 | unsigned long slice_end; |
162 | long slice_resid; | 162 | long slice_resid; |
163 | unsigned int slice_dispatch; | ||
163 | 164 | ||
164 | /* pending metadata requests */ | 165 | /* pending metadata requests */ |
165 | int meta_pending; | 166 | int meta_pending; |
@@ -176,13 +177,12 @@ struct cfq_queue { | |||
176 | enum cfqq_state_flags { | 177 | enum cfqq_state_flags { |
177 | CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ | 178 | CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ |
178 | CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ | 179 | CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ |
180 | CFQ_CFQQ_FLAG_must_dispatch, /* must be allowed a dispatch */ | ||
179 | CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ | 181 | CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ |
180 | CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ | 182 | CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ |
181 | CFQ_CFQQ_FLAG_must_dispatch, /* must dispatch, even if expired */ | ||
182 | CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ | 183 | CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ |
183 | CFQ_CFQQ_FLAG_idle_window, /* slice idling enabled */ | 184 | CFQ_CFQQ_FLAG_idle_window, /* slice idling enabled */ |
184 | CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ | 185 | CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ |
185 | CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */ | ||
186 | CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ | 186 | CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ |
187 | CFQ_CFQQ_FLAG_sync, /* synchronous queue */ | 187 | CFQ_CFQQ_FLAG_sync, /* synchronous queue */ |
188 | }; | 188 | }; |
@@ -203,13 +203,12 @@ static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \ | |||
203 | 203 | ||
204 | CFQ_CFQQ_FNS(on_rr); | 204 | CFQ_CFQQ_FNS(on_rr); |
205 | CFQ_CFQQ_FNS(wait_request); | 205 | CFQ_CFQQ_FNS(wait_request); |
206 | CFQ_CFQQ_FNS(must_dispatch); | ||
206 | CFQ_CFQQ_FNS(must_alloc); | 207 | CFQ_CFQQ_FNS(must_alloc); |
207 | CFQ_CFQQ_FNS(must_alloc_slice); | 208 | CFQ_CFQQ_FNS(must_alloc_slice); |
208 | CFQ_CFQQ_FNS(must_dispatch); | ||
209 | CFQ_CFQQ_FNS(fifo_expire); | 209 | CFQ_CFQQ_FNS(fifo_expire); |
210 | CFQ_CFQQ_FNS(idle_window); | 210 | CFQ_CFQQ_FNS(idle_window); |
211 | CFQ_CFQQ_FNS(prio_changed); | 211 | CFQ_CFQQ_FNS(prio_changed); |
212 | CFQ_CFQQ_FNS(queue_new); | ||
213 | CFQ_CFQQ_FNS(slice_new); | 212 | CFQ_CFQQ_FNS(slice_new); |
214 | CFQ_CFQQ_FNS(sync); | 213 | CFQ_CFQQ_FNS(sync); |
215 | #undef CFQ_CFQQ_FNS | 214 | #undef CFQ_CFQQ_FNS |
@@ -774,10 +773,15 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, | |||
774 | if (cfqq) { | 773 | if (cfqq) { |
775 | cfq_log_cfqq(cfqd, cfqq, "set_active"); | 774 | cfq_log_cfqq(cfqd, cfqq, "set_active"); |
776 | cfqq->slice_end = 0; | 775 | cfqq->slice_end = 0; |
776 | cfqq->slice_dispatch = 0; | ||
777 | |||
778 | cfq_clear_cfqq_wait_request(cfqq); | ||
779 | cfq_clear_cfqq_must_dispatch(cfqq); | ||
777 | cfq_clear_cfqq_must_alloc_slice(cfqq); | 780 | cfq_clear_cfqq_must_alloc_slice(cfqq); |
778 | cfq_clear_cfqq_fifo_expire(cfqq); | 781 | cfq_clear_cfqq_fifo_expire(cfqq); |
779 | cfq_mark_cfqq_slice_new(cfqq); | 782 | cfq_mark_cfqq_slice_new(cfqq); |
780 | cfq_clear_cfqq_queue_new(cfqq); | 783 | |
784 | del_timer(&cfqd->idle_slice_timer); | ||
781 | } | 785 | } |
782 | 786 | ||
783 | cfqd->active_queue = cfqq; | 787 | cfqd->active_queue = cfqq; |
@@ -795,7 +799,6 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
795 | if (cfq_cfqq_wait_request(cfqq)) | 799 | if (cfq_cfqq_wait_request(cfqq)) |
796 | del_timer(&cfqd->idle_slice_timer); | 800 | del_timer(&cfqd->idle_slice_timer); |
797 | 801 | ||
798 | cfq_clear_cfqq_must_dispatch(cfqq); | ||
799 | cfq_clear_cfqq_wait_request(cfqq); | 802 | cfq_clear_cfqq_wait_request(cfqq); |
800 | 803 | ||
801 | /* | 804 | /* |
@@ -924,7 +927,6 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) | |||
924 | (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2)) | 927 | (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2)) |
925 | return; | 928 | return; |
926 | 929 | ||
927 | cfq_mark_cfqq_must_dispatch(cfqq); | ||
928 | cfq_mark_cfqq_wait_request(cfqq); | 930 | cfq_mark_cfqq_wait_request(cfqq); |
929 | 931 | ||
930 | /* | 932 | /* |
@@ -1010,7 +1012,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) | |||
1010 | /* | 1012 | /* |
1011 | * The active queue has run out of time, expire it and select new. | 1013 | * The active queue has run out of time, expire it and select new. |
1012 | */ | 1014 | */ |
1013 | if (cfq_slice_used(cfqq)) | 1015 | if (cfq_slice_used(cfqq) && !cfq_cfqq_must_dispatch(cfqq)) |
1014 | goto expire; | 1016 | goto expire; |
1015 | 1017 | ||
1016 | /* | 1018 | /* |
@@ -1053,66 +1055,6 @@ keep_queue: | |||
1053 | return cfqq; | 1055 | return cfqq; |
1054 | } | 1056 | } |
1055 | 1057 | ||
1056 | /* | ||
1057 | * Dispatch some requests from cfqq, moving them to the request queue | ||
1058 | * dispatch list. | ||
1059 | */ | ||
1060 | static int | ||
1061 | __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, | ||
1062 | int max_dispatch) | ||
1063 | { | ||
1064 | int dispatched = 0; | ||
1065 | |||
1066 | BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); | ||
1067 | |||
1068 | do { | ||
1069 | struct request *rq; | ||
1070 | |||
1071 | /* | ||
1072 | * follow expired path, else get first next available | ||
1073 | */ | ||
1074 | rq = cfq_check_fifo(cfqq); | ||
1075 | if (rq == NULL) | ||
1076 | rq = cfqq->next_rq; | ||
1077 | |||
1078 | /* | ||
1079 | * finally, insert request into driver dispatch list | ||
1080 | */ | ||
1081 | cfq_dispatch_insert(cfqd->queue, rq); | ||
1082 | |||
1083 | dispatched++; | ||
1084 | |||
1085 | if (!cfqd->active_cic) { | ||
1086 | atomic_inc(&RQ_CIC(rq)->ioc->refcount); | ||
1087 | cfqd->active_cic = RQ_CIC(rq); | ||
1088 | } | ||
1089 | |||
1090 | if (RB_EMPTY_ROOT(&cfqq->sort_list)) | ||
1091 | break; | ||
1092 | |||
1093 | /* | ||
1094 | * If there is a non-empty RT cfqq waiting for current | ||
1095 | * cfqq's timeslice to complete, pre-empt this cfqq | ||
1096 | */ | ||
1097 | if (!cfq_class_rt(cfqq) && cfqd->busy_rt_queues) | ||
1098 | break; | ||
1099 | |||
1100 | } while (dispatched < max_dispatch); | ||
1101 | |||
1102 | /* | ||
1103 | * expire an async queue immediately if it has used up its slice. idle | ||
1104 | * queue always expire after 1 dispatch round. | ||
1105 | */ | ||
1106 | if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && | ||
1107 | dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) || | ||
1108 | cfq_class_idle(cfqq))) { | ||
1109 | cfqq->slice_end = jiffies + 1; | ||
1110 | cfq_slice_expired(cfqd, 0); | ||
1111 | } | ||
1112 | |||
1113 | return dispatched; | ||
1114 | } | ||
1115 | |||
1116 | static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) | 1058 | static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) |
1117 | { | 1059 | { |
1118 | int dispatched = 0; | 1060 | int dispatched = 0; |
@@ -1146,11 +1088,45 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) | |||
1146 | return dispatched; | 1088 | return dispatched; |
1147 | } | 1089 | } |
1148 | 1090 | ||
1091 | /* | ||
1092 | * Dispatch a request from cfqq, moving them to the request queue | ||
1093 | * dispatch list. | ||
1094 | */ | ||
1095 | static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) | ||
1096 | { | ||
1097 | struct request *rq; | ||
1098 | |||
1099 | BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); | ||
1100 | |||
1101 | /* | ||
1102 | * follow expired path, else get first next available | ||
1103 | */ | ||
1104 | rq = cfq_check_fifo(cfqq); | ||
1105 | if (!rq) | ||
1106 | rq = cfqq->next_rq; | ||
1107 | |||
1108 | /* | ||
1109 | * insert request into driver dispatch list | ||
1110 | */ | ||
1111 | cfq_dispatch_insert(cfqd->queue, rq); | ||
1112 | |||
1113 | if (!cfqd->active_cic) { | ||
1114 | struct cfq_io_context *cic = RQ_CIC(rq); | ||
1115 | |||
1116 | atomic_inc(&cic->ioc->refcount); | ||
1117 | cfqd->active_cic = cic; | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1121 | /* | ||
1122 | * Find the cfqq that we need to service and move a request from that to the | ||
1123 | * dispatch list | ||
1124 | */ | ||
1149 | static int cfq_dispatch_requests(struct request_queue *q, int force) | 1125 | static int cfq_dispatch_requests(struct request_queue *q, int force) |
1150 | { | 1126 | { |
1151 | struct cfq_data *cfqd = q->elevator->elevator_data; | 1127 | struct cfq_data *cfqd = q->elevator->elevator_data; |
1152 | struct cfq_queue *cfqq; | 1128 | struct cfq_queue *cfqq; |
1153 | int dispatched; | 1129 | unsigned int max_dispatch; |
1154 | 1130 | ||
1155 | if (!cfqd->busy_queues) | 1131 | if (!cfqd->busy_queues) |
1156 | return 0; | 1132 | return 0; |
@@ -1158,29 +1134,63 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) | |||
1158 | if (unlikely(force)) | 1134 | if (unlikely(force)) |
1159 | return cfq_forced_dispatch(cfqd); | 1135 | return cfq_forced_dispatch(cfqd); |
1160 | 1136 | ||
1161 | dispatched = 0; | 1137 | cfqq = cfq_select_queue(cfqd); |
1162 | while ((cfqq = cfq_select_queue(cfqd)) != NULL) { | 1138 | if (!cfqq) |
1163 | int max_dispatch; | 1139 | return 0; |
1140 | |||
1141 | /* | ||
1142 | * If this is an async queue and we have sync IO in flight, let it wait | ||
1143 | */ | ||
1144 | if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq)) | ||
1145 | return 0; | ||
1146 | |||
1147 | max_dispatch = cfqd->cfq_quantum; | ||
1148 | if (cfq_class_idle(cfqq)) | ||
1149 | max_dispatch = 1; | ||
1164 | 1150 | ||
1165 | max_dispatch = cfqd->cfq_quantum; | 1151 | /* |
1152 | * Does this cfqq already have too much IO in flight? | ||
1153 | */ | ||
1154 | if (cfqq->dispatched >= max_dispatch) { | ||
1155 | /* | ||
1156 | * idle queue must always only have a single IO in flight | ||
1157 | */ | ||
1166 | if (cfq_class_idle(cfqq)) | 1158 | if (cfq_class_idle(cfqq)) |
1167 | max_dispatch = 1; | 1159 | return 0; |
1168 | 1160 | ||
1169 | if (cfqq->dispatched >= max_dispatch && cfqd->busy_queues > 1) | 1161 | /* |
1170 | break; | 1162 | * We have other queues, don't allow more IO from this one |
1163 | */ | ||
1164 | if (cfqd->busy_queues > 1) | ||
1165 | return 0; | ||
1171 | 1166 | ||
1172 | if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq)) | 1167 | /* |
1173 | break; | 1168 | * we are the only queue, allow up to 4 times of 'quantum' |
1169 | */ | ||
1170 | if (cfqq->dispatched >= 4 * max_dispatch) | ||
1171 | return 0; | ||
1172 | } | ||
1174 | 1173 | ||
1175 | cfq_clear_cfqq_must_dispatch(cfqq); | 1174 | /* |
1176 | cfq_clear_cfqq_wait_request(cfqq); | 1175 | * Dispatch a request from this cfqq |
1177 | del_timer(&cfqd->idle_slice_timer); | 1176 | */ |
1177 | cfq_dispatch_request(cfqd, cfqq); | ||
1178 | cfqq->slice_dispatch++; | ||
1179 | cfq_clear_cfqq_must_dispatch(cfqq); | ||
1178 | 1180 | ||
1179 | dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); | 1181 | /* |
1182 | * expire an async queue immediately if it has used up its slice. idle | ||
1183 | * queue always expire after 1 dispatch round. | ||
1184 | */ | ||
1185 | if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && | ||
1186 | cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) || | ||
1187 | cfq_class_idle(cfqq))) { | ||
1188 | cfqq->slice_end = jiffies + 1; | ||
1189 | cfq_slice_expired(cfqd, 0); | ||
1180 | } | 1190 | } |
1181 | 1191 | ||
1182 | cfq_log(cfqd, "dispatched=%d", dispatched); | 1192 | cfq_log(cfqd, "dispatched a request"); |
1183 | return dispatched; | 1193 | return 1; |
1184 | } | 1194 | } |
1185 | 1195 | ||
1186 | /* | 1196 | /* |
@@ -1506,7 +1516,6 @@ retry: | |||
1506 | cfqq->cfqd = cfqd; | 1516 | cfqq->cfqd = cfqd; |
1507 | 1517 | ||
1508 | cfq_mark_cfqq_prio_changed(cfqq); | 1518 | cfq_mark_cfqq_prio_changed(cfqq); |
1509 | cfq_mark_cfqq_queue_new(cfqq); | ||
1510 | 1519 | ||
1511 | cfq_init_prio_data(cfqq, ioc); | 1520 | cfq_init_prio_data(cfqq, ioc); |
1512 | 1521 | ||
@@ -1893,15 +1902,13 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1893 | 1902 | ||
1894 | if (cfqq == cfqd->active_queue) { | 1903 | if (cfqq == cfqd->active_queue) { |
1895 | /* | 1904 | /* |
1896 | * if we are waiting for a request for this queue, let it rip | 1905 | * Remember that we saw a request from this process, but |
1897 | * immediately and flag that we must not expire this queue | 1906 | * don't start queuing just yet. Otherwise we risk seeing lots |
1898 | * just now | 1907 | * of tiny requests, because we disrupt the normal plugging |
1908 | * and merging. | ||
1899 | */ | 1909 | */ |
1900 | if (cfq_cfqq_wait_request(cfqq)) { | 1910 | if (cfq_cfqq_wait_request(cfqq)) |
1901 | cfq_mark_cfqq_must_dispatch(cfqq); | 1911 | cfq_mark_cfqq_must_dispatch(cfqq); |
1902 | del_timer(&cfqd->idle_slice_timer); | ||
1903 | blk_start_queueing(cfqd->queue); | ||
1904 | } | ||
1905 | } else if (cfq_should_preempt(cfqd, cfqq, rq)) { | 1912 | } else if (cfq_should_preempt(cfqd, cfqq, rq)) { |
1906 | /* | 1913 | /* |
1907 | * not the active queue - expire current slice if it is | 1914 | * not the active queue - expire current slice if it is |
@@ -1910,7 +1917,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1910 | * this new queue is RT and the current one is BE | 1917 | * this new queue is RT and the current one is BE |
1911 | */ | 1918 | */ |
1912 | cfq_preempt_queue(cfqd, cfqq); | 1919 | cfq_preempt_queue(cfqd, cfqq); |
1913 | cfq_mark_cfqq_must_dispatch(cfqq); | ||
1914 | blk_start_queueing(cfqd->queue); | 1920 | blk_start_queueing(cfqd->queue); |
1915 | } | 1921 | } |
1916 | } | 1922 | } |
@@ -2172,6 +2178,12 @@ static void cfq_idle_slice_timer(unsigned long data) | |||
2172 | timed_out = 0; | 2178 | timed_out = 0; |
2173 | 2179 | ||
2174 | /* | 2180 | /* |
2181 | * We saw a request before the queue expired, let it through | ||
2182 | */ | ||
2183 | if (cfq_cfqq_must_dispatch(cfqq)) | ||
2184 | goto out_kick; | ||
2185 | |||
2186 | /* | ||
2175 | * expired | 2187 | * expired |
2176 | */ | 2188 | */ |
2177 | if (cfq_slice_used(cfqq)) | 2189 | if (cfq_slice_used(cfqq)) |
@@ -2187,10 +2199,8 @@ static void cfq_idle_slice_timer(unsigned long data) | |||
2187 | /* | 2199 | /* |
2188 | * not expired and it has a request pending, let it dispatch | 2200 | * not expired and it has a request pending, let it dispatch |
2189 | */ | 2201 | */ |
2190 | if (!RB_EMPTY_ROOT(&cfqq->sort_list)) { | 2202 | if (!RB_EMPTY_ROOT(&cfqq->sort_list)) |
2191 | cfq_mark_cfqq_must_dispatch(cfqq); | ||
2192 | goto out_kick; | 2203 | goto out_kick; |
2193 | } | ||
2194 | } | 2204 | } |
2195 | expire: | 2205 | expire: |
2196 | cfq_slice_expired(cfqd, timed_out); | 2206 | cfq_slice_expired(cfqd, timed_out); |
diff --git a/block/elevator.c b/block/elevator.c index ca6788a0195a..fb81bcc14a8c 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -573,7 +573,7 @@ void elv_requeue_request(struct request_queue *q, struct request *rq) | |||
573 | elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE); | 573 | elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE); |
574 | } | 574 | } |
575 | 575 | ||
576 | static void elv_drain_elevator(struct request_queue *q) | 576 | void elv_drain_elevator(struct request_queue *q) |
577 | { | 577 | { |
578 | static int printed; | 578 | static int printed; |
579 | while (q->elevator->ops->elevator_dispatch_fn(q, 1)) | 579 | while (q->elevator->ops->elevator_dispatch_fn(q, 1)) |
@@ -587,6 +587,31 @@ static void elv_drain_elevator(struct request_queue *q) | |||
587 | } | 587 | } |
588 | } | 588 | } |
589 | 589 | ||
590 | /* | ||
591 | * Call with queue lock held, interrupts disabled | ||
592 | */ | ||
593 | void elv_quisce_start(struct request_queue *q) | ||
594 | { | ||
595 | queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); | ||
596 | |||
597 | /* | ||
598 | * make sure we don't have any requests in flight | ||
599 | */ | ||
600 | elv_drain_elevator(q); | ||
601 | while (q->rq.elvpriv) { | ||
602 | blk_start_queueing(q); | ||
603 | spin_unlock_irq(q->queue_lock); | ||
604 | msleep(10); | ||
605 | spin_lock_irq(q->queue_lock); | ||
606 | elv_drain_elevator(q); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | void elv_quisce_end(struct request_queue *q) | ||
611 | { | ||
612 | queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); | ||
613 | } | ||
614 | |||
590 | void elv_insert(struct request_queue *q, struct request *rq, int where) | 615 | void elv_insert(struct request_queue *q, struct request *rq, int where) |
591 | { | 616 | { |
592 | struct list_head *pos; | 617 | struct list_head *pos; |
@@ -1101,18 +1126,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) | |||
1101 | * Turn on BYPASS and drain all requests w/ elevator private data | 1126 | * Turn on BYPASS and drain all requests w/ elevator private data |
1102 | */ | 1127 | */ |
1103 | spin_lock_irq(q->queue_lock); | 1128 | spin_lock_irq(q->queue_lock); |
1104 | 1129 | elv_quisce_start(q); | |
1105 | queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); | ||
1106 | |||
1107 | elv_drain_elevator(q); | ||
1108 | |||
1109 | while (q->rq.elvpriv) { | ||
1110 | blk_start_queueing(q); | ||
1111 | spin_unlock_irq(q->queue_lock); | ||
1112 | msleep(10); | ||
1113 | spin_lock_irq(q->queue_lock); | ||
1114 | elv_drain_elevator(q); | ||
1115 | } | ||
1116 | 1130 | ||
1117 | /* | 1131 | /* |
1118 | * Remember old elevator. | 1132 | * Remember old elevator. |
@@ -1136,7 +1150,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) | |||
1136 | */ | 1150 | */ |
1137 | elevator_exit(old_elevator); | 1151 | elevator_exit(old_elevator); |
1138 | spin_lock_irq(q->queue_lock); | 1152 | spin_lock_irq(q->queue_lock); |
1139 | queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); | 1153 | elv_quisce_end(q); |
1140 | spin_unlock_irq(q->queue_lock); | 1154 | spin_unlock_irq(q->queue_lock); |
1141 | 1155 | ||
1142 | blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); | 1156 | blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); |