From: Nick Piggin Comments, cleanups, sanity. drivers/block/as-iosched.c | 67 ++++++++++++++++++++++++++++----------------- 1 files changed, 43 insertions(+), 24 deletions(-) diff -puN drivers/block/as-iosched.c~as-np-1 drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-np-1 2003-03-16 13:59:01.000000000 -0800 +++ 25-akpm/drivers/block/as-iosched.c 2003-03-16 13:59:01.000000000 -0800 @@ -81,12 +81,14 @@ static unsigned long write_batch_expire */ static unsigned long antic_expire = HZ / 100; -#define ANTIC_OFF 0 /* Not anticipating (normal operation) */ -#define ANTIC_WAIT_REQ 1 /* The last read has not yet completed */ -#define ANTIC_WAIT_NEXT 2 /* Currently anticipating a request vs +enum anticipation_states { + ANTIC_OFF=0, /* Not anticipating (normal operation) */ + ANTIC_WAIT_REQ, /* The last read has not yet completed */ + ANTIC_WAIT_NEXT, /* Currently anticipating a request vs last read (which has completed) */ -#define ANTIC_FINISHED 3 /* Anticipating but have found a candidate + ANTIC_FINISHED, /* Anticipating but have found a candidate or timed out */ +}; /* * This is the per-process anticipatory I/O scheduler state. It is refcounted @@ -156,9 +158,13 @@ struct as_data { unsigned long antic_expire; }; -#define AS_RQ_NEW 0 -#define AS_RQ_QUEUED 1 -#define AS_RQ_DISPATCHED 2 +enum arq_states { + AS_RQ_NEW=0, /* New - not referenced and not on any lists */ + AS_RQ_QUEUED, /* In the request queue. It belongs to the + scheduler */ + AS_RQ_DISPATCHED, /* On the dispatch list. It belongs to the + driver now */ +}; /* * per-request data. @@ -909,21 +915,22 @@ static void as_antic_waitnext(struct as_ /* * This is executed in a "deferred" context. Either in a timer handler or - * in tasklet. It tries to move a request into the dispatch queue (which is - * not a queue at all! FIXME!) and then calls the driver's request_fn so the - * driver can submit that request. + * in tasklet. It calls the driver's request_fn so the driver can submit + * that request. IMPORTANT! This guy will reenter the elevator, so setup + * all queue global state before calling, and don't rely on any state over + * calls. + * + * FIXME! dispatch queue is not a queue at all! + * Andrew! as_queue_notready does not _try_ to move a request to dispatch + * list, in fact it tries not to! Unfortunately it sometimes must in order + * to guarantee elv_next_request will return !NULL after a ready indication. */ static void __as_antic_stop(struct as_data *ad) { - int status = ad->antic_status; + struct request_queue *q = ad->q; - ad->antic_status = ANTIC_FINISHED; - if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) { - struct request_queue *q = ad->q; - - if (!as_queue_notready(q)) - q->request_fn(q); - } + if (!as_queue_notready(q)) + q->request_fn(q); } /* @@ -946,8 +953,15 @@ static void __as_bottom_half(unsigned lo */ static void as_antic_timeout(unsigned long data) { + struct request_queue *q = (struct request_queue *)data; + struct as_data *ad = q->elevator.elevator_data; + int status = ad->antic_status; + ant_stats.timeouts++; - __as_bottom_half(data); + if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) { + ad->antic_status = ANTIC_FINISHED; + __as_bottom_half(data); + } } /* @@ -966,9 +980,14 @@ static void as_tasklet_handler(unsigned */ static void as_antic_stop(struct as_data *ad) { - if (ad->antic_status == ANTIC_WAIT_NEXT) - del_timer(&ad->antic_timer); - tasklet_schedule(&ad->tasklet); + int status = ad->antic_status; + + if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) { + if (status == ANTIC_WAIT_NEXT) + del_timer(&ad->antic_timer); + ad->antic_status = ANTIC_FINISHED; + tasklet_schedule(&ad->tasklet); + } } /* @@ -1119,8 +1138,8 @@ static void as_update_arq(struct as_data */ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq) { -// BUG_ON(ad->antic_status == ANTIC_WAIT_REQ || -// ad->antic_status == ANTIC_WAIT_NEXT); + BUG_ON(ad->antic_status == ANTIC_WAIT_REQ || + ad->antic_status == ANTIC_WAIT_NEXT); if (!ad->as_io_context) /* _