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

This patch is on top of 2.5.68+rq-dyn-alloc-6 (I'll send
rq-dyn-alloc-6 if you want it).

I had managed to trigger a lockup _every_ time on bootup
while using BLKDEV_MIN_RQ = BLKDEV_MAX_RQ = 1, so I worked
from there. This patch gets that case working, and passes
lots of disk IO stressing with MIN = 4, MAX = 128.

I have not always been able to easily run into the lockup
however, so maybe its still there.

The last two hunks of the patch are the ones which seem
to have solved the problem, however the rest of it seems
legitimate to me.

Basically what I was seeing was that a request would be
allocated with __make_request, but it would never get to
ide_do_request. This was being caused I think by an unplug
racing with __make_request, the queue would be unplugged
before the request was put on it, thus causing
__make_request to not kick the queue _after_ putting the
request on it.

__make_request should probably be prettied up more, but
lets just see if this one works.



 drivers/block/ll_rw_blk.c |   80 ++++++++++++++++++++++++++++------------------
 1 files changed, 49 insertions(+), 31 deletions(-)

diff -puN drivers/block/ll_rw_blk.c~dynamic-request-allocation-fix drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~dynamic-request-allocation-fix	2003-04-28 23:59:42.000000000 -0700
+++ 25-akpm/drivers/block/ll_rw_blk.c	2003-04-29 00:55:24.000000000 -0700
@@ -1159,7 +1159,7 @@ static int blk_init_free_list(request_qu
 	rl->count[READ] = BLKDEV_MAX_RQ;
 	rl->count[WRITE] = BLKDEV_MAX_RQ;
 
-	rl->rq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep);
+	rl->rq_pool = mempool_create(BLKDEV_MIN_RQ*2, mempool_alloc_slab, mempool_free_slab, request_cachep);
 
 	if (!rl->rq_pool)
 		return -ENOMEM;
@@ -1282,34 +1282,51 @@ static struct request *get_request(reque
 	struct request *rq = NULL;
 	struct request_list *rl = &q->rq;
 
-	if (!rl->count[rw])
-		return NULL;
+	spin_lock_irq(q->queue_lock);
+	BUG_ON(rl->count[rw] < 0);
+	if (rl->count[rw] == 0) {
+		spin_unlock_irq(q->queue_lock);
+		goto out;
+	}
+	rl->count[rw]--;
+	if (rl->count[rw] < queue_congestion_on_threshold())
+		set_queue_congested(q, rw);
+	spin_unlock_irq(q->queue_lock);
 
 	rq = blk_alloc_request(q, gfp_mask);
-	if (rq) {
+	if (!rq) {
 		spin_lock_irq(q->queue_lock);
-		rl->count[rw]--;
-		if (rl->count[rw] < queue_congestion_on_threshold())
-			set_queue_congested(q, rw);
+		rl->count[rw]++;
+		if (rl->count[rw] >= queue_congestion_off_threshold())
+			clear_queue_congested(q, rw);
 		spin_unlock_irq(q->queue_lock);
-
-		INIT_LIST_HEAD(&rq->queuelist);
-		rq->flags = 0;
-		rq->errors = 0;
-		rq->rq_status = RQ_ACTIVE;
-		rq->bio = rq->biotail = NULL;
-		rq->buffer = NULL;
-		rq->ref_count = 1;
-		rq->q = q;
-		rq->rl = rl;
-		rq->special = NULL;
-		rq->data = NULL;
-		rq->waiting = NULL;
-		rq->sense = NULL;
+		goto out;
 	}
+	
+	INIT_LIST_HEAD(&rq->queuelist);
+
+	/*
+	 * first three bits are identical in rq->flags and bio->bi_rw,
+	 * see bio.h and blkdev.h
+	 */
+	rq->flags = rw;
 
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->bio = rq->biotail = NULL;
+	rq->buffer = NULL;
+	rq->ref_count = 1;
+	rq->q = q;
+	rq->rl = rl;
+	rq->waiting = NULL;
+	rq->special = NULL;
+	rq->data = NULL;
+	rq->sense = NULL;
+
+out:
 	return rq;
 }
+
 /*
  * No available requests for this queue, unplug the device.
  */
@@ -1721,18 +1738,20 @@ again:
 	 * a free slot.
 	 */
 get_rq:
-	spin_unlock_irq(q->queue_lock);
 	if (freereq) {
 		req = freereq;
 		freereq = NULL;
-	} else if ((req = get_request(q, rw, GFP_ATOMIC)) == NULL) {
-		/*
-		 * READA bit set
-		 */
-		if (bio_flagged(bio, BIO_RW_AHEAD))
-			goto end_io;
-
-		freereq = get_request_wait(q, rw);
+	} else {
+		spin_unlock_irq(q->queue_lock);
+		if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
+			/*
+			 * READA bit set
+			 */
+			if (bio_flagged(bio, BIO_RW_AHEAD))
+				goto end_io;
+	
+			freereq = get_request_wait(q, rw);
+		}
 		goto again;
 	}
 
@@ -1760,7 +1779,6 @@ get_rq:
 	req->rq_disk = bio->bi_bdev->bd_disk;
 	req->start_time = jiffies;
 
-	spin_lock_irq(q->queue_lock);
 	add_request(q, req, insert_here);
 out:
 	if (freereq)

_