diff -urNp --exclude CVS --exclude BitKeeper x-ref/drivers/block/elevator.c x/drivers/block/elevator.c --- x-ref/drivers/block/elevator.c 2003-07-17 06:01:25.000000000 +0200 +++ x/drivers/block/elevator.c 2003-07-17 06:02:25.000000000 +0200 @@ -74,6 +74,30 @@ inline int bh_rq_in_between(struct buffe return 0; } +static int rq_mergeable(struct request *req, struct buffer_head *bh, + request_queue_t *q, int rw, int count, int max_sectors) +{ + if (q->head_active && !q->plugged) { + struct request *next; + next = blkdev_entry_next_request(&q->queue_head); + if (next == req) + return 0; + } + if (q->head_active) + return 0; + if (req->waiting) + return 0; + if (req->rq_dev != bh->b_rdev) + return 0; + if (req->cmd != rw) + return 0; + if (req->nr_sectors + count > max_sectors) + return 0; + if (bh_elv_seq(bh) != bh_elv_seq(req->bh)) + return 0; + + return 1; +} int elevator_linus_merge(request_queue_t *q, struct request **req, struct list_head * head, @@ -91,6 +115,25 @@ int elevator_linus_merge(request_queue_t entry = &q->atomic_head; real_head = entry; + /* + * check last merge hint + */ + if (q->last_merge) { + __rq = q->last_merge; + + if (rq_mergeable(__rq, bh, q, rw, count, max_sectors)) { + if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { + *req = __rq; + ret = ELEVATOR_BACK_MERGE; + goto out; + } else if (__rq->sector - count == bh->b_rsector) { + *req = __rq; + ret = ELEVATOR_FRONT_MERGE; + goto out; + } + } + } + while (!backmerge_only && (entry = entry->prev) != head) { __rq = blkdev_entry_to_request(entry); @@ -118,15 +161,18 @@ int elevator_linus_merge(request_queue_t if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { ret = ELEVATOR_BACK_MERGE; *req = __rq; + q->last_merge = __rq; break; } else if (__rq->sector - count == bh->b_rsector && !backmerge_only) { ret = ELEVATOR_FRONT_MERGE; __rq->elevator_sequence--; *req = __rq; + q->last_merge = __rq; break; } } +out: /* * account merge (ret != 0, cost is 1) or seeky insert (*req is set, * cost is ELV_LINUS_SEEK_COST @@ -148,6 +194,8 @@ void elevator_linus_merge_req(struct req { if (next->elevator_sequence < req->elevator_sequence) req->elevator_sequence = next->elevator_sequence; + if (req->q) + req->q->last_merge = req; } /* diff -urNp --exclude CVS --exclude BitKeeper x-ref/drivers/block/ll_rw_blk.c x/drivers/block/ll_rw_blk.c --- x-ref/drivers/block/ll_rw_blk.c 2003-07-17 06:01:25.000000000 +0200 +++ x/drivers/block/ll_rw_blk.c 2003-07-17 06:01:35.000000000 +0200 @@ -440,10 +440,18 @@ static void generic_plug_device(request_ */ static inline void __generic_unplug_device(request_queue_t *q) { + struct request *next; + if (q->plugged) { q->plugged = 0; - if (!list_empty(&q->queue_head)) + if (!list_empty(&q->queue_head)) { + next = blkdev_entry_next_request(&q->queue_head); + + if (next == q->last_merge) + q->last_merge = NULL; + q->request_fn(q); + } } } @@ -677,6 +685,7 @@ void blk_init_queue(request_queue_t * q, q->plug_tq.data = q; q->plugged = 0; q->can_throttle = 0; + q->last_merge = NULL; /* * These booleans describe the queue properties. We set the @@ -992,6 +1001,9 @@ static inline void add_request(request_q * inserted at elevator_merge time */ list_add(&req->queue, insert_here); + + if (!q->last_merge) + q->last_merge = req; } /* diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/linux/blk.h x/include/linux/blk.h --- x-ref/include/linux/blk.h 2003-07-17 06:01:20.000000000 +0200 +++ x/include/linux/blk.h 2003-07-17 06:01:27.000000000 +0200 @@ -86,6 +86,13 @@ void initrd_init(void); static inline void blkdev_dequeue_request(struct request * req) { + request_queue_t *q = req->q; + + if (q) { + if (q->last_merge == req || (q->head_active && q->last_merge == blkdev_next_request(req))) + q->last_merge = NULL; + } + list_del(&req->queue); } diff -urNp --exclude CVS --exclude BitKeeper x-ref/include/linux/blkdev.h x/include/linux/blkdev.h --- x-ref/include/linux/blkdev.h 2003-07-17 06:01:25.000000000 +0200 +++ x/include/linux/blkdev.h 2003-07-17 06:01:27.000000000 +0200 @@ -107,6 +107,7 @@ struct request_queue struct list_head queue_head; struct list_head atomic_head; elevator_t elevator; + struct request *last_merge; request_fn_proc * request_fn; merge_request_fn * back_merge_fn;