diff -urN -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.5.28/drivers/block/elevator.c linux/drivers/block/elevator.c --- /opt/kernel/linux-2.5.28/drivers/block/elevator.c Wed Jul 24 23:03:30 2002 +++ linux/drivers/block/elevator.c Fri Jul 26 11:05:00 2002 @@ -220,7 +220,8 @@ } } -void elevator_linus_merge_req(struct request *req, struct request *next) +void elevator_linus_merge_req(request_queue_t *q, struct request *req, + struct request *next) { if (elv_linus_sequence(next) < elv_linus_sequence(req)) elv_linus_sequence(req) = elv_linus_sequence(next); @@ -232,6 +233,9 @@ elevator_t *e = &q->elevator; int lat = 0, *latency = e->elevator_data; + if (!insert_here) + insert_here = q->queue_head.prev; + if (!(rq->flags & REQ_BARRIER)) lat = latency[rq_data_dir(rq)]; @@ -318,7 +322,7 @@ struct request *elevator_noop_next_request(request_queue_t *q) { - if (!blk_queue_empty(q)) + if (!list_empty(&q->queue_head)) return list_entry_rq(q->queue_head.next); return NULL; @@ -376,7 +380,7 @@ elevator_t *e = &q->elevator; if (e->elevator_merge_req_fn) - e->elevator_merge_req_fn(rq, next); + e->elevator_merge_req_fn(q, rq, next); } /* @@ -433,6 +437,27 @@ e->elevator_remove_req_fn(q, rq); } +int elv_queue_empty(request_queue_t *q) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_queue_empty_fn) + return e->elevator_queue_empty_fn(q); + + return list_empty(&q->queue_head); +} + +inline struct list_head *elv_get_sort_head(request_queue_t *q, + struct request *rq) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_get_sort_head_fn) + return e->elevator_get_sort_head_fn(q, rq); + + return &q->queue_head; +} + elevator_t elevator_linus = { elevator_merge_fn: elevator_linus_merge, elevator_merge_cleanup_fn: elevator_linus_merge_cleanup, diff -urN -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.5.28/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- /opt/kernel/linux-2.5.28/drivers/block/ll_rw_blk.c Wed Jul 24 23:03:20 2002 +++ linux/drivers/block/ll_rw_blk.c Fri Jul 26 12:25:14 2002 @@ -1350,7 +1354,6 @@ if (rq_data_dir(req) != rq_data_dir(next) || !kdev_same(req->rq_dev, next->rq_dev) - || req->nr_sectors + next->nr_sectors > q->max_sectors || next->waiting || next->special) return; @@ -1361,15 +1364,14 @@ * counts here. */ if (q->merge_requests_fn(q, req, next)) { - elv_merge_requests(q, req, next); - - blkdev_dequeue_request(next); - req->biotail->bi_next = next->bio; req->biotail = next->biotail; req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; + elv_merge_requests(q, req, next); + + blkdev_dequeue_request(next); blkdev_release_request(next); } } @@ -1377,16 +1379,18 @@ static inline void attempt_back_merge(request_queue_t *q, struct request *rq) { struct list_head *next = rq->queuelist.next; + struct list_head *sort_head = elv_get_sort_head(q, rq); - if (next != &q->queue_head) + if (next != sort_head) attempt_merge(q, rq, list_entry_rq(next)); } static inline void attempt_front_merge(request_queue_t *q, struct request *rq) { struct list_head *prev = rq->queuelist.prev; + struct list_head *sort_head = elv_get_sort_head(q, rq); - if (prev != &q->queue_head) + if (prev != sort_head) attempt_merge(q, list_entry_rq(prev), rq); } @@ -1446,7 +1450,7 @@ spin_lock_irq(q->queue_lock); again: req = NULL; - insert_here = q->queue_head.prev; + insert_here = NULL; if (blk_queue_empty(q)) { blk_plug_device(q); @@ -1464,11 +1468,10 @@ break; } - elv_merge_cleanup(q, req, nr_sectors); - req->biotail->bi_next = bio; req->biotail = bio; req->nr_sectors = req->hard_nr_sectors += nr_sectors; + elv_merge_cleanup(q, req, nr_sectors); drive_stat_acct(req, nr_sectors, 0); attempt_back_merge(q, req); goto out; @@ -1480,8 +1483,6 @@ break; } - elv_merge_cleanup(q, req, nr_sectors); - bio->bi_next = req->bio; req->bio = bio; /* @@ -1494,6 +1495,7 @@ req->hard_cur_sectors = cur_nr_sectors; req->sector = req->hard_sector = sector; req->nr_sectors = req->hard_nr_sectors += nr_sectors; + elv_merge_cleanup(q, req, nr_sectors); drive_stat_acct(req, nr_sectors, 0); attempt_front_merge(q, req); goto out; @@ -1562,9 +1564,7 @@ req->buffer = bio_data(bio); /* see ->buffer comment above */ req->waiting = NULL; req->bio = req->biotail = bio; - if (bio->bi_bdev) - req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); - else req->rq_dev = NODEV; + req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); add_request(q, req, insert_here); out: if (freereq) diff -urN -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.5.28/include/linux/elevator.h linux/include/linux/elevator.h --- /opt/kernel/linux-2.5.28/include/linux/elevator.h Wed Jul 24 23:03:18 2002 +++ linux/include/linux/elevator.h Fri Jul 26 11:10:58 2002 @@ -6,13 +6,14 @@ typedef void (elevator_merge_cleanup_fn) (request_queue_t *, struct request *, int); -typedef void (elevator_merge_req_fn) (struct request *, struct request *); +typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *); typedef struct request *(elevator_next_req_fn) (request_queue_t *); typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *); typedef int (elevator_queue_empty_fn) (request_queue_t *); typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); +typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *); typedef int (elevator_init_fn) (request_queue_t *, elevator_t *); typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *); @@ -28,6 +29,7 @@ elevator_remove_req_fn *elevator_remove_req_fn; elevator_queue_empty_fn *elevator_queue_empty_fn; + elevator_get_sort_head_fn *elevator_get_sort_head_fn; elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; @@ -45,6 +47,8 @@ extern void elv_merge_requests(request_queue_t *, struct request *, struct request *); extern void elv_remove_request(request_queue_t *, struct request *); +extern int elv_queue_empty(request_queue_t *); +extern inline struct list_head *elv_get_sort_head(request_queue_t *, struct request *); /* * noop I/O scheduler. always merges, always inserts new request at tail @@ -72,6 +82,9 @@ extern int elevator_init(request_queue_t *, elevator_t *, elevator_t); 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 *); /* * Return values from elevator merger