]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] fix elevator_linus accounting
authorJens Axboe <axboe@suse.de>
Mon, 16 Sep 2002 01:23:22 +0000 (18:23 -0700)
committerJens Axboe <axboe@burns.home.kernel.dk>
Mon, 16 Sep 2002 01:23:22 +0000 (18:23 -0700)
elevator_linus is seriously broken wrt accounting. Marcelo recently took
the patch to fix it in 2.4.20-pre, here's the 2.5 equiv.

Right now, we account merges as costly and seeks as not. Only thing that
prevents seek starvation is the aging scan. That is broken, very much
so. This patch fixes that to account merges and inserts differently. A
seek is ELV_LINUS_SEEK_COST more costly than a merge, currently that
define is at '16'. Doing the math on a disk, this sort of makes sense.

Defaults are read latency of 1024, which means 1024 merges or 64 seeks.
Writes are double that.

drivers/block/elevator.c
drivers/block/ll_rw_blk.c
include/linux/elevator.h

index d5290e3b3cc7dd715ef78fd6303621a9368dac1e..15bfca03f35b6e292a446fae474226471eaf4641 100644 (file)
@@ -177,14 +177,9 @@ int elevator_linus_merge(request_queue_t *q, struct request **req,
 
                if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
                        break;
-
-               /*
-                * simply "aging" of requests in queue
-                */
-               if (elv_linus_sequence(__rq)-- <= 0)
-                       break;
                if (!(__rq->flags & REQ_CMD))
                        continue;
+
                if (elv_linus_sequence(__rq) < bio_sectors(bio))
                        break;
 
@@ -200,24 +195,20 @@ int elevator_linus_merge(request_queue_t *q, struct request **req,
                }
        }
 
-       return ret;
-}
-
-void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int count)
-{
-       struct list_head *entry;
-
-       BUG_ON(req->q != q);
-
        /*
-        * second pass scan of requests that got passed over, if any
+        * if *req, it's either a seek or merge in the middle of the queue
         */
-       entry = &req->queuelist;
-       while ((entry = entry->next) != &q->queue_head) {
-               struct request *tmp;
-               tmp = list_entry_rq(entry);
-               elv_linus_sequence(tmp) -= count;
+       if (*req) {
+               struct list_head *entry = &(*req)->queuelist;
+               int cost = ret ? 1 : ELV_LINUS_SEEK_COST;
+
+               while ((entry = entry->next) != &q->queue_head) {
+                       __rq = list_entry_rq(entry);
+                       elv_linus_sequence(__rq) -= cost;
+               }
        }
+
+       return ret;
 }
 
 void elevator_linus_merge_req(request_queue_t *q, struct request *req,
@@ -260,8 +251,8 @@ int elevator_linus_init(request_queue_t *q, elevator_t *e)
        if (!latency)
                return -ENOMEM;
 
-       latency[READ] = 8192;
-       latency[WRITE] = 16384;
+       latency[READ] = 1024;
+       latency[WRITE] = 2048;
 
        e->elevator_data = latency;
        return 0;
@@ -355,15 +346,6 @@ int elevator_global_init(void)
        return 0;
 }
 
-void elv_merge_cleanup(request_queue_t *q, struct request *rq,
-                      int nr_sectors)
-{
-       elevator_t *e = &q->elevator;
-
-       if (e->elevator_merge_cleanup_fn)
-               e->elevator_merge_cleanup_fn(q, rq, nr_sectors);
-}
-
 int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio)
 {
        elevator_t *e = &q->elevator;
@@ -460,7 +442,6 @@ inline struct list_head *elv_get_sort_head(request_queue_t *q,
 
 elevator_t elevator_linus = {
        elevator_merge_fn:              elevator_linus_merge,
-       elevator_merge_cleanup_fn:      elevator_linus_merge_cleanup,
        elevator_merge_req_fn:          elevator_linus_merge_req,
        elevator_next_req_fn:           elevator_noop_next_request,
        elevator_add_req_fn:            elevator_linus_add_request,
index b7765eb5a55007ea1c062fb83f3495763bb2defa..e95f7f0808f904048c98e78a9e1e89d1a0ddda6c 100644 (file)
@@ -1508,7 +1508,6 @@ again:
                        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;
@@ -1532,7 +1531,6 @@ again:
                        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;
index 5730a5bd5a7851ae4046509824da841c2940d7cc..e98168f92e674a027750dc19ab5619fcf9e0bd2b 100644 (file)
@@ -4,8 +4,6 @@
 typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
                                 struct bio *);
 
-typedef void (elevator_merge_cleanup_fn) (request_queue_t *, struct request *, int);
-
 typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
 
 typedef struct request *(elevator_next_req_fn) (request_queue_t *);
@@ -21,7 +19,6 @@ typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
 struct elevator_s
 {
        elevator_merge_fn *elevator_merge_fn;
-       elevator_merge_cleanup_fn *elevator_merge_cleanup_fn;
        elevator_merge_req_fn *elevator_merge_req_fn;
 
        elevator_next_req_fn *elevator_next_req_fn;
@@ -42,7 +39,6 @@ struct elevator_s
  */
 extern void __elv_add_request(request_queue_t *, struct request *,
                              struct list_head *);
-extern void elv_merge_cleanup(request_queue_t *, struct request *, int);
 extern int elv_merge(request_queue_t *, struct request **, struct bio *);
 extern void elv_merge_requests(request_queue_t *, struct request *,
                               struct request *);
@@ -61,6 +57,7 @@ extern elevator_t elevator_noop;
  */
 extern elevator_t elevator_linus;
 #define elv_linus_sequence(rq) ((long)(rq)->elevator_private)
+#define ELV_LINUS_SEEK_COST    16
 
 /*
  * use the /proc/iosched interface, all the below is history ->