From: Jens Axboe Here's a quickie that limits the queue depth to 1 by default, changable in sysfs. There's room for improvement, if you want to play with things like increasing the depth when anticipation doesn't work anyways. Cc: Nick Piggin Signed-off-by: Andrew Morton --- drivers/block/as-iosched.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 50 insertions(+) diff -puN drivers/block/as-iosched.c~as-limit-queue-depth drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-limit-queue-depth 2005-05-03 20:53:53.000000000 -0700 +++ 25-akpm/drivers/block/as-iosched.c 2005-05-03 20:53:53.000000000 -0700 @@ -59,6 +59,11 @@ #define default_antic_expire ((HZ / 150) ? HZ / 150 : 1) /* + * max in-flight at the hardware level + */ +#define default_queue_depth (1) + +/* * Keep track of up to 20ms thinktimes. We can go as big as we like here, * however huge values tend to interfere and not decay fast enough. A program * might be in a non-io phase of operation. Waiting on user input for example, @@ -126,6 +131,9 @@ struct as_data { int ioc_finished; /* IO associated with io_context is finished */ int nr_dispatched; + unsigned long queue_depth; + int in_flight; + /* * settings that change how the i/o scheduler behaves */ @@ -175,6 +183,7 @@ struct as_rq { unsigned long expires; unsigned int is_sync; + unsigned int in_flight; enum arq_state state; }; @@ -1018,6 +1027,13 @@ out_ioc: put_io_context(arq->io_context); out: arq->state = AS_RQ_POSTSCHED; + + if (arq->in_flight) { + WARN_ON(!ad->in_flight); + + arq->in_flight = 0; + ad->in_flight--; + } } /* @@ -1363,6 +1379,7 @@ static struct request *as_next_request(r { struct as_data *ad = q->elevator->elevator_data; struct request *rq = NULL; + struct as_rq *arq; /* * if there are still requests on the dispatch queue, grab the first @@ -1370,6 +1387,24 @@ static struct request *as_next_request(r if (!list_empty(ad->dispatch) || as_dispatch_request(ad)) rq = list_entry_rq(ad->dispatch->next); + /* + * if no request was available, or if this isn't a normal fs request + * just pass that to the driver + */ + if (!rq || ((arq = RQ_DATA(rq)) == NULL) || !blk_fs_request(rq)) + return rq; + + /* + * allow this request, if we are not exceeding the queue depth set + * by the user or if this request was already seen by the driver + */ + if (arq->in_flight) + return rq; + else if (ad->in_flight >= ad->queue_depth) + return NULL; + + arq->in_flight = 1; + ad->in_flight++; return rq; } @@ -1469,6 +1504,12 @@ static void as_deactivate_request(reques struct as_rq *arq = RQ_DATA(rq); if (arq) { + if (arq->in_flight) { + WARN_ON(!ad->in_flight); + + arq->in_flight = 0; + ad->in_flight--; + } if (arq->state == AS_RQ_REMOVED) { arq->state = AS_RQ_DISPATCHED; if (arq->io_context && arq->io_context->aic) @@ -1913,6 +1954,7 @@ static int as_init_queue(request_queue_t ad->antic_expire = default_antic_expire; ad->batch_expire[REQ_SYNC] = default_read_batch_expire; ad->batch_expire[REQ_ASYNC] = default_write_batch_expire; + ad->queue_depth = default_queue_depth; e->elevator_data = ad; ad->current_batch_expires = jiffies + ad->batch_expire[REQ_SYNC]; @@ -1976,6 +2018,7 @@ SHOW_FUNCTION(as_writeexpire_show, ad->f SHOW_FUNCTION(as_anticexpire_show, ad->antic_expire); SHOW_FUNCTION(as_read_batchexpire_show, ad->batch_expire[REQ_SYNC]); SHOW_FUNCTION(as_write_batchexpire_show, ad->batch_expire[REQ_ASYNC]); +SHOW_FUNCTION(as_queue_depth_show, ad->queue_depth); #undef SHOW_FUNCTION #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ @@ -1996,6 +2039,7 @@ STORE_FUNCTION(as_read_batchexpire_store &ad->batch_expire[REQ_SYNC], 0, INT_MAX); STORE_FUNCTION(as_write_batchexpire_store, &ad->batch_expire[REQ_ASYNC], 0, INT_MAX); +STORE_FUNCTION(as_queue_depth_store, &ad->queue_depth, 1, INT_MAX); #undef STORE_FUNCTION static struct as_fs_entry as_est_entry = { @@ -2027,6 +2071,11 @@ static struct as_fs_entry as_write_batch .show = as_write_batchexpire_show, .store = as_write_batchexpire_store, }; +static struct as_fs_entry as_queue_depth_entry = { + .attr = {.name = "queue_depth", .mode = S_IRUGO | S_IWUSR }, + .show = as_queue_depth_show, + .store = as_queue_depth_store, +}; static struct attribute *default_attrs[] = { &as_est_entry.attr, @@ -2035,6 +2084,7 @@ static struct attribute *default_attrs[] &as_anticexpire_entry.attr, &as_read_batchexpire_entry.attr, &as_write_batchexpire_entry.attr, + &as_queue_depth_entry.attr, NULL, }; _