Patch from Nick Piggin 1. Changes request "ID" assignment to be more correct. Which ever process initiates the request will be the ID When two requests merge, we keep the ID of the first one initiated. Previously it would assign the ID whenever doing an "update" which included adding, but also meant any process merging. This probably won't make much difference because there probably aren't many workloads where inter-process mergeing is common. 2. Fixes a few other small deadline->as name things 3. Fixes logic so we don't choose the next request before setting "last_sector", thus using the old last_sector to choose. Also fix so we don't run the choose function twice every time. 4. Small optimisation in the choose function if both candidates are the same request 5. When adding a blk_fs_request, we'll only break anticipating if the request is added to the dispatch list (probably common). With this patch, the xterm -e true time in the presence of a sequential reader seems to be a linear function of read_expire. It still doesn't seem quite right and I would expect the xterm to do better. I'll keep looking into it. drivers/block/as-iosched.c | 67 +++++++++++++++++++++------------------------ 1 files changed, 32 insertions(+), 35 deletions(-) diff -puN drivers/block/as-iosched.c~as-update-1 drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-update-1 Mon Feb 24 15:09:20 2003 +++ 25-akpm/drivers/block/as-iosched.c Mon Feb 24 15:09:20 2003 @@ -171,6 +171,11 @@ static kmem_cache_t *arq_pool; #define RQ_DATA(rq) ((struct as_rq *) (rq)->elevator_private) +static inline unsigned long request_id(void) +{ + return (unsigned long)current->pid; +} + /* * the back merge hash support functions */ @@ -362,6 +367,8 @@ as_add_request(struct as_data *ad, struc { const int data_dir = rq_data_dir(arq->request); + arq->request_id = request_id(); + as_add_arq_rb(ad, arq); /* * set expire time (only used for reads) and add to fifo list @@ -473,10 +480,10 @@ as_merged_requests(request_queue_t *q, s { struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(req); - struct as_rq *dnext = RQ_DATA(next); + struct as_rq *anext = RQ_DATA(next); BUG_ON(!arq); - BUG_ON(!dnext); + BUG_ON(!anext); /* * reposition arq (this is the merged request) in hash, and in rbtree @@ -491,13 +498,14 @@ as_merged_requests(request_queue_t *q, s } /* - * if dnext expires before arq, assign its expire time to arq - * and move into dnext position (dnext will be deleted) in fifo + * if anext expires before arq, assign its expire time to arq + * and move into anext position (anext will be deleted) in fifo */ - if (!list_empty(&arq->fifo) && !list_empty(&dnext->fifo)) { - if (time_before(dnext->expires, arq->expires)) { - list_move(&arq->fifo, &dnext->fifo); - arq->expires = dnext->expires; + if (!list_empty(&arq->fifo) && !list_empty(&anext->fifo)) { + if (time_before(anext->expires, arq->expires)) { + list_move(&arq->fifo, &anext->fifo); + arq->expires = anext->expires; + arq->request_id = anext->request_id; } } @@ -527,23 +535,9 @@ static void as_move_request(struct as_data *ad, struct as_rq *arq) { const int data_dir = rq_data_dir(arq->request); - struct rb_node *rbnext = rb_next(&arq->rb_node); - struct rb_node *rbprev = rb_prev(&arq->rb_node); - struct as_rq *arq_next, *arq_prev; BUG_ON(!ON_RB(&arq->rb_node)); - if (rbprev) - arq_prev = rb_entry_arq(rbprev); - else - arq_prev = NULL; - - if (rbnext) - arq_next = rb_entry_arq(rbnext); - else - arq_next = as_find_first_arq(ad, data_dir); - ad->next_arq[data_dir] = as_choose_req(ad, arq_next, arq_prev); - ad->last_sector[data_dir] = arq->request->sector + arq->request->nr_sectors; if (data_dir == READ) @@ -614,10 +608,6 @@ static inline int as_batch_expired(struc * anticipatory scheduling functions follow */ -static inline unsigned long request_id(void) -{ - return (unsigned long)current->pid; -} static int as_queue_empty(request_queue_t *q); @@ -690,7 +680,7 @@ as_choose_req(struct as_data *ad, sector_t last, s1, s2, d1, d2; const sector_t maxback = MAXBACK; - if (arq1 == NULL) + if (arq1 == NULL || arq1 == arq2) return arq2; if (arq2 == NULL) return arq1; @@ -727,7 +717,7 @@ as_choose_req(struct as_data *ad, goto elevator_wrap; /* Found the deltas */ - if (d1 < d2) + if (d1 < d2) return arq1; else if (d2 < d1) return arq2; @@ -784,11 +774,7 @@ static void as_update_arq(struct as_data *ad, struct as_rq *arq) { const int data_dir = rq_data_dir(arq->request); - sector_t last = ad->last_sector[data_dir]; - sector_t this = arq->request->sector; - unsigned long delay = jiffies - ad->antic_start; - arq->request_id = request_id(); if (data_dir == READ) ant_stats.reads++; @@ -801,6 +787,11 @@ as_update_arq(struct as_data *ad, struct /* have we been anticipating this request? */ if (ad->antic_status != ANTIC_OFF && data_dir == READ && as_antic_req(ad, arq)) { + + /* statistics stuff */ + sector_t last = ad->last_sector[data_dir]; + sector_t this = arq->request->sector; + unsigned long delay = jiffies - ad->antic_start; long lba_offset; int neg; int log2; @@ -844,12 +835,17 @@ can_start_anticipation(struct as_data *a */ return 0; - if (ad->antic_status == ANTIC_WAIT && as_antic_expired(ad)) + if (ad->antic_status == ANTIC_WAIT && as_antic_expired(ad)) { /* * In this situation status should really be FINISHED, however * the timer hasn't had the chance to run yet. */ + del_timer(&ad->antic_timer); + ad->antic_status = ANTIC_FINISHED; + blk_remove_plug(arq->request->q); + schedule_work(&ad->antic_work); return 0; + } if (arq && as_antic_req(ad, arq)) /* @@ -1011,7 +1007,7 @@ static struct request *as_next_request(r struct request *rq = NULL; /* - * if there are still requests on the dispatch queue, grab the first one + * if there are still requests on the dispatch queue, grab the first */ if (!list_empty(ad->dispatch) || as_dispatch_request(q)) rq = list_entry_rq(ad->dispatch->next); @@ -1036,7 +1032,8 @@ as_insert_request(request_queue_t *q, st list_add(&rq->queuelist, insert_here); - if (rq_data_dir(rq) == READ && ad->antic_status != ANTIC_OFF) { + if (!list_empty(ad->dispatch) && rq_data_dir(rq) == READ + && ad->antic_status == ANTIC_WAIT) { del_timer(&ad->antic_timer); ad->antic_status = ANTIC_FINISHED; blk_remove_plug(q); _