[PATCH] nvme-tcp: print correct opcode on timeout and error handling

Akinobu Mita akinobu.mita at gmail.com
Tue Mar 7 08:30:45 PST 2023


In timeout and error handling, various information is reported about the
command in error, but the printed opcode may not be correct

The opcode is obtained from the nvme_command structure referenced by the
'cmd' member in the nvme_request structure.
(i.e. nvme_req(req)->cmd->common.opcode)

For the nvme-tcp driver, the 'cmd' member in the nvme_request structure
points to a structure within the page fragment allocated by
nvme_tcp_init_request().  This page fragment is used as a command capsule
PDU, and then may be reused as a h2c data PDU, so the nvme_command
referenced by the 'cmd' member has already been overwritten.

To fix this problem, when setting up the nvme_command, keep the opcode in
a newly added member in the nvme_tcp_request and use that instead.

Signed-off-by: Akinobu Mita <akinobu.mita at gmail.com>
Cc: Sagi Grimberg <sagi at grimberg.me>
Cc: Chaitanya Kulkarni <kch at nvidia.com>
Cc: Christoph Hellwig <hch at lst.de>
Cc: Keith Busch <kbusch at kernel.org>
Cc: Jens Axboe <axboe at fb.com>
Cc: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 10 ++++++----
 drivers/nvme/host/nvme.h | 11 +++++++++++
 drivers/nvme/host/tcp.c  | 15 ++++++++++++++-
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index c2730b116dc6..a86f787ba3bd 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -310,12 +310,14 @@ static void nvme_log_error(struct request *req)
 {
 	struct nvme_ns *ns = req->q->queuedata;
 	struct nvme_request *nr = nvme_req(req);
+	u8 opcode;
 
+	nvme_get_request_info(req, &opcode);
 	if (ns) {
 		pr_err_ratelimited("%s: %s(0x%x) @ LBA %llu, %llu blocks, %s (sct 0x%x / sc 0x%x) %s%s\n",
 		       ns->disk ? ns->disk->disk_name : "?",
-		       nvme_get_opcode_str(nr->cmd->common.opcode),
-		       nr->cmd->common.opcode,
+		       nvme_get_opcode_str(opcode),
+		       opcode,
 		       (unsigned long long)nvme_sect_to_lba(ns, blk_rq_pos(req)),
 		       (unsigned long long)blk_rq_bytes(req) >> ns->lba_shift,
 		       nvme_get_error_status_str(nr->status),
@@ -328,8 +330,8 @@ static void nvme_log_error(struct request *req)
 
 	pr_err_ratelimited("%s: %s(0x%x), %s (sct 0x%x / sc 0x%x) %s%s\n",
 			   dev_name(nr->ctrl->device),
-			   nvme_get_admin_opcode_str(nr->cmd->common.opcode),
-			   nr->cmd->common.opcode,
+			   nvme_get_admin_opcode_str(opcode),
+			   opcode,
 			   nvme_get_error_status_str(nr->status),
 			   nr->status >> 8 & 7,	/* Status Code Type */
 			   nr->status & 0xff,	/* Status Code */
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bf46f122e9e1..bbb458323e91 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -525,6 +525,7 @@ struct nvme_ctrl_ops {
 	int (*get_address)(struct nvme_ctrl *ctrl, char *buf, int size);
 	void (*print_device_info)(struct nvme_ctrl *ctrl);
 	bool (*supports_pci_p2pdma)(struct nvme_ctrl *ctrl);
+	void (*get_request_info)(struct request *req, u8 *opcode);
 };
 
 /*
@@ -597,6 +598,16 @@ static inline void nvme_print_device_info(struct nvme_ctrl *ctrl)
 		subsys->firmware_rev);
 }
 
+static inline void nvme_get_request_info(struct request *rq, u8 *opcode)
+{
+	struct nvme_request *req = nvme_req(rq);
+
+	if (req->ctrl->ops->get_request_info)
+		req->ctrl->ops->get_request_info(rq, opcode);
+	else
+		*opcode = req->cmd->common.opcode;
+}
+
 #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
 void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj,
 			    const char *dev_name);
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 7723a4989524..a6c0ae51d830 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -90,6 +90,8 @@ struct nvme_tcp_request {
 	struct list_head	entry;
 	struct llist_node	lentry;
 	__le32			ddgst;
+	u8			opcode;
+	u8			fctype;
 
 	struct bio		*curr_bio;
 	struct iov_iter		iter;
@@ -2285,7 +2287,7 @@ static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq)
 	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
 	struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
 	struct nvme_tcp_cmd_pdu *pdu = req->pdu;
-	u8 opc = pdu->cmd.common.opcode, fctype = pdu->cmd.fabrics.fctype;
+	u8 opc = req->opcode, fctype = req->fctype;
 	int qid = nvme_tcp_queue_id(req->queue);
 
 	dev_warn(ctrl->device,
@@ -2354,6 +2356,9 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
 
 	req->state = NVME_TCP_SEND_CMD_PDU;
 	req->status = cpu_to_le16(NVME_SC_SUCCESS);
+	req->opcode = pdu->cmd.common.opcode;
+	if (req->opcode == nvme_fabrics_command)
+		req->fctype = pdu->cmd.fabrics.fctype;
 	req->offset = 0;
 	req->data_sent = 0;
 	req->pdu_len = 0;
@@ -2509,6 +2514,13 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
 	return len;
 }
 
+static void nvme_tcp_get_request_info(struct request *rq, u8 *opcode)
+{
+	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+
+	*opcode = req->opcode;
+}
+
 static const struct blk_mq_ops nvme_tcp_mq_ops = {
 	.queue_rq	= nvme_tcp_queue_rq,
 	.commit_rqs	= nvme_tcp_commit_rqs,
@@ -2542,6 +2554,7 @@ static const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = {
 	.delete_ctrl		= nvme_tcp_delete_ctrl,
 	.get_address		= nvme_tcp_get_address,
 	.stop_ctrl		= nvme_tcp_stop_ctrl,
+	.get_request_info	= nvme_tcp_get_request_info,
 };
 
 static bool
-- 
2.34.1




More information about the Linux-nvme mailing list