[PATCH 4/9] nvmet: refactor passthru fixup code

Christoph Hellwig hch at lst.de
Wed Dec 14 08:13:42 PST 2022


Add a helper to check if a given command needs a fixup and use that
instead of setting the use_workqueue flag that can get out of sync.
Also move the fixup into a separate out of line function.

Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 drivers/nvme/target/nvmet.h    |  1 -
 drivers/nvme/target/passthru.c | 50 ++++++++++++++++++++++------------
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 89bedfcd974c41..b4f7d2aa869142 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -369,7 +369,6 @@ struct nvmet_req {
 			struct bio		inline_bio;
 			struct request		*rq;
 			struct work_struct      work;
-			bool			use_workqueue;
 		} p;
 #ifdef CONFIG_BLK_DEV_ZONED
 		struct {
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 0b238fce2c11f2..63fe8aaf968486 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -211,19 +211,20 @@ static u16 nvmet_passthru_override_id_ns(struct nvmet_req *req)
 	return status;
 }
 
-static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
+static bool nvmet_passthru_needs_fixup(struct nvmet_req *req)
 {
-	struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
-	struct request *rq = req->p.rq;
-	struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
-	struct nvme_ns *ns = rq->q->queuedata;
-	u32 effects;
-	int status;
+	/*
+	 * Some CNS values of Identify need fixups after I/O completion and
+	 * thus need to be handled in a workqueue.  Don't bother selecting the
+	 * specific ones as Identify performance doesn't matter too much.
+	 */
+	return req->cmd->common.opcode == nvme_admin_identify;
+}
 
-	effects = nvme_passthru_start(ctrl, ns, req->cmd->common.opcode);
-	status = nvme_execute_rq(rq, false);
-	if (status == NVME_SC_SUCCESS &&
-	    req->cmd->common.opcode == nvme_admin_identify) {
+static void nvmet_passthru_fixup(struct nvmet_req *req)
+{
+	switch (req->cmd->common.opcode) {
+	case nvme_admin_identify:
 		switch (req->cmd->identify.cns) {
 		case NVME_ID_CNS_CTRL:
 			nvmet_passthru_override_id_ctrl(req);
@@ -234,8 +235,26 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
 		case NVME_ID_CNS_NS_DESC_LIST:
 			nvmet_passthru_override_id_descs(req);
 			break;
+		default:
+			break;
 		}
-	} else if (status < 0)
+	}
+}
+
+static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
+{
+	struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
+	struct request *rq = req->p.rq;
+	struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
+	struct nvme_ns *ns = rq->q->queuedata;
+	u32 effects;
+	int status;
+
+	effects = nvme_passthru_start(ctrl, ns, req->cmd->common.opcode);
+	status = nvme_execute_rq(rq, false);
+	if (status == NVME_SC_SUCCESS && nvmet_passthru_needs_fixup(req))
+		nvmet_passthru_fixup(req);
+	else if (status < 0)
 		status = NVME_SC_INTERNAL;
 
 	req->cqe->result = nvme_req(rq)->result;
@@ -342,7 +361,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 	 * which is typically in interrupt context.
 	 */
 	effects = nvme_command_effects(ctrl, ns, req->cmd->common.opcode);
-	if (req->p.use_workqueue || effects) {
+	if (nvmet_passthru_needs_fixup(req) || effects) {
 		INIT_WORK(&req->p.work, nvmet_passthru_execute_cmd_work);
 		req->p.rq = rq;
 		queue_work(nvmet_wq, &req->p.work);
@@ -404,7 +423,6 @@ static void nvmet_passthru_set_host_behaviour(struct nvmet_req *req)
 
 static u16 nvmet_setup_passthru_command(struct nvmet_req *req)
 {
-	req->p.use_workqueue = false;
 	req->execute = nvmet_passthru_execute_cmd;
 	return NVME_SC_SUCCESS;
 }
@@ -538,25 +556,21 @@ u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
 		switch (req->cmd->identify.cns) {
 		case NVME_ID_CNS_CTRL:
 			req->execute = nvmet_passthru_execute_cmd;
-			req->p.use_workqueue = true;
 			return NVME_SC_SUCCESS;
 		case NVME_ID_CNS_CS_CTRL:
 			switch (req->cmd->identify.csi) {
 			case NVME_CSI_ZNS:
 				req->execute = nvmet_passthru_execute_cmd;
-				req->p.use_workqueue = true;
 				return NVME_SC_SUCCESS;
 			}
 			return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
 		case NVME_ID_CNS_NS:
 			req->execute = nvmet_passthru_execute_cmd;
-			req->p.use_workqueue = true;
 			return NVME_SC_SUCCESS;
 		case NVME_ID_CNS_CS_NS:
 			switch (req->cmd->identify.csi) {
 			case NVME_CSI_ZNS:
 				req->execute = nvmet_passthru_execute_cmd;
-				req->p.use_workqueue = true;
 				return NVME_SC_SUCCESS;
 			}
 			return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
-- 
2.35.1




More information about the Linux-nvme mailing list