Commit 88c42974 authored by Jens Axboe's avatar Jens Axboe Committed by Jens Axboe

[PATCH] fix elevator_linus accounting

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.
parent 33ddb687
......@@ -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;
if (*req) {
struct list_head *entry = &(*req)->queuelist;
int cost = ret ? 1 : ELV_LINUS_SEEK_COST;
while ((entry = entry->next) != &q->queue_head) {
struct request *tmp;
tmp = list_entry_rq(entry);
elv_linus_sequence(tmp) -= count;
__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,
......
......@@ -1508,7 +1508,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
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 @@ static int __make_request(request_queue_t *q, struct bio *bio)
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;
......
......@@ -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 ->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment