diff options
| -rw-r--r-- | drivers/block/deadline-iosched.c | 28 | ||||
| -rw-r--r-- | drivers/block/elevator.c | 19 | ||||
| -rw-r--r-- | drivers/block/ll_rw_blk.c | 16 | ||||
| -rw-r--r-- | include/linux/elevator.h | 6 |
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 |
