From cf54a0dff38435bb3b7652872717cd02fdbac0ca Mon Sep 17 00:00:00 2001 From: Christian Aurich Zanettini Martins Date: Tue, 27 Oct 2026 16:47:10 -0300 Subject: [PATCH] nvme-tcp: fix request PDU size when header digest is enabled Since commit 61b0ed3be81b ("nvme-tcp: parallelize I/O queue allocation and startup") the I/O tag set is allocated before the I/O queues. nvme_tcp_init_request() sizes the PDU with nvme_tcp_hdgst_len(queue), but queue->hdr_digest is only set later by nvme_tcp_alloc_queue(), so every I/O PDU is allocated without room for the header digest. With hdr_digest enabled, the digest is then written 4 bytes past the PDU, over the header of the next PDU in the page_frag cache, and the target drops the connection on the first I/O: nvmet_tcp: unexpected pdu type 159 nvmet: ctrl 1 fatal error occurred! Queues that a later reconnect adds for the first time have the same problem. Set queue->hdr_digest when allocating the controller, together with pf_cache_lock, so it is valid before any request is initialized. Fixes: 61b0ed3be81b ("nvme-tcp: parallelize I/O queue allocation and startup") Signed-off-by: Christian Aurich Zanettini Martins Signed-off-by: Keith Busch --- drivers/nvme/host/tcp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index dbefe36b0575..191e5811d25e 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2079,7 +2079,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid, } } - queue->hdr_digest = nctrl->opts->hdr_digest; queue->data_digest = nctrl->opts->data_digest; rcv_pdu_size = sizeof(struct nvme_tcp_rsp_pdu) + @@ -3229,10 +3228,13 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, /* * The I/O tag set is allocated before the I/O queues, and initializing * its requests already allocates the PDUs from the page frag caches of - * the queues, so initialize their locks here. + * the queues, sized by their header digest setting, so set up the + * locks and hdr_digest here. */ - for (i = 0; i < ctrl->ctrl.queue_count; i++) + for (i = 0; i < ctrl->ctrl.queue_count; i++) { mutex_init(&ctrl->queues[i].pf_cache_lock); + ctrl->queues[i].hdr_digest = opts->hdr_digest; + } ctrl->net = get_net(current->nsproxy->net_ns);