Commit c3b4afca authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe

blk-mq: free hctx->ctxs in queue's release handler

Now blk_cleanup_queue() can be called before calling
del_gendisk()[1], inside which hctx->ctxs is touched
from blk_mq_unregister_hctx(), but the variable has
been freed by blk_cleanup_queue() at that time.

So this patch moves freeing of hctx->ctxs into queue's
release handler for fixing the oops reported by Stefan.

[1], 6cd18e71 (block: destroy bdi before blockdev is
unregistered)
Reported-by: default avatarStefan Seyfried <stefan.seyfried@googlemail.com>
Cc: NeilBrown <neilb@suse.de>
Cc: Christoph Hellwig <hch@lst.de>
Cc: stable@vger.kernel.org (v4.0)
Signed-off-by: default avatarMing Lei <tom.leiming@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent d4a4f75c
...@@ -1600,6 +1600,7 @@ static int blk_mq_hctx_notify(void *data, unsigned long action, ...@@ -1600,6 +1600,7 @@ static int blk_mq_hctx_notify(void *data, unsigned long action,
return NOTIFY_OK; return NOTIFY_OK;
} }
/* hctx->ctxs will be freed in queue's release handler */
static void blk_mq_exit_hctx(struct request_queue *q, static void blk_mq_exit_hctx(struct request_queue *q,
struct blk_mq_tag_set *set, struct blk_mq_tag_set *set,
struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx) struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
...@@ -1618,7 +1619,6 @@ static void blk_mq_exit_hctx(struct request_queue *q, ...@@ -1618,7 +1619,6 @@ static void blk_mq_exit_hctx(struct request_queue *q,
blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier); blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier);
blk_free_flush_queue(hctx->fq); blk_free_flush_queue(hctx->fq);
kfree(hctx->ctxs);
blk_mq_free_bitmap(&hctx->ctx_map); blk_mq_free_bitmap(&hctx->ctx_map);
} }
...@@ -1891,8 +1891,12 @@ void blk_mq_release(struct request_queue *q) ...@@ -1891,8 +1891,12 @@ void blk_mq_release(struct request_queue *q)
unsigned int i; unsigned int i;
/* hctx kobj stays in hctx */ /* hctx kobj stays in hctx */
queue_for_each_hw_ctx(q, hctx, i) queue_for_each_hw_ctx(q, hctx, i) {
if (!hctx)
continue;
kfree(hctx->ctxs);
kfree(hctx); kfree(hctx);
}
kfree(q->queue_hw_ctx); kfree(q->queue_hw_ctx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment