diff options
Diffstat (limited to 'block/elevator.c')
-rw-r--r-- | block/elevator.c | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/block/elevator.c b/block/elevator.c index 85a11cee7d1c..39dcccc82ada 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -304,15 +304,7 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) | |||
304 | 304 | ||
305 | rq->flags &= ~REQ_STARTED; | 305 | rq->flags &= ~REQ_STARTED; |
306 | 306 | ||
307 | /* | 307 | __elv_add_request(q, rq, ELEVATOR_INSERT_REQUEUE, 0); |
308 | * if this is the flush, requeue the original instead and drop the flush | ||
309 | */ | ||
310 | if (rq->flags & REQ_BAR_FLUSH) { | ||
311 | clear_bit(QUEUE_FLAG_FLUSH, &q->queue_flags); | ||
312 | rq = rq->end_io_data; | ||
313 | } | ||
314 | |||
315 | __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); | ||
316 | } | 308 | } |
317 | 309 | ||
318 | static void elv_drain_elevator(request_queue_t *q) | 310 | static void elv_drain_elevator(request_queue_t *q) |
@@ -332,8 +324,19 @@ static void elv_drain_elevator(request_queue_t *q) | |||
332 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, | 324 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, |
333 | int plug) | 325 | int plug) |
334 | { | 326 | { |
327 | struct list_head *pos; | ||
328 | unsigned ordseq; | ||
329 | |||
330 | if (q->ordcolor) | ||
331 | rq->flags |= REQ_ORDERED_COLOR; | ||
332 | |||
335 | if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { | 333 | if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { |
336 | /* | 334 | /* |
335 | * toggle ordered color | ||
336 | */ | ||
337 | q->ordcolor ^= 1; | ||
338 | |||
339 | /* | ||
337 | * barriers implicitly indicate back insertion | 340 | * barriers implicitly indicate back insertion |
338 | */ | 341 | */ |
339 | if (where == ELEVATOR_INSERT_SORT) | 342 | if (where == ELEVATOR_INSERT_SORT) |
@@ -393,6 +396,30 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
393 | q->elevator->ops->elevator_add_req_fn(q, rq); | 396 | q->elevator->ops->elevator_add_req_fn(q, rq); |
394 | break; | 397 | break; |
395 | 398 | ||
399 | case ELEVATOR_INSERT_REQUEUE: | ||
400 | /* | ||
401 | * If ordered flush isn't in progress, we do front | ||
402 | * insertion; otherwise, requests should be requeued | ||
403 | * in ordseq order. | ||
404 | */ | ||
405 | rq->flags |= REQ_SOFTBARRIER; | ||
406 | |||
407 | if (q->ordseq == 0) { | ||
408 | list_add(&rq->queuelist, &q->queue_head); | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | ordseq = blk_ordered_req_seq(rq); | ||
413 | |||
414 | list_for_each(pos, &q->queue_head) { | ||
415 | struct request *pos_rq = list_entry_rq(pos); | ||
416 | if (ordseq <= blk_ordered_req_seq(pos_rq)) | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | list_add_tail(&rq->queuelist, pos); | ||
421 | break; | ||
422 | |||
396 | default: | 423 | default: |
397 | printk(KERN_ERR "%s: bad insertion point %d\n", | 424 | printk(KERN_ERR "%s: bad insertion point %d\n", |
398 | __FUNCTION__, where); | 425 | __FUNCTION__, where); |
@@ -422,25 +449,16 @@ static inline struct request *__elv_next_request(request_queue_t *q) | |||
422 | { | 449 | { |
423 | struct request *rq; | 450 | struct request *rq; |
424 | 451 | ||
425 | if (unlikely(list_empty(&q->queue_head) && | 452 | while (1) { |
426 | !q->elevator->ops->elevator_dispatch_fn(q, 0))) | 453 | while (!list_empty(&q->queue_head)) { |
427 | return NULL; | 454 | rq = list_entry_rq(q->queue_head.next); |
428 | 455 | if (blk_do_ordered(q, &rq)) | |
429 | rq = list_entry_rq(q->queue_head.next); | 456 | return rq; |
430 | 457 | } | |
431 | /* | ||
432 | * if this is a barrier write and the device has to issue a | ||
433 | * flush sequence to support it, check how far we are | ||
434 | */ | ||
435 | if (blk_fs_request(rq) && blk_barrier_rq(rq)) { | ||
436 | BUG_ON(q->ordered == QUEUE_ORDERED_NONE); | ||
437 | 458 | ||
438 | if (q->ordered == QUEUE_ORDERED_FLUSH && | 459 | if (!q->elevator->ops->elevator_dispatch_fn(q, 0)) |
439 | !blk_barrier_preflush(rq)) | 460 | return NULL; |
440 | rq = blk_start_pre_flush(q, rq); | ||
441 | } | 461 | } |
442 | |||
443 | return rq; | ||
444 | } | 462 | } |
445 | 463 | ||
446 | struct request *elv_next_request(request_queue_t *q) | 464 | struct request *elv_next_request(request_queue_t *q) |
@@ -593,7 +611,21 @@ void elv_completed_request(request_queue_t *q, struct request *rq) | |||
593 | * request is released from the driver, io must be done | 611 | * request is released from the driver, io must be done |
594 | */ | 612 | */ |
595 | if (blk_account_rq(rq)) { | 613 | if (blk_account_rq(rq)) { |
614 | struct request *first_rq = list_entry_rq(q->queue_head.next); | ||
615 | |||
596 | q->in_flight--; | 616 | q->in_flight--; |
617 | |||
618 | /* | ||
619 | * Check if the queue is waiting for fs requests to be | ||
620 | * drained for flush sequence. | ||
621 | */ | ||
622 | if (q->ordseq && q->in_flight == 0 && | ||
623 | blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN && | ||
624 | blk_ordered_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) { | ||
625 | blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0); | ||
626 | q->request_fn(q); | ||
627 | } | ||
628 | |||
597 | if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) | 629 | if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) |
598 | e->ops->elevator_completed_req_fn(q, rq); | 630 | e->ops->elevator_completed_req_fn(q, rq); |
599 | } | 631 | } |