nvmet_sq_destroy stuck forever when data digest is turned on
Grupi, Elad
Elad.Grupi at dell.com
Thu Oct 12 07:03:04 PDT 2023
Hi Sagi
The patch causes double completion when 'cmd->exp_ddgst != cmd->recv_ddgst'
Other than that it works fine and solves the issue
With this patch, the meaning of cmd->rbytes_done becomes unclear to me,
It is now more complex than counting the bytes we read from the socket.
If the IO is split between multiple PDUs, the rbytes_done represents the bytes read in each PDU not including the data_digest except the last PDU.
Internal Use - Confidential
-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me>
Sent: Tuesday, 19 September 2023 15:23
To: Grupi, Elad <Elad.Grupi at dell.com>; linux-nvme at lists.infradead.org
Cc: Engel, Amit <Amit.Engel at Dell.com>; Zinger, Eldad <Eldad.Zinger at dell.com>
Subject: Re: nvmet_sq_destroy stuck forever when data digest is turned on
[EXTERNAL EMAIL]
> Hi
>
> I have an issue with nvmet_tcp_release_queue_work hitting hung task after 2 minutes of waiting for nvmet_sq_destroy.
> This issue reproduces only when data digest is on.
>
> I am inspecting the code of nvmet_tcp_release_queue_work and I see
> that the code handles 'data in' commands This means that it calls nvmet_req_uninit for any command that its data is still in transit.
>
> There might be commands that the data transfer is already done, but
> data digest was not received from socket yet (aka rcv_state is
> NVMET_TCP_RECV_DDGST) The data digest will never be read from the socket because the socket is blocked by NVMET_TCP_RECV_ERR Hence nvmet_sq_destroy will be stuck forever waiting for nvmet_tcp_try_recv_ddgst to execute.
>
> Can you suggest a fix for such an issue?
Does this (untested) patch make the issue go away?
--
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 97d07488072d..f5eaf3457ada 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -204,10 +204,16 @@ static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
return cmd - queue->cmds;
}
+static inline u8 nvmet_tcp_ddgst_len(struct nvmet_tcp_queue *queue) {
+ return queue->data_digest ? NVME_TCP_DIGEST_LENGTH : 0; }
+
static inline bool nvmet_tcp_has_data_in(struct nvmet_tcp_cmd *cmd)
{
- return nvme_is_write(cmd->req.cmd) &&
- cmd->rbytes_done < cmd->req.transfer_len;
+ u32 total_len = cmd->req.transfer_len +
nvmet_tcp_ddgst_len(cmd->queue);
+
+ return nvme_is_write(cmd->req.cmd) && cmd->rbytes_done <
+ total_len;
}
static inline bool nvmet_tcp_need_data_in(struct nvmet_tcp_cmd *cmd) @@ -265,11 +271,6 @@ static inline u8 nvmet_tcp_hdgst_len(struct nvmet_tcp_queue *queue)
return queue->hdr_digest ? NVME_TCP_DIGEST_LENGTH : 0;
}
-static inline u8 nvmet_tcp_ddgst_len(struct nvmet_tcp_queue *queue) -{
- return queue->data_digest ? NVME_TCP_DIGEST_LENGTH : 0;
-}
-
static inline void nvmet_tcp_hdgst(struct ahash_request *hash,
void *pdu, size_t len)
{
@@ -1221,8 +1222,8 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue)
goto out;
}
- if (cmd->rbytes_done == cmd->req.transfer_len)
- nvmet_tcp_execute_request(cmd);
+ cmd->rbytes_done += NVME_TCP_DIGEST_LENGTH;
+ nvmet_tcp_execute_request(cmd);
ret = 0;
out:
--
More information about the Linux-nvme
mailing list