Thread (10 messages) 10 messages, 3 authors, 2021-05-25

Re: [PATCH 2/2] nvmet-tcp: fix connect error when setting param_inline_data_size to zero.

From: Hou Pu <hidden>
Date: 2021-05-21 02:58:02

On Fri, May 21, 2021 at 6:44 AM Sagi Grimberg [off-list ref] wrote:
quoted
When setting inline_data_size to zero, connect failed. This could be
reproduced with following steps.

Controller side:
mkdir /sys/kernel/config/nvmet/ports/1
cd /sys/kernel/config/nvmet/ports/1
echo 0.0.0.0 > addr_traddr
echo 4421 > addr_trsvcid
echo ipv4 > addr_adrfam
echo tcp > addr_trtype
echo 0 > param_inline_data_size
ln -s /sys/kernel/config/nvmet/subsystems/mysub /sys/kernel/config/nvmet/ports/1/subsystems/mysub

Host side:
[  325.145323][  T203] nvme nvme1: Connect command failed, error wo/DNR bit: 22
[  325.159481][  T203] nvme nvme1: failed to connect queue: 0 ret=16406
Failed to write to /dev/nvme-fabrics: Input/output error

Kernel log from controller side is:
[  114.567411][   T56] nvmet_tcp: queue 0: failed to map data
[  114.568093][   T56] nvmet_tcp: unexpected pdu type 201

When admin-connect command comes with 1024 inline data size, in nvmet_tcp_map_data(),
this size is compared with cmd->req.port->inline_data_size (which is 0),
thus the command is responded with an error code. But admin-connect command
is always allowed to use no more than 8192 bytes according to the nvme over
fabrics specification.

The host side decides the inline data size when allocating the queue
according the queue number, the size of queue 0 is 8k and others is ioccsz*16.
The target side should do like this.

Fixes: 0d5ee2b2ab4f ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data")
Signed-off-by: Hou Pu <redacted>
---
  drivers/nvme/target/tcp.c | 24 +++++++++++++++++++++---
  1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d8aceef83284..83985ab8c3aa 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -167,6 +167,24 @@ static const struct nvmet_fabrics_ops nvmet_tcp_ops;
  static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
  static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);

+static inline int nvmet_tcp_inline_data_size(struct nvmet_tcp_cmd *cmd)
+{
+     struct nvmet_tcp_queue *queue = cmd->queue;
+     struct nvme_command *nvme_cmd = cmd->req.cmd;
+     int inline_data_size = NVME_TCP_ADMIN_CCSZ;
+     u16 qid = 0;
+
+     if (likely(queue->nvme_sq.ctrl)) {
+             /* The connect admin/io queue has been executed. */
+             qid = queue->nvme_sq.qid;
+             if (qid)
+                     inline_data_size = cmd->req.port->inline_data_size;
+     } else if (nvme_cmd->connect.qid)
+             inline_data_size = cmd->req.port->inline_data_size;
How can a connection to an I/O queue arrive without having the ctrl
reference installed? Is this for the failure case?
Hi Sagi,
AFAIK after the host finishes setting up the admin queue,
it connects to the io queue and sends the io-connect command. At this
point the nvmet_tcp_queue is firstly allocated and does not have a valid
queue->nvme_sq.ctrl. It is assigned after io-connect in nvmet_install_queue().
So this function tries to find the correct queue number before or after a
fabrics connect command.

Thank,
Hou

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help