[PATCH] nvmet-tcp: fix possible list corruption for unexpected command failure
Keith Busch
kbusch at kernel.org
Wed Dec 8 07:14:34 PST 2021
On Wed, Dec 08, 2021 at 03:35:06PM +0200, Sagi Grimberg wrote:
> nvmet_tcp_handle_req_failure needs to understand weather to prepare
> for incoming data or the next pdu. However if we misidentify this, we
> will wait for 0-length data, and queue the response although nvmet_req_init
> already did that.
>
> The particular command was namespace management command with no data,
> which was incorrectly categorized as a command with incapsule data.
>
> Also, add a code comment of what we are trying to do here.
>
> Reported-by: Witold Baryluk
> Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
> ---
> drivers/nvme/target/tcp.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index cb6a473c3eaf..7c1c43ce466b 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -922,7 +922,14 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
> size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length);
> int ret;
>
> - if (!nvme_is_write(cmd->req.cmd) ||
> + /*
> + * This command has not been processed yet, hence we are trying to
> + * figure out if there is still pending data left to receive. If
> + * we don't, we can simply prepare for the next pdu and bail out,
> + * otherwise we will need to prepare a buffer and receive the
> + * stale data before continuing forward.
> + */
> + if (!nvme_is_write(cmd->req.cmd) || !data_len ||
> data_len > cmd->req.port->inline_data_size) {
> nvmet_prepare_receive_pdu(queue);
> return;
> --
Let me see if I can get this understood:
1. nvmet_req_init() will queue a response from tcp's RECV_PDU state if
the current command is a read, no data, or a write with data length
exceeding inline length.
2. nvmet_tcp_handle_req_failure(), which is called immediately after
nvmet_req_init(), will abandon the current cmd if it's a read, a
zero data command, or a data length exceeding inline length;
otherwise it will later queue the response.
It sounds like all the cases are covered to ensure exactly one response
gets enqueued for this error case. I think this works, however, a little
confusing with the dependency on tcp's .queue_response special handling.
:)
Anyway,
Reviewed-by: Keith Busch <kbusch at kernel.org>
More information about the Linux-nvme
mailing list