diff options
author | Keith Busch <kbusch@kernel.org> | 2021-05-17 15:36:43 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-05-26 12:06:49 +0200 |
commit | 33ebdee80e409f39459bd219ef675434288ba1f0 (patch) | |
tree | b1ef76e52dfed20fb7d23c47fe9e36a7215f32c8 /drivers/nvme | |
parent | 9c980795ccd77e8abec33dd6fe28dfe1c4083e65 (diff) | |
download | kernel_replicant_linux-33ebdee80e409f39459bd219ef675434288ba1f0.tar.gz kernel_replicant_linux-33ebdee80e409f39459bd219ef675434288ba1f0.tar.bz2 kernel_replicant_linux-33ebdee80e409f39459bd219ef675434288ba1f0.zip |
nvme-tcp: rerun io_work if req_list is not empty
[ Upstream commit a0fdd1418007f83565d3f2e04b47923ba93a9b8c ]
A possible race condition exists where the request to send data is
enqueued from nvme_tcp_handle_r2t()'s will not be observed by
nvme_tcp_send_all() if it happens to be running. The driver relies on
io_work to send the enqueued request when it is runs again, but the
concurrently running nvme_tcp_send_all() may not have released the
send_mutex at that time. If no future commands are enqueued to re-kick
the io_work, the request will timeout in the SEND_H2C state, resulting
in a timeout error like:
nvme nvme0: queue 1: timeout request 0x3 type 6
Ensure the io_work continues to run as long as the req_list is not empty.
Fixes: db5ad6b7f8cdd ("nvme-tcp: try to send request in queue_rq context")
Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/nvme')
-rw-r--r-- | drivers/nvme/host/tcp.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 4cf81f3841ae..7346a05d395b 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1140,7 +1140,8 @@ static void nvme_tcp_io_work(struct work_struct *w) pending = true; else if (unlikely(result < 0)) break; - } + } else + pending = !llist_empty(&queue->req_list); result = nvme_tcp_try_recv(queue); if (result > 0) |