From: Nick Piggin This goes on top of previous. It fixes a leak (search for "no need") - I'm not sure what was going on there, I think the semantics for elv_completed_request function might have changed. I surely put it there for a reason :P Anyway, it also changes a lot of stuff from: if (x) blah to: if (!x) { WARN return; } blah And it changes put_as_io_context so it no longer NULLs the target and catches double frees (of which there don't appear to be any). Adds a check to be sure nr_as_io_contexts is > 0. Don't have a check for the upper bound unfortunately. A decent invariant would be something like: nr_as_io_contexts <= total-reqs-for-all-queues + nr_threads. Which could be done quite easily. But anyway, it seems to not leak anymore. Please apply. I may have been a bit eager in my checks, but they are only WARNs... drivers/block/as-iosched.c | 69 +++++++++++++++++++++++++++++---------------- 1 files changed, 45 insertions(+), 24 deletions(-) diff -puN drivers/block/as-iosched.c~as-double-free-and-debug drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-double-free-and-debug 2003-06-11 19:49:20.000000000 -0700 +++ 25-akpm/drivers/block/as-iosched.c 2003-06-11 19:49:20.000000000 -0700 @@ -214,8 +214,9 @@ static void put_as_io_context(struct as_ return; BUG_ON(atomic_read(&aic->refcount) == 0); - *paic = NULL; + if (atomic_dec_and_test(&aic->refcount)) { + WARN_ON(atomic_read(&nr_as_io_requests) == 0); atomic_dec(&nr_as_io_requests); kfree(aic); } @@ -354,7 +355,12 @@ static inline void as_hot_arq_hash(struc struct request *rq = arq->request; struct list_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))]; - if (ON_HASH(arq) && arq->hash.prev != head) { + if (!ON_HASH(arq)) { + WARN_ON(1); + return; + } + + if (arq->hash.prev != head) { list_del(&arq->hash); list_add(&arq->hash, head); } @@ -462,10 +468,13 @@ static void as_add_arq_rb(struct as_data static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq) { - if (ON_RB(&arq->rb_node)) { - rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq)); - RB_CLEAR(&arq->rb_node); + if (!ON_RB(&arq->rb_node)) { + WARN_ON(1); + return; } + + rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq)); + RB_CLEAR(&arq->rb_node); } static struct request * @@ -1061,17 +1070,19 @@ static void as_remove_queued_request(req static void as_remove_dispatched_request(request_queue_t *q, struct request *rq) { struct as_rq *arq = RQ_DATA(rq); + struct as_io_context *aic; - if (arq) { - struct as_io_context *aic; + if (!arq) { + WARN_ON(1); + return; + } - WARN_ON(arq->state != AS_RQ_DISPATCHED); - WARN_ON(ON_RB(&arq->rb_node)); - aic = arq->as_io_context; - if (aic) { - WARN_ON(!atomic_read(&aic->nr_dispatched)); - atomic_dec(&aic->nr_dispatched); - } + WARN_ON(arq->state != AS_RQ_DISPATCHED); + WARN_ON(ON_RB(&arq->rb_node)); + aic = arq->as_io_context; + if (aic) { + WARN_ON(!atomic_read(&aic->nr_dispatched)); + atomic_dec(&aic->nr_dispatched); } } /* @@ -1086,12 +1097,15 @@ static void as_remove_request(request_qu if (unlikely(!blk_fs_request(rq))) return; - if (arq) { - if (ON_RB(&arq->rb_node)) - as_remove_queued_request(q, rq); - else - as_remove_dispatched_request(q, rq); + if (!arq) { + WARN_ON(1); + return; } + + if (ON_RB(&arq->rb_node)) + as_remove_queued_request(q, rq); + else + as_remove_dispatched_request(q, rq); } /* @@ -1165,7 +1179,11 @@ static void as_move_to_dispatch(struct a /* In case we have to anticipate after this */ copy_as_io_context(&ad->as_io_context, &arq->as_io_context); } else { - put_as_io_context(&ad->as_io_context); + if (ad->as_io_context) { + put_as_io_context(&ad->as_io_context); + ad->as_io_context = NULL; + } + if (ad->current_write_count != 0) ad->current_write_count--; } @@ -1563,7 +1581,7 @@ as_merged_requests(request_queue_t *q, s * kill knowledge of next, this one is a goner */ as_remove_queued_request(q, next); -/* put_as_io_context(&anext->as_io_context); no need to do this because as_completed_request takes care of it */ + put_as_io_context(&anext->as_io_context); } /* @@ -1591,10 +1609,13 @@ static void as_put_request(request_queue struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - mempool_free(arq, ad->arq_pool); - rq->elevator_private = NULL; + if (!arq) { + WARN_ON(1); + return; } + + mempool_free(arq, ad->arq_pool); + rq->elevator_private = NULL; } static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask) _