[PATCH 09/11] nvmet: serve the FDP log pages

Guixin Liu kanie at linux.alibaba.com
Sun Oct 18 20:36:22 PDT 2026


The bridge advertises the FDP log pages 20h to 23h as supported;
serve them.

The FDP Configurations log page (LID 20h) is constructed from the
snapshot taken at namespace enable time: one valid configuration
with a single reclaim group, the backing number of reclaim unit
handles, all of the Initially Isolated type, and the backing reclaim
unit nominal size.  The page is addressed by the Endurance Group
Identifier in the Log Specific Identifier field.  Hosts first
request the 16 byte header to learn the page size and then the full
page; both request sizes are served from the same construction path.

The remaining pages are owned by the backing controller and are
forwarded to it over its admin queue, addressed by the Endurance
Group Identifier of the backing endurance group, so hosts read the
real reclaim unit handle usage, counters and events of the backing
device.

Assisted-by: LLM
Signed-off-by: Guixin Liu <kanie at linux.alibaba.com>
---
 drivers/nvme/target/admin-cmd.c | 16 ++++++
 drivers/nvme/target/fdp.c       | 98 ++++++++++++++++++++++++++++++++-
 drivers/nvme/target/nvmet.h     | 14 +++++
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 34492cf02875a..08bec1259dd94 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -220,6 +220,16 @@ static void nvmet_execute_get_supported_log_pages(struct nvmet_req *req)
 	logs->lids[NVME_LOG_FEATURES] = cpu_to_le32(NVME_LIDS_LSUPP);
 	logs->lids[NVME_LOG_RMI] = cpu_to_le32(NVME_LIDS_LSUPP);
 	logs->lids[NVME_LOG_RESERVATION] = cpu_to_le32(NVME_LIDS_LSUPP);
+	if (nvmet_fdp_subsys_configured(nvmet_req_subsys(req))) {
+		logs->lids[NVME_LOG_FDP_CONFIGS] =
+			cpu_to_le32(NVME_LIDS_LSUPP);
+		logs->lids[NVME_LOG_FDP_RUH_USAGE] =
+			cpu_to_le32(NVME_LIDS_LSUPP);
+		logs->lids[NVME_LOG_FDP_STATS] =
+			cpu_to_le32(NVME_LIDS_LSUPP);
+		logs->lids[NVME_LOG_FDP_EVENTS] =
+			cpu_to_le32(NVME_LIDS_LSUPP);
+	}
 
 	status = nvmet_copy_to_sgl(req, 0, logs, sizeof(*logs));
 	kfree(logs);
@@ -648,6 +658,12 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
 		return nvmet_execute_get_log_page_rmi(req);
 	case NVME_LOG_RESERVATION:
 		return nvmet_execute_get_log_page_resv(req);
+	case NVME_LOG_FDP_CONFIGS:
+		return nvmet_execute_get_log_page_fdp_configs(req);
+	case NVME_LOG_FDP_RUH_USAGE:
+	case NVME_LOG_FDP_STATS:
+	case NVME_LOG_FDP_EVENTS:
+		return nvmet_fdp_log_forward(req);
 	}
 	pr_debug("unhandled lid %d on qid %d\n",
 	       req->cmd->get_log_page.lid, req->sq->qid);
diff --git a/drivers/nvme/target/fdp.c b/drivers/nvme/target/fdp.c
index 6458efadbcb8e..8c0bc297471ec 100644
--- a/drivers/nvme/target/fdp.c
+++ b/drivers/nvme/target/fdp.c
@@ -162,7 +162,6 @@ u16 nvmet_get_feat_fdp(struct nvmet_req *req)
 	return 0;
 }
 
-
 static u16 nvmet_fdp_io_mgmt_check(struct nvmet_req *req)
 {
 	if (!nvmet_fdp_enabled(req->ns))
@@ -333,3 +332,100 @@ static int nvmet_fdp_init_backend(struct nvmet_ns *ns)
 	return ret;
 }
 
+void nvmet_execute_get_log_page_fdp_configs(struct nvmet_req *req)
+{
+	u32 lsi = le16_to_cpu(req->cmd->get_log_page.lsi);
+	struct nvme_fdp_config_desc *desc;
+	struct nvme_fdp_config_log *log;
+	struct nvmet_ns *ns;
+	size_t dsze, total;
+	u16 status = 0;
+	int i;
+
+	ns = nvmet_fdp_lookup_ns(req, lsi);
+	if (!ns) {
+		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+		goto out;
+	}
+
+	dsze = ALIGN(struct_size(desc, ruhs, ns->fdp.nruh), 8);
+	total = sizeof(*log) + dsze;
+
+	log = kzalloc(req->transfer_len, GFP_KERNEL);
+	if (!log) {
+		status = NVME_SC_INTERNAL;
+		goto out_put;
+	}
+
+	if (req->transfer_len >= sizeof(*log)) {
+		/* single configuration, 0's based */
+		log->numfdpc = 0;
+		log->ver = 0;
+		log->sze = cpu_to_le32(total);
+	}
+	if (req->transfer_len >= total) {
+		desc = (void *)(log + 1);
+		desc->dsze = cpu_to_le16(dsze);
+		/* FDPCV set, FDPVWC clear, RGIF 0 for the single RG */
+		desc->fdpa = 1 << 7;
+		desc->nrg = cpu_to_le32(1);
+		desc->nruh = cpu_to_le16(ns->fdp.nruh);
+		desc->maxpids = cpu_to_le16(ns->fdp.nruh - 1);
+		desc->nns = cpu_to_le32(1);
+		desc->runs = cpu_to_le64(ns->fdp.runs);
+		/* all handles Initially Isolated */
+		for (i = 0; i < ns->fdp.nruh; i++)
+			desc->ruhs[i].ruht = 0x1;
+	}
+
+	status = nvmet_copy_to_sgl(req, 0, log, req->transfer_len);
+	kfree(log);
+out_put:
+	percpu_ref_put(&ns->ref);
+out:
+	nvmet_req_complete(req, status);
+}
+
+/*
+ * Forward an FDP log page that the backing controller owns, addressed
+ * by the Endurance Group Identifier of the backing endurance group.
+ */
+void nvmet_fdp_log_forward(struct nvmet_req *req)
+{
+	struct nvme_command c = {};
+	struct nvmet_ns *ns;
+	u16 status = 0;
+	void *buf;
+	int ret;
+
+	ns = nvmet_fdp_lookup_ns(req,
+				 le16_to_cpu(req->cmd->get_log_page.lsi));
+	if (!ns) {
+		status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
+		goto out;
+	}
+
+	buf = kzalloc(req->transfer_len, GFP_KERNEL);
+	if (!buf) {
+		status = NVME_SC_INTERNAL;
+		goto out_put;
+	}
+
+	c = *req->cmd;
+	c.get_log_page.nsid = cpu_to_le32(0);
+	c.get_log_page.lsi = cpu_to_le16(ns->fdp.backend_endgid);
+	ret = nvme_submit_sync_cmd(ns->fdp.backend_ctrl->admin_q, &c, buf,
+				   req->transfer_len);
+	if (ret) {
+		status = ret > 0 ? ret : NVME_SC_INTERNAL;
+		goto free;
+	}
+
+	status = nvmet_copy_to_sgl(req, 0, buf, req->transfer_len);
+free:
+	kfree(buf);
+out_put:
+	percpu_ref_put(&ns->ref);
+out:
+	nvmet_req_complete(req, status);
+}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 037c3862062ab..5bcc719973a57 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -1003,6 +1003,8 @@ u16 nvmet_set_feat_fdp(struct nvmet_req *req);
 u16 nvmet_get_feat_fdp(struct nvmet_req *req);
 void nvmet_execute_io_mgmt_recv(struct nvmet_req *req);
 void nvmet_execute_io_mgmt_send(struct nvmet_req *req);
+void nvmet_execute_get_log_page_fdp_configs(struct nvmet_req *req);
+void nvmet_fdp_log_forward(struct nvmet_req *req);
 #else
 static inline bool nvmet_fdp_enabled(struct nvmet_ns *ns)
 {
@@ -1035,6 +1037,18 @@ static inline void nvmet_execute_io_mgmt_send(struct nvmet_req *req)
 {
 	nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_STATUS_DNR);
 }
+static inline void nvmet_execute_get_log_page_fdp_configs(struct nvmet_req *req)
+{
+	nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_STATUS_DNR);
+}
+static inline void nvmet_fdp_log_forward(struct nvmet_req *req)
+{
+	nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_STATUS_DNR);
+}
+static inline u8 nvmet_fdp_write_stream(struct nvmet_req *req)
+{
+	return 0;
+}
 #endif
 
 /*
-- 
2.43.7




More information about the Linux-nvme mailing list