| From c3b4afca7023b5aa0531912364246e67f79b3010 Mon Sep 17 00:00:00 2001 |
| From: Ming Lei <tom.leiming@gmail.com> |
| Date: Thu, 4 Jun 2015 22:25:04 +0800 |
| Subject: blk-mq: free hctx->ctxs in queue's release handler |
| |
| From: Ming Lei <tom.leiming@gmail.com> |
| |
| commit c3b4afca7023b5aa0531912364246e67f79b3010 upstream. |
| |
| 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], 6cd18e711dd8075 (block: destroy bdi before blockdev is |
| unregistered) |
| |
| Reported-by: Stefan Seyfried <stefan.seyfried@googlemail.com> |
| Cc: NeilBrown <neilb@suse.de> |
| Cc: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Ming Lei <tom.leiming@gmail.com> |
| Signed-off-by: Jens Axboe <axboe@fb.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| block/blk-mq.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/block/blk-mq.c |
| +++ b/block/blk-mq.c |
| @@ -1589,6 +1589,7 @@ static int blk_mq_hctx_notify(void *data |
| return NOTIFY_OK; |
| } |
| |
| +/* hctx->ctxs will be freed in queue's release handler */ |
| static void blk_mq_exit_hctx(struct request_queue *q, |
| struct blk_mq_tag_set *set, |
| struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx) |
| @@ -1607,7 +1608,6 @@ static void blk_mq_exit_hctx(struct requ |
| |
| blk_mq_unregister_cpu_notifier(&hctx->cpu_notifier); |
| blk_free_flush_queue(hctx->fq); |
| - kfree(hctx->ctxs); |
| blk_mq_free_bitmap(&hctx->ctx_map); |
| } |
| |
| @@ -1873,8 +1873,12 @@ void blk_mq_release(struct request_queue |
| unsigned int i; |
| |
| /* 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(q->queue_hw_ctx); |
| |