From: Nick Piggin 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) _