| From 792c58bc6d11eb120cf411f3c6396cb2f335c336 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 24 Jul 2020 15:10:12 -0700 |
| Subject: nvme-tcp: fix controller reset hang during traffic |
| |
| From: Sagi Grimberg <sagi@grimberg.me> |
| |
| [ Upstream commit 2875b0aecabe2f081a8432e2bc85b85df0529490 ] |
| |
| commit fe35ec58f0d3 ("block: update hctx map when use multiple maps") |
| exposed an issue where we may hang trying to wait for queue freeze |
| during I/O. We call blk_mq_update_nr_hw_queues which in case of multiple |
| queue maps (which we have now for default/read/poll) is attempting to |
| freeze the queue. However we never started queue freeze when starting the |
| reset, which means that we have inflight pending requests that entered the |
| queue that we will not complete once the queue is quiesced. |
| |
| So start a freeze before we quiesce the queue, and unfreeze the queue |
| after we successfully connected the I/O queues (and make sure to call |
| blk_mq_update_nr_hw_queues only after we are sure that the queue was |
| already frozen). |
| |
| This follows to how the pci driver handles resets. |
| |
| Fixes: fe35ec58f0d3 ("block: update hctx map when use multiple maps") |
| Signed-off-by: Sagi Grimberg <sagi@grimberg.me> |
| Signed-off-by: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/nvme/host/tcp.c | 12 +++++++++--- |
| 1 file changed, 9 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c |
| index 26461bf3fdcc3..99eaa0474e10b 100644 |
| --- a/drivers/nvme/host/tcp.c |
| +++ b/drivers/nvme/host/tcp.c |
| @@ -1753,15 +1753,20 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) |
| ret = PTR_ERR(ctrl->connect_q); |
| goto out_free_tag_set; |
| } |
| - } else { |
| - blk_mq_update_nr_hw_queues(ctrl->tagset, |
| - ctrl->queue_count - 1); |
| } |
| |
| ret = nvme_tcp_start_io_queues(ctrl); |
| if (ret) |
| goto out_cleanup_connect_q; |
| |
| + if (!new) { |
| + nvme_start_queues(ctrl); |
| + nvme_wait_freeze(ctrl); |
| + blk_mq_update_nr_hw_queues(ctrl->tagset, |
| + ctrl->queue_count - 1); |
| + nvme_unfreeze(ctrl); |
| + } |
| + |
| return 0; |
| |
| out_cleanup_connect_q: |
| @@ -1866,6 +1871,7 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl, |
| { |
| if (ctrl->queue_count <= 1) |
| return; |
| + nvme_start_freeze(ctrl); |
| nvme_stop_queues(ctrl); |
| nvme_tcp_stop_io_queues(ctrl); |
| if (ctrl->tagset) { |
| -- |
| 2.25.1 |
| |