From: Nick Piggin This patch converts AS over to the completion notifier. Works OK on IDE disk here. Would be interesting with SCSI, TCQ, CDROMs (my IDE CDROM doesn't think its a valid block device in mm3, and complains its unable to identify the CD-ROM format), and that POWER4 box which crashed running hwscan (or something). It has some very ugly looking debug checks which should turn up problems pretty quickly. It would be an idea to also keep an eye on nr_as_io_requests to make sure they aren't leaking. Andrew be sure to reenable the thinktime stuff when you test this! drivers/block/as-iosched.c | 64 +++++++++++++++++++++++++++++++++++++-------- 1 files changed, 54 insertions(+), 10 deletions(-) diff -puN drivers/block/as-iosched.c~as-use-completion drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-use-completion 2003-04-17 22:12:14.000000000 -0700 +++ 25-akpm/drivers/block/as-iosched.c 2003-04-17 22:12:14.000000000 -0700 @@ -131,6 +131,10 @@ struct as_data { unsigned long fifo_expire[2]; unsigned long batch_expire[2]; unsigned long antic_expire; + + int read_outstanding; /* DEBUG the completion notifier */ + int write_outstanding; + int quiet; }; #define list_entry_fifo(ptr) list_entry((ptr), struct as_rq, fifo) @@ -859,17 +863,41 @@ static void as_update_arq(struct as_data } /* - * as_complete_arq is to be called when a request has completed and returned - * something to the requesting process, be it an error or data. + * as_completed_request is to be called when a request has completed and + * returned something to the requesting process, be it an error or data. */ -static void as_complete_arq(struct as_data *ad, struct as_rq *arq) +static void as_completed_request(request_queue_t *q, struct request *rq) { + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(rq); struct as_io_context *aic = arq->as_io_context; + + arq->state = AS_RQ_NEW; + + if (unlikely(!blk_fs_request(rq) || rq->flags & REQ_HARDBARRIER)) { + WARN_ON(aic); + return; + } + + if (rq_data_dir(rq) == READ) { + ad->read_outstanding--; + if (!ad->quiet && ad->read_outstanding < 0) { + WARN_ON(1); + ad->quiet = 1; + } + } else { + ad->write_outstanding--; + if (!ad->quiet && ad->write_outstanding < 0) { + WARN_ON(1); + ad->quiet = 1; + } + } + if (!aic) return; if (rq_data_dir(arq->request) == READ) { - set_bit(AS_TASK_IORUNNING, &arq->as_io_context->state); + set_bit(AS_TASK_IORUNNING, &aic->state); aic->last_end_request = jiffies; } aic->last_data_dir = rq_data_dir(arq->request); @@ -885,6 +913,8 @@ static void as_complete_arq(struct as_da as_antic_waitnext(ad); } } + + put_as_io_context(&arq->as_io_context); } /* @@ -961,7 +991,6 @@ static void as_remove_dispatched_request */ static void as_remove_request(request_queue_t *q, struct request *rq) { - struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(rq); if (unlikely(!blk_fs_request(rq) || rq->flags & REQ_HARDBARRIER)) @@ -972,10 +1001,6 @@ static void as_remove_request(request_qu as_remove_queued_request(q, rq); else as_remove_dispatched_request(q, rq); - - as_complete_arq(ad, arq); - arq->state = AS_RQ_NEW; - put_as_io_context(&arq->as_io_context); } } @@ -1168,6 +1193,7 @@ static struct request *as_next_request(r return rq; } +extern int queue_nr_requests; /* DEBUG completion notifier */ /* * add arq to rbtree and fifo */ @@ -1175,6 +1201,23 @@ static void as_add_request(struct as_dat { const int data_dir = rq_data_dir(arq->request); + struct request_list *rl = ad->q->rq + data_dir; + int nr = queue_nr_requests - rl->count; + + if (data_dir == READ) { + ad->read_outstanding++; + if (!ad->quiet && ad->read_outstanding > nr) { + WARN_ON(1); + ad->quiet = 1; + } + } else { + ad->write_outstanding++; + if (!ad->quiet && ad->write_outstanding > nr) { + WARN_ON(1); + ad->quiet = 1; + } + } + arq->as_io_context = get_as_io_context(); if (arq->as_io_context) { @@ -1412,7 +1455,7 @@ as_merged_requests(request_queue_t *q, s * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); - put_as_io_context(&anext->as_io_context); +/* put_as_io_context(&anext->as_io_context); no need to do this because as_completed_request takes care of it */ } /* @@ -1695,6 +1738,7 @@ elevator_t iosched_as = { .elevator_add_req_fn = as_insert_request, .elevator_remove_req_fn = as_remove_request, .elevator_queue_empty_fn = as_queue_empty, + .elevator_completed_req_fn = as_completed_request, .elevator_former_req_fn = as_former_request, .elevator_latter_req_fn = as_latter_request, .elevator_init_fn = as_init, _