Skip to content

Commit b01c8ac

Browse files
author
Ming Lei
committed
blk-mq: Defer freeing flush queue to SRCU callback
JIRA: https://issues.redhat.com/browse/RHEL-123480 commit 135b852 Author: Ming Lei <ming.lei@redhat.com> Date: Sat Aug 30 10:18:22 2025 +0800 blk-mq: Defer freeing flush queue to SRCU callback The freeing of the flush queue/request in blk_mq_exit_hctx() can race with tag iterators that may still be accessing it. To prevent a potential use-after-free, the deallocation should be deferred until after a grace period. With this way, we can replace the big tags->lock in tags iterator code path with srcu for solving the issue. This patch introduces an SRCU-based deferred freeing mechanism for the flush queue. The changes include: - Adding a `rcu_head` to `struct blk_flush_queue`. - Creating a new callback function, `blk_free_flush_queue_callback`, to handle the actual freeing. - Replacing the direct call to `blk_free_flush_queue()` in `blk_mq_exit_hctx()` with `call_srcu()`, using the `tags_srcu` instance to ensure synchronization with tag iterators. Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Ming Lei <ming.lei@redhat.com>
1 parent 9aab74e commit b01c8ac

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

block/blk-mq.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3912,6 +3912,14 @@ static void blk_mq_clear_flush_rq_mapping(struct blk_mq_tags *tags,
39123912
spin_unlock_irqrestore(&tags->lock, flags);
39133913
}
39143914

3915+
static void blk_free_flush_queue_callback(struct rcu_head *head)
3916+
{
3917+
struct blk_flush_queue *fq =
3918+
container_of(head, struct blk_flush_queue, rcu_head);
3919+
3920+
blk_free_flush_queue(fq);
3921+
}
3922+
39153923
/* hctx->ctxs will be freed in queue's release handler */
39163924
static void blk_mq_exit_hctx(struct request_queue *q,
39173925
struct blk_mq_tag_set *set,
@@ -3931,7 +3939,8 @@ static void blk_mq_exit_hctx(struct request_queue *q,
39313939
if (set->ops->exit_hctx)
39323940
set->ops->exit_hctx(hctx, hctx_idx);
39333941

3934-
blk_free_flush_queue(hctx->fq);
3942+
call_srcu(&set->tags_srcu, &hctx->fq->rcu_head,
3943+
blk_free_flush_queue_callback);
39353944
hctx->fq = NULL;
39363945

39373946
xa_erase(&q->hctx_table, hctx_idx);

block/blk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct blk_flush_queue {
3131
struct list_head flush_queue[2];
3232
unsigned long flush_data_in_flight;
3333
struct request *flush_rq;
34+
struct rcu_head rcu_head;
3435
};
3536

3637
bool is_flush_rq(struct request *req);

0 commit comments

Comments
 (0)