diff options
| author | Josef Bacik <josef@toxicpanda.com> | 2026-10-28 10:41:46 -0600 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2026-10-29 07:15:47 -0600 |
| commit | 10b249e9b05eed0c4c65b9b89dfc2cf33d68d19a (patch) | |
| tree | c139400e8fad61333efaa634c195d486f079d3c5 | |
| parent | 6c55f94317249bc195e197f6a8730c843e72ea8c (diff) | |
| download | linux-10b249e9b05eed0c4c65b9b89dfc2cf33d68d19a.tar.gz linux-10b249e9b05eed0c4c65b9b89dfc2cf33d68d19a.zip | |
blk-mq: free the bitmaps of tags in the SRCU callback
Commit ad0d05dbddc1 keeps struct blk_mq_tags and the requests until the
iterators under tags_srcu are gone, but the two bitmaps they walk are
still freed right away. When the number of hardware queues shrinks,
blk_mq_tagset_busy_iter() may be about to walk tags that
__blk_mq_update_nr_hw_queues() frees. sbitmap_free() clears the map
pointer, so that's a NULL dereference or a use-after-free, depending on
the timing.
Free the bitmaps with the rest in the callback.
Fixes: ad0d05dbddc1 ("blk-mq: Defer freeing of tags page_list to SRCU callback")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Link: https://patch.msgid.link/20261028164415.1262013-44-axboe@kernel.dk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
| -rw-r--r-- | block/blk-mq-tag.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 2b751bfa50e1..3515031b3226 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -611,17 +611,17 @@ static void blk_mq_free_tags_callback(struct rcu_head *head) kmemleak_free(page_address(page)); __free_pages(page, page->private); } + /* An iterator may walk the bitmaps for as long as it may see the tags */ + sbitmap_queue_free(&tags->bitmap_tags); + sbitmap_queue_free(&tags->breserved_tags); kfree(tags); } void blk_mq_free_tags(struct blk_mq_tags *tags) { - sbitmap_queue_free(&tags->bitmap_tags); - sbitmap_queue_free(&tags->breserved_tags); - /* if tags pages is not allocated yet, free tags directly */ if (list_empty(&tags->page_list)) { - kfree(tags); + blk_mq_free_tags_callback(&tags->rcu_head); return; } |
