From: Nick Piggin <piggin@cyberone.com.au>

Seeing as the previous unfair behaviour of the request allocator has gone, AS
is up the creek.

This patch implements a hint (Jens, I commandeered elv_may_queue) so that AS
can tell the request allocator to allocate a request even if there are none
left (the accounting is quite flexible and easily handles overallocations).

elv_may_queue semantics have changed from "the elevator does _not_ want
another request allocated" to "the elevator _insists_ that another request is
allocated".  I couldn't see any harm ;)

Now in practice, AS will only allow _1_ request over the limit, because as
soon as the request is sent to AS, it stops anticipating.

Anyway, with this and the previous patch, 64 dd's in parallel get around
about disk bandwidth (22MB/s).

With nr_requests == 4, I still see around 15MB/s.  Quite impressive.



 drivers/block/as-iosched.c |   15 +++++++++++++++
 drivers/block/elevator.c   |    2 +-
 drivers/block/ll_rw_blk.c  |    2 +-
 3 files changed, 17 insertions(+), 2 deletions(-)

diff -puN drivers/block/as-iosched.c~blk-as-hint drivers/block/as-iosched.c
--- 25/drivers/block/as-iosched.c~blk-as-hint	2003-06-15 01:56:30.000000000 -0700
+++ 25-akpm/drivers/block/as-iosched.c	2003-06-15 01:56:30.000000000 -0700
@@ -1641,6 +1641,20 @@ static int as_set_request(request_queue_
 	return 1;
 }
 
+static int as_may_queue(request_queue_t *q, int rw)
+{
+	struct as_data *ad = q->elevator.elevator_data;
+	struct as_io_context *aic;
+	if (ad->antic_status == ANTIC_WAIT_REQ ||
+			ad->antic_status == ANTIC_WAIT_NEXT) {
+		aic = get_as_io_context();
+		if (ad->as_io_context == aic)
+			return 1;
+	}
+
+	return 0;
+}
+
 static void as_exit(request_queue_t *q, elevator_t *e)
 {
 	struct as_data *ad = e->elevator_data;
@@ -1879,6 +1893,7 @@ elevator_t iosched_as = {
 	.elevator_latter_req_fn =	as_latter_request,
 	.elevator_set_req_fn =		as_set_request,
 	.elevator_put_req_fn =		as_put_request,
+	.elevator_may_queue_fn =	as_may_queue,
 	.elevator_init_fn =		as_init,
 	.elevator_exit_fn =		as_exit,
 
diff -puN drivers/block/elevator.c~blk-as-hint drivers/block/elevator.c
--- 25/drivers/block/elevator.c~blk-as-hint	2003-06-15 01:56:30.000000000 -0700
+++ 25-akpm/drivers/block/elevator.c	2003-06-15 01:56:30.000000000 -0700
@@ -368,7 +368,7 @@ int elv_may_queue(request_queue_t *q, in
 	if (e->elevator_may_queue_fn)
 		return e->elevator_may_queue_fn(q, rw);
 
-	return 1;
+	return 0;
 }
 
 void elv_completed_request(request_queue_t *q, struct request *rq)
diff -puN drivers/block/ll_rw_blk.c~blk-as-hint drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~blk-as-hint	2003-06-15 01:56:30.000000000 -0700
+++ 25-akpm/drivers/block/ll_rw_blk.c	2003-06-15 01:56:43.000000000 -0700
@@ -1325,7 +1325,7 @@ static struct request *get_request(reque
 	struct request_list *rl = &q->rq;
 
 	spin_lock_irq(q->queue_lock);
-	if (rl->count[rw] >= q->nr_requests || !elv_may_queue(q, rw)) {
+	if (rl->count[rw] >= q->nr_requests && !elv_may_queue(q, rw)) {
 		spin_unlock_irq(q->queue_lock);
 		goto out;
 	}

_