blk-flush: fix possibe deadlock when process nvme_timeout()#944
blk-flush: fix possibe deadlock when process nvme_timeout()#944blktests-ci[bot] wants to merge 1 commit into
Conversation
|
Upstream branch: 979c294 |
a7bb5c5 to
5e41a3b
Compare
|
Upstream branch: acb7500 |
1837d92 to
344bf73
Compare
5e41a3b to
c3a084b
Compare
|
Upstream branch: 9716c08 |
344bf73 to
6a345ca
Compare
c3a084b to
5f78e5d
Compare
|
Upstream branch: 2a2974b |
6a345ca to
d2059a6
Compare
5f78e5d to
e48f9db
Compare
|
Upstream branch: 062871f |
d2059a6 to
065e66f
Compare
199644a to
e6d9eb8
Compare
|
Upstream branch: 66affa3 |
065e66f to
d487453
Compare
e6d9eb8 to
7d8604f
Compare
|
Upstream branch: bade58e |
d487453 to
45c4cfe
Compare
7d8604f to
4cc45a3
Compare
|
Upstream branch: 4edcdef |
45c4cfe to
b663d19
Compare
4cc45a3 to
90ffd56
Compare
|
Upstream branch: dc59e4f |
There's when process nvme_timeout():
[ 206.734601][ T8184] nvme nvme0: I/O tag 512 (1200) opcode 0x0 (I/O Cmd) QID 3 timeout, aborting req_op:FLUSH(2) size:0
[ 206.736112][ C0] nvme nvme0: Abort status: 0x0
[ 208.094637][ T8184] nvme nvme0: I/O tag 512 (1200) opcode 0x0 (I/O Cmd) QID 3 timeout, reset controller
[root@localhost ~]# cat /proc/8184/stack
[<0>] msleep+0x37/0x50
[<0>] blk_mq_tagset_wait_completed_request+0x6f/0xe0
[<0>] nvme_cancel_tagset+0x79/0xa0
[<0>] nvme_dev_disable+0x55c/0x7e0
[<0>] nvme_timeout+0x25b/0x1530
[<0>] blk_mq_handle_expired+0x210/0x2c0
[<0>] bt_iter+0x2bb/0x360
[<0>] blk_mq_queue_tag_busy_iter+0x9f8/0x1f30
[<0>] blk_mq_timeout_work+0x5dc/0x7d0
[<0>] process_one_work+0xa08/0x1d00
[<0>] worker_thread+0x698/0xeb0
[<0>] kthread+0x408/0x540
[<0>] ret_from_fork+0xa4d/0xdd0
[<0>] ret_from_fork_asm+0x1a/0x30
Above issue may happen as follows:
nvme_timeout // tag 512 request's flush request the first timeout
iod->aborted = 1;
abort_req = nvme_alloc_request(dev->ctrl.admin_q, &cmd,
BLK_MQ_REQ_NOWAIT, NVME_QID_ANY); // Abort tag 512 flush request
blk_execute_rq_nowait(abort_req->q, NULL, abort_req, 0, abort_endio);
// Abort request completion, will no wait
....
****'abort_req' not complete***
....
nvme_timeout // tag 512 request's flush request the second timeout
if (!nvmeq->qid || (iod->flags & IOD_ABORTED))
nvme_req(req)->flags |= NVME_REQ_CANCELLED;
goto disable;
...
**** tag 512 request's flush request end ****
nvme_try_complete_req
blk_mq_complete_request_remote(req);
WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
...
nvme_end_req(req);
blk_mq_end_request(req, status);
__blk_mq_end_request(rq, error);
if (rq->end_io)
rq->end_io(rq, error);
flush_end_io(rq, error);
// The timeout process holds the reference count.
// so request keep MQ_RQ_COMPLETE state
if (!refcount_dec_and_test(&flush_rq->ref))
fq->rq_status = error;
return;
**** tag 512 flush request is MQ_RQ_COMPLETE state ****
disable:
nvme_dev_disable(dev, false);
nvme_cancel_tagset(&dev->ctrl);
blk_mq_tagset_busy_iter(&dev->tagset, nvme_cancel_request,
&dev->ctrl);
nvme_cancel_request
if (blk_mq_request_completed(req))
return true;
blk_mq_tagset_wait_completed_request(&dev->tagset);
while (true)
blk_mq_tagset_busy_iter(tagset,
blk_mq_tagset_count_completed_rqs, &count);
blk_mq_tagset_count_completed_rqs();
// request is MQ_RQ_COMPLETE state
if (blk_mq_request_completed(rq)) // return true
(*count)++;
if (!count) // So the value of 'count' is never 0, loop endless
break;
msleep(5);
The preceding problem occurs because the timeout processing flow holds
the reference count of the request, and the flush request is always in
the MQ_RQ_COMPLETE state due to the special nature of the flush request.
As a result, a dead loop occurs in the nvme_dev_disable() process.
To solve the preceding problem, if only the timeout processing flow holds
the reference count when the flush request times out, the request status
must be changed to MQ_RQ_IDLE in advance. In this way, it is safe to call
blk_mq_tagset_wait_completed_request () during the timeout processing.
Fixes: e1569a1 ("nvme: do not restart the request timeout if we're resetting the controller")
Signed-off-by: Ye Bin <yebin10@huawei.com>
b663d19 to
7bbba1e
Compare
Pull request for series with
subject: blk-flush: fix possibe deadlock when process nvme_timeout()
version: 1
url: https://patchwork.kernel.org/project/linux-block/list/?series=1107792