--- a/sys/dev/disk/nvme/nvme_admin.c 2026-09-22 22:06:14.009580937 +0000 +++ b/sys/dev/disk/nvme/nvme_admin.c 2026-09-22 22:06:20.053502285 +0000 @@ -638,13 +638,22 @@ sc->nscary[j]->nsid == rp->nsids[i]) break; } - if (j == NVME_MAX_NAMESPACES) { - j = i; - if (sc->nscary[j] != NULL) { - for (j = NVME_MAX_NAMESPACES - 1; j >= 0; --j) { - if (sc->nscary[j] == NULL) - break; - } + if (j != NVME_MAX_NAMESPACES) { + /* + * Duplicate nsid in the device-supplied list. + * Never re-run the identify/attach sequence for a + * namespace we already processed in this scan; a + * second nvme_disk_attach() on a live namespace + * corrupts the global disklist and devstat queues. + */ + nvme_put_request(req); + continue; + } + j = i; + if (sc->nscary[j] != NULL) { + for (j = NVME_MAX_NAMESPACES - 1; j >= 0; --j) { + if (sc->nscary[j] == NULL) + break; } } if (j < 0) { --- a/sys/dev/disk/nvme/nvme_disk.c 2026-09-22 22:06:14.013580885 +0000 +++ b/sys/dev/disk/nvme/nvme_disk.c 2026-09-22 22:06:28.173396615 +0000 @@ -74,6 +74,18 @@ size_t len; uint64_t cap_gb; + /* + * Defense-in-depth: the active namespace list is device-controlled + * and must never cause the same namespace to be attached twice; + * a second disk_create() on a live struct disk corrupts the global + * disklist and devstat queues. + */ + if (nsc->cdev != NULL) { + device_printf(nsc->sc->dev, + "namespace %u already attached\n", nsc->nsid); + return; + } + sc = nsc->sc; devstat_add_entry(&nsc->stats, "nvme", nsc->unit, nsc->blksize, DEVSTAT_NO_ORDERED_TAGS, @@ -118,6 +130,7 @@ if (nsc->cdev) { disk_destroy(&nsc->disk); devstat_remove_entry(&nsc->stats); + nsc->cdev = NULL; /* allow a later re-attach */ } }