Skip to content

Commit 157f377

Browse files
committed
block: directly insert blk-mq request from blk_insert_cloned_request()
A NULL pointer crash was reported for the case of having the BFQ IO scheduler attached to the underlying blk-mq paths of a DM multipath device. The crash occured in blk_mq_sched_insert_request()'s call to e->type->ops.mq.insert_requests(). Paolo Valente correctly summarized why the crash occured with: "the call chain (dm_mq_queue_rq -> map_request -> setup_clone -> blk_rq_prep_clone) creates a cloned request without invoking e->type->ops.mq.prepare_request for the target elevator e. The cloned request is therefore not initialized for the scheduler, but it is however inserted into the scheduler by blk_mq_sched_insert_request." All said, a request-based DM multipath device's IO scheduler should be the only one used -- when the original requests are issued to the underlying paths as cloned requests they are inserted directly in the underlying dispatch queue(s) rather than through an additional elevator. But commit bd166ef ("blk-mq-sched: add framework for MQ capable IO schedulers") switched blk_insert_cloned_request() from using blk_mq_insert_request() to blk_mq_sched_insert_request(). Which incorrectly added elevator machinery into a call chain that isn't supposed to have any. To fix this introduce a blk-mq private blk_mq_request_bypass_insert() that blk_insert_cloned_request() calls to insert the request without involving any elevator that may be attached to the cloned request's request_queue. Fixes: bd166ef ("blk-mq-sched: add framework for MQ capable IO schedulers") Cc: [email protected] Reported-by: Bart Van Assche <[email protected]> Tested-by: Mike Snitzer <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent be1c704 commit 157f377

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

block/blk-core.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2342,7 +2342,12 @@ blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *
23422342
if (q->mq_ops) {
23432343
if (blk_queue_io_stat(q))
23442344
blk_account_io_start(rq, true);
2345-
blk_mq_sched_insert_request(rq, false, true, false, false);
2345+
/*
2346+
* Since we have a scheduler attached on the top device,
2347+
* bypass a potential scheduler on the bottom device for
2348+
* insert.
2349+
*/
2350+
blk_mq_request_bypass_insert(rq);
23462351
return BLK_STS_OK;
23472352
}
23482353

block/blk-mq.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,22 @@ void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
14011401
blk_mq_hctx_mark_pending(hctx, ctx);
14021402
}
14031403

1404+
/*
1405+
* Should only be used carefully, when the caller knows we want to
1406+
* bypass a potential IO scheduler on the target device.
1407+
*/
1408+
void blk_mq_request_bypass_insert(struct request *rq)
1409+
{
1410+
struct blk_mq_ctx *ctx = rq->mq_ctx;
1411+
struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(rq->q, ctx->cpu);
1412+
1413+
spin_lock(&hctx->lock);
1414+
list_add_tail(&rq->queuelist, &hctx->dispatch);
1415+
spin_unlock(&hctx->lock);
1416+
1417+
blk_mq_run_hw_queue(hctx, false);
1418+
}
1419+
14041420
void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
14051421
struct list_head *list)
14061422

block/blk-mq.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
5454
*/
5555
void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
5656
bool at_head);
57+
void blk_mq_request_bypass_insert(struct request *rq);
5758
void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
5859
struct list_head *list);
5960

0 commit comments

Comments
 (0)