summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/block/deadline-iosched.c28
-rw-r--r--drivers/block/elevator.c19
-rw-r--r--drivers/block/ll_rw_blk.c16
-rw-r--r--include/linux/elevator.h6
4 files changed, 41 insertions, 28 deletions
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index 462dcb346c35..53890b484ea3 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -138,7 +138,7 @@ deadline_find_hash(struct deadline_data *dd, sector_t offset)
}
static int
-deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
+deadline_merge(request_queue_t *q, struct list_head **insert, struct bio *bio)
{
struct deadline_data *dd = q->elevator.elevator_data;
const int data_dir = bio_data_dir(bio);
@@ -150,9 +150,11 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
/*
* try last_merge to avoid going to hash
*/
- ret = elv_try_last_merge(q, req, bio);
- if (ret != ELEVATOR_NO_MERGE)
+ ret = elv_try_last_merge(q, bio);
+ if (ret != ELEVATOR_NO_MERGE) {
+ *insert = q->last_merge;
goto out;
+ }
/*
* see if the merge hash can satisfy a back merge
@@ -161,12 +163,15 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
if (elv_rq_merge_ok(__rq, bio)) {
- *req = __rq;
+ *insert = &__rq->queuelist;
ret = ELEVATOR_BACK_MERGE;
goto out;
}
}
+ /*
+ * scan list from back to find insertion point.
+ */
entry = sort_list = &dd->sort_list[data_dir];
while ((entry = entry->prev) != sort_list) {
__rq = list_entry_rq(entry);
@@ -177,8 +182,8 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
if (!(__rq->flags & REQ_CMD))
continue;
- if (!*req && bio_rq_in_between(bio, __rq, sort_list))
- *req = __rq;
+ if (!*insert && bio_rq_in_between(bio, __rq, sort_list))
+ *insert = &__rq->queuelist;
if (__rq->flags & REQ_BARRIER)
break;
@@ -189,12 +194,21 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
if (__rq->sector - bio_sectors(bio) == bio->bi_sector) {
ret = elv_try_merge(__rq, bio);
if (ret != ELEVATOR_NO_MERGE) {
- *req = __rq;
+ *insert = &__rq->queuelist;
break;
}
}
}
+ /*
+ * no insertion point found, check the very front
+ */
+ if (!*insert && !list_empty(sort_list)) {
+ __rq = list_entry_rq(sort_list->next);
+ if (bio->bi_sector + bio_sectors(bio) < __rq->sector)
+ *insert = sort_list;
+ }
+
out:
return ret;
}
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 8d0349e46b9b..9237eec87ba4 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -136,8 +136,7 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio)
return ret;
}
-inline int elv_try_last_merge(request_queue_t *q, struct request **req,
- struct bio *bio)
+inline int elv_try_last_merge(request_queue_t *q, struct bio *bio)
{
int ret = ELEVATOR_NO_MERGE;
@@ -150,8 +149,8 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
if (!rq_mergeable(__rq))
q->last_merge = NULL;
- else if ((ret = elv_try_merge(__rq, bio)))
- *req = __rq;
+ else
+ ret = elv_try_merge(__rq, bio);
}
return ret;
@@ -162,15 +161,17 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
*
* See if we can find a request that this buffer can be coalesced with.
*/
-int elevator_noop_merge(request_queue_t *q, struct request **req,
+int elevator_noop_merge(request_queue_t *q, struct list_head **insert,
struct bio *bio)
{
struct list_head *entry = &q->queue_head;
struct request *__rq;
int ret;
- if ((ret = elv_try_last_merge(q, req, bio)))
+ if ((ret = elv_try_last_merge(q, bio))) {
+ *insert = q->last_merge;
return ret;
+ }
while ((entry = entry->prev) != &q->queue_head) {
__rq = list_entry_rq(entry);
@@ -182,7 +183,7 @@ int elevator_noop_merge(request_queue_t *q, struct request **req,
continue;
if ((ret = elv_try_merge(__rq, bio))) {
- *req = __rq;
+ *insert = &__rq->queuelist;
q->last_merge = &__rq->queuelist;
return ret;
}
@@ -240,12 +241,12 @@ int elevator_global_init(void)
return 0;
}
-int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio)
+int elv_merge(request_queue_t *q, struct list_head **entry, struct bio *bio)
{
elevator_t *e = &q->elevator;
if (e->elevator_merge_fn)
- return e->elevator_merge_fn(q, rq, bio);
+ return e->elevator_merge_fn(q, entry, bio);
return ELEVATOR_NO_MERGE;
}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 510c767c4364..13f769d27a5d 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -1583,7 +1583,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
spin_lock_irq(q->queue_lock);
again:
- req = NULL;
insert_here = NULL;
if (blk_queue_empty(q)) {
@@ -1593,10 +1592,13 @@ again:
if (barrier)
goto get_rq;
- el_ret = elv_merge(q, &req, bio);
+ el_ret = elv_merge(q, &insert_here, bio);
switch (el_ret) {
case ELEVATOR_BACK_MERGE:
+ req = list_entry_rq(insert_here);
+
BUG_ON(!rq_mergeable(req));
+
if (!q->back_merge_fn(q, req, bio)) {
insert_here = &req->queuelist;
break;
@@ -1611,7 +1613,10 @@ again:
goto out;
case ELEVATOR_FRONT_MERGE:
+ req = list_entry_rq(insert_here);
+
BUG_ON(!rq_mergeable(req));
+
if (!q->front_merge_fn(q, req, bio)) {
insert_here = req->queuelist.prev;
break;
@@ -1638,13 +1643,6 @@ again:
* elevator says don't/can't merge. get new request
*/
case ELEVATOR_NO_MERGE:
- /*
- * use elevator hints as to where to insert the
- * request. if no hints, just add it to the back
- * of the queue
- */
- if (req)
- insert_here = &req->queuelist;
break;
default:
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index b18faeef9955..5c6c7db6e97e 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -1,7 +1,7 @@
#ifndef _LINUX_ELEVATOR_H
#define _LINUX_ELEVATOR_H
-typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
+typedef int (elevator_merge_fn) (request_queue_t *, struct list_head **,
struct bio *);
typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
@@ -42,7 +42,7 @@ struct elevator_s
*/
extern void __elv_add_request(request_queue_t *, struct request *,
struct list_head *);
-extern int elv_merge(request_queue_t *, struct request **, struct bio *);
+extern int elv_merge(request_queue_t *, struct list_head **, struct bio *);
extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *);
extern void elv_merged_request(request_queue_t *, struct request *);
@@ -78,7 +78,7 @@ extern void elevator_exit(request_queue_t *, elevator_t *);
extern inline int bio_rq_in_between(struct bio *, struct request *, struct list_head *);
extern inline int elv_rq_merge_ok(struct request *, struct bio *);
extern inline int elv_try_merge(struct request *, struct bio *);
-extern inline int elv_try_last_merge(request_queue_t *, struct request **, struct bio *);
+extern inline int elv_try_last_merge(request_queue_t *, struct bio *);
/*
* Return values from elevator merger