# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.817 -> 1.818 # drivers/block/ll_rw_blk.c 1.127 -> 1.128 # include/linux/blkdev.h 1.79 -> 1.80 # include/linux/blk.h 1.28 -> 1.29 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/10/28 axboe@burns.home.kernel.dk 1.818 # Two parts: # # o Always use list_del_init() on request queuelist, this allows us to # sanity check the integrity of the request on insertion and removal. # So we can complain loudly instead of silently corrupting memory. # # o Add references to requests. This is cheap, since we dont have to use # an atomic variable for it (all puts are inside queue lock). We've had # a bug in IDE for years where we want to inspect request state after # io completion, but this is not possible to do race free right now. # REQ_BLOCK_PC and sgio will need this too, for checking io residual # etc. This is not just a theoretical race, I've seen it happen. # -------------------------------------------- # diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Mon Oct 28 18:20:39 2002 +++ b/drivers/block/ll_rw_blk.c Mon Oct 28 18:20:39 2002 @@ -565,7 +565,7 @@ return; } - list_del(&rq->queuelist); + list_del_init(&rq->queuelist); rq->flags &= ~REQ_QUEUED; rq->tag = -1; @@ -649,7 +649,7 @@ if (rq->tag == -1) { printk("bad tag found on list\n"); - list_del(&rq->queuelist); + list_del_init(&rq->queuelist); rq->flags &= ~REQ_QUEUED; } else blk_queue_end_tag(q, rq); @@ -1132,7 +1132,7 @@ while (!list_empty(head)) { rq = list_entry(head->next, struct request, queuelist); - list_del(&rq->queuelist); + list_del_init(&rq->queuelist); kmem_cache_free(request_cachep, rq); i++; } @@ -1292,13 +1292,20 @@ if (!list_empty(&rl->free)) { rq = blkdev_free_rq(&rl->free); - list_del(&rq->queuelist); + list_del_init(&rq->queuelist); + rq->ref_count = 1; rl->count--; if (rl->count < queue_congestion_on_threshold()) set_queue_congested(q, rw); rq->flags = 0; rq->rq_status = RQ_ACTIVE; + rq->errors = 0; rq->special = NULL; + rq->buffer = NULL; + rq->data = NULL; + rq->sense = NULL; + rq->waiting = NULL; + rq->bio = rq->biotail = NULL; rq->q = q; rq->rl = rl; } @@ -1497,13 +1504,14 @@ __elv_add_request_pos(q, req, insert_here); } -/* - * Must be called with queue lock held and interrupts disabled - */ -void blk_put_request(struct request *req) +void __blk_put_request(request_queue_t *q, struct request *req) { struct request_list *rl = req->rl; - request_queue_t *q = req->q; + + if (unlikely(--req->ref_count)) + return; + if (unlikely(!q)) + return; req->rq_status = RQ_INACTIVE; req->q = NULL; @@ -1516,6 +1524,8 @@ if (rl) { int rw = 0; + BUG_ON(!list_empty(&req->queuelist)); + list_add(&req->queuelist, &rl->free); if (rl == &q->rq[WRITE]) @@ -1533,6 +1543,23 @@ } } +void blk_put_request(struct request *req) +{ + request_queue_t *q = req->q; + + /* + * if req->q isn't set, this request didnt originate from the + * block layer, so it's safe to just disregard it + */ + if (q) { + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __blk_put_request(q, req); + spin_unlock_irqrestore(q->queue_lock, flags); + } +} + /** * blk_congestion_wait - wait for a queue to become uncongested * @rw: READ or WRITE @@ -1591,7 +1618,7 @@ elv_merge_requests(q, req, next); blkdev_dequeue_request(next); - blk_put_request(next); + __blk_put_request(q, next); } } @@ -1784,7 +1811,7 @@ add_request(q, req, insert_here); out: if (freereq) - blk_put_request(freereq); + __blk_put_request(q, freereq); spin_unlock_irq(q->queue_lock); return 0; @@ -2069,7 +2096,7 @@ if (req->waiting) complete(req->waiting); - blk_put_request(req); + __blk_put_request(req); } int __init blk_dev_init(void) diff -Nru a/include/linux/blk.h b/include/linux/blk.h --- a/include/linux/blk.h Mon Oct 28 18:20:39 2002 +++ b/include/linux/blk.h Mon Oct 28 18:20:39 2002 @@ -44,7 +44,9 @@ static inline void blkdev_dequeue_request(struct request *req) { - list_del(&req->queuelist); + BUG_ON(list_empty(&req->queuelist)); + + list_del_init(&req->queuelist); if (req->q) elv_remove_request(req->q, req); diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Mon Oct 28 18:20:39 2002 +++ b/include/linux/blkdev.h Mon Oct 28 18:20:39 2002 @@ -26,6 +26,8 @@ struct list_head queuelist; /* looking for ->queue? you must _not_ * access it directly, use * blkdev_dequeue_request! */ + int ref_count; + void *elevator_private; unsigned char cmd[16];