// insmod ./null_blk queue_mode=2 irqmode=2 completion_nsec=10000000000 [ 332.929595] null_blk: rq 00000000ecf12d66 timed out [ 336.036131] ------------[ cut here ]------------ [ 336.036139] refcount_t: underflow; use-after-free. [ 336.036155] WARNING: CPU: 0 PID: 0 at lib/refcount.c:28 refcount_warn_saturate+0xae/0xf0 [ 336.036407] RIP: 0010:refcount_warn_saturate+0xae/0xf0 [ 336.036467] Call Trace: [ 336.036470] <IRQ> [ 336.036476] blk_mq_free_request+0x140/0x150 [ 336.036487] blk_mq_end_request+0x129/0x140 [ 336.036496] end_cmd+0x30/0x80 [null_blk] [ 336.036516] ? null_complete_rq+0x20/0x20 [null_blk] [ 336.036532] null_cmd_timer_expired+0x12/0x20 [null_blk] [ 336.036546] __hrtimer_run_queues+0x10d/0x2a0 [ 336.036555] hrtimer_interrupt+0x109/0x220 [ 336.036561] ? sched_clock_cpu+0x16/0xd0 [ 336.036573] __sysvec_apic_timer_interrupt+0x69/0x120 [ 336.036581] sysvec_apic_timer_interrupt+0x77/0x90 [ 336.036593] </IRQ> [ 336.036596] asm_sysvec_apic_timer_interrupt+0x12/0x20 ... [ 336.036740] ---[ end trace bfb36b9c4f62fd9a ]--- [ 339.756204] null_blk: rq 0000000050397c34 timed out [ 339.756934] null_blk: module loaded In case of expiried NULL_IRQ_TIMER nullblk requests, first null_timeout_rq() does blk_mq_complete_request() dropping a ref and not removing killing cmd->timer, and then cmd->timer fires and gets underflow in null_cmd_timer_expired(). Cancel hrtimer on blk-mq request expiration. Signed-off-by: Pavel Begunkov <asml.silence@xxxxxxxxx> --- non-NULL_IRQ_TIMER may also need some patching. drivers/block/null_blk/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index d6c821d48090..a87c3359f357 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -1451,8 +1451,16 @@ static bool should_requeue_request(struct request *rq) static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res) { + struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq); + pr_info("rq %p timed out\n", rq); - blk_mq_complete_request(rq); + + if (cmd->nq->dev->irqmode == NULL_IRQ_TIMER) { + if (hrtimer_try_to_cancel(&cmd->timer) != -1) + blk_mq_complete_request(rq); + } else { + blk_mq_complete_request(rq); + } return BLK_EH_DONE; } -- 2.24.0