summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/elevator.c25
-rw-r--r--include/linux/blkdev.h2
2 files changed, 22 insertions, 5 deletions
diff --git a/block/elevator.c b/block/elevator.c
index a475b1a19f67..73aa46b6db49 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -226,6 +226,7 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq)
if (q->last_merge == rq)
q->last_merge = NULL;
+ q->nr_sorted--;
boundary = q->end_sector;
@@ -284,6 +285,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
if (e->ops->elevator_merge_req_fn)
e->ops->elevator_merge_req_fn(q, rq, next);
+ q->nr_sorted--;
q->last_merge = rq;
}
@@ -315,6 +317,20 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
__elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
}
+static void elv_drain_elevator(request_queue_t *q)
+{
+ static int printed;
+ while (q->elevator->ops->elevator_dispatch_fn(q, 1))
+ ;
+ if (q->nr_sorted == 0)
+ return;
+ if (printed++ < 10) {
+ printk(KERN_ERR "%s: forced dispatching is broken "
+ "(nr_sorted=%u), please report this\n",
+ q->elevator->elevator_type->elevator_name, q->nr_sorted);
+ }
+}
+
void __elv_add_request(request_queue_t *q, struct request *rq, int where,
int plug)
{
@@ -349,9 +365,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
case ELEVATOR_INSERT_BACK:
rq->flags |= REQ_SOFTBARRIER;
-
- while (q->elevator->ops->elevator_dispatch_fn(q, 1))
- ;
+ elv_drain_elevator(q);
list_add_tail(&rq->queuelist, &q->queue_head);
/*
* We kick the queue here for the following reasons.
@@ -370,6 +384,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
case ELEVATOR_INSERT_SORT:
BUG_ON(!blk_fs_request(rq));
rq->flags |= REQ_SORTED;
+ q->nr_sorted++;
if (q->last_merge == NULL && rq_mergeable(rq))
q->last_merge = rq;
/*
@@ -692,8 +707,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
- while (q->elevator->ops->elevator_dispatch_fn(q, 1))
- ;
+ elv_drain_elevator(q);
while (q->rq.elvpriv) {
blk_remove_plug(q);
@@ -701,6 +715,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
spin_unlock_irq(q->queue_lock);
msleep(10);
spin_lock_irq(q->queue_lock);
+ elv_drain_elevator(q);
}
spin_unlock_irq(q->queue_lock);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 025a7f084dbd..a33a31e71bbc 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -406,6 +406,7 @@ struct request_queue
atomic_t refcnt;
+ unsigned int nr_sorted;
unsigned int in_flight;
/*
@@ -631,6 +632,7 @@ static inline void elv_dispatch_add_tail(struct request_queue *q,
{
if (q->last_merge == rq)
q->last_merge = NULL;
+ q->nr_sorted--;
q->end_sector = rq_end_sector(rq);
q->boundary_rq = rq;