aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/elevator.c242
-rw-r--r--drivers/block/ll_rw_blk.c23
-rw-r--r--include/linux/blkdev.h17
-rw-r--r--include/linux/elevator.h16
4 files changed, 201 insertions, 97 deletions
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 4144f30d82a9..a27555908d35 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -40,6 +40,11 @@
40static DEFINE_SPINLOCK(elv_list_lock); 40static DEFINE_SPINLOCK(elv_list_lock);
41static LIST_HEAD(elv_list); 41static LIST_HEAD(elv_list);
42 42
43static inline sector_t rq_last_sector(struct request *rq)
44{
45 return rq->sector + rq->nr_sectors;
46}
47
43/* 48/*
44 * can we safely merge with this request? 49 * can we safely merge with this request?
45 */ 50 */
@@ -143,6 +148,9 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e,
143 INIT_LIST_HEAD(&q->queue_head); 148 INIT_LIST_HEAD(&q->queue_head);
144 q->last_merge = NULL; 149 q->last_merge = NULL;
145 q->elevator = eq; 150 q->elevator = eq;
151 q->last_sector = 0;
152 q->boundary_rq = NULL;
153 q->max_back_kb = 0;
146 154
147 if (eq->ops->elevator_init_fn) 155 if (eq->ops->elevator_init_fn)
148 ret = eq->ops->elevator_init_fn(q, eq); 156 ret = eq->ops->elevator_init_fn(q, eq);
@@ -225,6 +233,48 @@ void elevator_exit(elevator_t *e)
225 kfree(e); 233 kfree(e);
226} 234}
227 235
236/*
237 * Insert rq into dispatch queue of q. Queue lock must be held on
238 * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be
239 * appended to the dispatch queue. To be used by specific elevators.
240 */
241void elv_dispatch_insert(request_queue_t *q, struct request *rq, int sort)
242{
243 sector_t boundary;
244 unsigned max_back;
245 struct list_head *entry;
246
247 if (!sort) {
248 /* Specific elevator is performing sort. Step away. */
249 q->last_sector = rq_last_sector(rq);
250 q->boundary_rq = rq;
251 list_add_tail(&rq->queuelist, &q->queue_head);
252 return;
253 }
254
255 boundary = q->last_sector;
256 max_back = q->max_back_kb * 2;
257 boundary = boundary > max_back ? boundary - max_back : 0;
258
259 list_for_each_prev(entry, &q->queue_head) {
260 struct request *pos = list_entry_rq(entry);
261
262 if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
263 break;
264 if (rq->sector >= boundary) {
265 if (pos->sector < boundary)
266 continue;
267 } else {
268 if (pos->sector >= boundary)
269 break;
270 }
271 if (rq->sector >= pos->sector)
272 break;
273 }
274
275 list_add(&rq->queuelist, entry);
276}
277
228int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) 278int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
229{ 279{
230 elevator_t *e = q->elevator; 280 elevator_t *e = q->elevator;
@@ -255,13 +305,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
255 e->ops->elevator_merge_req_fn(q, rq, next); 305 e->ops->elevator_merge_req_fn(q, rq, next);
256} 306}
257 307
258/* 308void elv_requeue_request(request_queue_t *q, struct request *rq)
259 * For careful internal use by the block layer. Essentially the same as
260 * a requeue in that it tells the io scheduler that this request is not
261 * active in the driver or hardware anymore, but we don't want the request
262 * added back to the scheduler. Function is not exported.
263 */
264void elv_deactivate_request(request_queue_t *q, struct request *rq)
265{ 309{
266 elevator_t *e = q->elevator; 310 elevator_t *e = q->elevator;
267 311
@@ -269,19 +313,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq)
269 * it already went through dequeue, we need to decrement the 313 * it already went through dequeue, we need to decrement the
270 * in_flight count again 314 * in_flight count again
271 */ 315 */
272 if (blk_account_rq(rq)) 316 if (blk_account_rq(rq)) {
273 q->in_flight--; 317 q->in_flight--;
318 if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn)
319 e->ops->elevator_deactivate_req_fn(q, rq);
320 }
274 321
275 rq->flags &= ~REQ_STARTED; 322 rq->flags &= ~REQ_STARTED;
276 323
277 if (e->ops->elevator_deactivate_req_fn)
278 e->ops->elevator_deactivate_req_fn(q, rq);
279}
280
281void elv_requeue_request(request_queue_t *q, struct request *rq)
282{
283 elv_deactivate_request(q, rq);
284
285 /* 324 /*
286 * if this is the flush, requeue the original instead and drop the flush 325 * if this is the flush, requeue the original instead and drop the flush
287 */ 326 */
@@ -290,55 +329,89 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
290 rq = rq->end_io_data; 329 rq = rq->end_io_data;
291 } 330 }
292 331
293 /* 332 __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
294 * the request is prepped and may have some resources allocated.
295 * allowing unprepped requests to pass this one may cause resource
296 * deadlock. turn on softbarrier.
297 */
298 rq->flags |= REQ_SOFTBARRIER;
299
300 /*
301 * if iosched has an explicit requeue hook, then use that. otherwise
302 * just put the request at the front of the queue
303 */
304 if (q->elevator->ops->elevator_requeue_req_fn)
305 q->elevator->ops->elevator_requeue_req_fn(q, rq);
306 else
307 __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
308} 333}
309 334
310void __elv_add_request(request_queue_t *q, struct request *rq, int where, 335void __elv_add_request(request_queue_t *q, struct request *rq, int where,
311 int plug) 336 int plug)
312{ 337{
313 /* 338 if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
314 * barriers implicitly indicate back insertion 339 /*
315 */ 340 * barriers implicitly indicate back insertion
316 if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) && 341 */
317 where == ELEVATOR_INSERT_SORT) 342 if (where == ELEVATOR_INSERT_SORT)
318 where = ELEVATOR_INSERT_BACK; 343 where = ELEVATOR_INSERT_BACK;
344
345 /*
346 * this request is scheduling boundary, update last_sector
347 */
348 if (blk_fs_request(rq)) {
349 q->last_sector = rq_last_sector(rq);
350 q->boundary_rq = rq;
351 }
352 }
319 353
320 if (plug) 354 if (plug)
321 blk_plug_device(q); 355 blk_plug_device(q);
322 356
323 rq->q = q; 357 rq->q = q;
324 358
325 if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) { 359 if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) {
326 q->elevator->ops->elevator_add_req_fn(q, rq, where);
327
328 if (blk_queue_plugged(q)) {
329 int nrq = q->rq.count[READ] + q->rq.count[WRITE]
330 - q->in_flight;
331
332 if (nrq >= q->unplug_thresh)
333 __generic_unplug_device(q);
334 }
335 } else
336 /* 360 /*
337 * if drain is set, store the request "locally". when the drain 361 * if drain is set, store the request "locally". when the drain
338 * is finished, the requests will be handed ordered to the io 362 * is finished, the requests will be handed ordered to the io
339<