git: f6d434f110fd - main - nvmf: Rescan all namespaces if the changed NS log page is too large

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 05 Jun 2024 20:04:01 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=f6d434f110fd95e346f18fb09a6f91f36b528d2d

commit f6d434f110fd95e346f18fb09a6f91f36b528d2d
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-06-05 19:52:43 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-06-05 19:52:43 +0000

    nvmf: Rescan all namespaces if the changed NS log page is too large
    
    Previously this just punted with a warning message.
    
    Reviewed by:    imp
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D45460
---
 sys/dev/nvmf/host/nvmf.c     | 49 ++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/nvmf/host/nvmf_aer.c |  2 +-
 sys/dev/nvmf/host/nvmf_var.h |  1 +
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c
index 086df5f637c9..1e7fce42b2a3 100644
--- a/sys/dev/nvmf/host/nvmf.c
+++ b/sys/dev/nvmf/host/nvmf.c
@@ -804,6 +804,55 @@ nvmf_rescan_ns(struct nvmf_softc *sc, uint32_t nsid)
 	free(data, M_NVMF);
 }
 
+static void
+nvmf_purge_namespaces(struct nvmf_softc *sc, uint32_t first_nsid,
+    uint32_t next_valid_nsid)
+{
+	struct nvmf_namespace *ns;
+
+	for (uint32_t nsid = first_nsid; nsid < next_valid_nsid; nsid++)
+	{
+		/* XXX: Needs locking around sc->ns[]. */
+		ns = sc->ns[nsid - 1];
+		if (ns != NULL) {
+			nvmf_destroy_ns(ns);
+			sc->ns[nsid - 1] = NULL;
+
+			nvmf_sim_rescan_ns(sc, nsid);
+		}
+	}
+}
+
+static bool
+nvmf_rescan_ns_cb(struct nvmf_softc *sc, uint32_t nsid,
+    const struct nvme_namespace_data *data, void *arg)
+{
+	uint32_t *last_nsid = arg;
+
+	/* Check for any gaps prior to this namespace. */
+	nvmf_purge_namespaces(sc, *last_nsid + 1, nsid);
+	*last_nsid = nsid;
+
+	nvmf_rescan_ns_1(sc, nsid, data);
+	return (true);
+}
+
+void
+nvmf_rescan_all_ns(struct nvmf_softc *sc)
+{
+	uint32_t last_nsid;
+
+	last_nsid = 0;
+	if (!nvmf_scan_active_namespaces(sc, nvmf_rescan_ns_cb, &last_nsid))
+		return;
+
+	/*
+	 * Check for any namespace devices after the last active
+	 * namespace.
+	 */
+	nvmf_purge_namespaces(sc, last_nsid + 1, sc->cdata->nn + 1);
+}
+
 int
 nvmf_passthrough_cmd(struct nvmf_softc *sc, struct nvme_pt_command *pt,
     bool admin)
diff --git a/sys/dev/nvmf/host/nvmf_aer.c b/sys/dev/nvmf/host/nvmf_aer.c
index 4c950f1518d0..2f7f177d0421 100644
--- a/sys/dev/nvmf/host/nvmf_aer.c
+++ b/sys/dev/nvmf/host/nvmf_aer.c
@@ -62,7 +62,7 @@ nvmf_handle_changed_namespaces(struct nvmf_softc *sc,
 	 * probably just rescan the entire set of namespaces.
 	 */
 	if (ns_list->ns[0] == 0xffffffff) {
-		device_printf(sc->dev, "too many changed namespaces\n");
+		nvmf_rescan_all_ns(sc);
 		return;
 	}
 
diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h
index e0f6d33d2a73..2fa0216baab8 100644
--- a/sys/dev/nvmf/host/nvmf_var.h
+++ b/sys/dev/nvmf/host/nvmf_var.h
@@ -148,6 +148,7 @@ int	nvmf_init_ivars(struct nvmf_ivars *ivars, struct nvmf_handoff_host *hh);
 void	nvmf_free_ivars(struct nvmf_ivars *ivars);
 void	nvmf_disconnect(struct nvmf_softc *sc);
 void	nvmf_rescan_ns(struct nvmf_softc *sc, uint32_t nsid);
+void	nvmf_rescan_all_ns(struct nvmf_softc *sc);
 int	nvmf_passthrough_cmd(struct nvmf_softc *sc, struct nvme_pt_command *pt,
     bool admin);