--- a/sys/dev/disk/nvme/nvme.c 2026-09-21 05:05:42.529638062 +0000 +++ b/sys/dev/disk/nvme/nvme.c 2026-09-21 05:05:50.517535124 +0000 @@ -529,6 +529,24 @@ } /* + * Submit an ADMIN request. Unlike the I/O path, admin submitters (the + * admin thread and NVMEIOCGETLOG) do not hold the submission queue lock + * around their submit sequence, so take it here: nvme_submit_request() + * mutates subq_tail/unsubmitted and writes ksubq[subq_tail] and must not + * race a concurrent admin-thread submission on queue 0. + */ +void +nvme_submit_admin_request(nvme_request_t *req) +{ + nvme_subqueue_t *queue = req->subq; + + KKASSERT(queue->qid == 0); + lockmgr(&queue->lk, LK_EXCLUSIVE); + nvme_submit_request(req); + lockmgr(&queue->lk, LK_RELEASE); +} + +/* * Wait for a request to complete. * * Caller does not need to hold the queue lock. If it does, or if it @@ -797,7 +815,7 @@ req->cmd.crsub.flags = NVME_CREATESUB_PC | NVME_CREATESUB_PRI_URG; req->cmd.crsub.comq_id = subq->comqid; - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); nvme_put_request(req); @@ -840,7 +858,7 @@ req->cmd.crcom.ivect = ivect; req->cmd.crcom.flags = NVME_CREATECOM_PC | NVME_CREATECOM_IEN; - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); nvme_put_request(req); @@ -874,7 +892,7 @@ req->cmd.head.prp1 = 0; req->cmd.delete.qid = qid; - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); nvme_put_request(req); @@ -899,7 +917,7 @@ req->cmd.head.prp1 = 0; req->cmd.delete.qid = qid; - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); nvme_put_request(req); --- a/sys/dev/disk/nvme/nvme.h +++ b/sys/dev/disk/nvme/nvme.h @@ -298,6 +298,7 @@ nvme_request_t *nvme_get_dump_request(nvme_subqueue_t *queue, uint8_t opcode, char *kva, size_t bytes); void nvme_submit_request(nvme_request_t *req); +void nvme_submit_admin_request(nvme_request_t *req); int nvme_wait_request(nvme_request_t *req); int nvme_poll_request(nvme_request_t *req); void nvme_put_request(nvme_request_t *req); --- a/sys/dev/disk/nvme/nvme_ioctl.c 2026-09-21 04:58:29.815217063 +0000 +++ b/sys/dev/disk/nvme/nvme_ioctl.c 2026-09-21 05:05:50.565534505 +0000 @@ -53,7 +53,7 @@ /* leave numdh 0 (NVMe 1.2.1 allows > 65535 dwords) */ /* leave lpol and lpou 0 for now */ bzero(req->info, sizeof(*req->info)); - nvme_submit_request(req); + nvme_submit_admin_request(req); ioc->status = nvme_wait_request(req); bcopy(req->info, &ioc->info, ioc->ret_size); nvme_put_request(req); --- a/sys/dev/disk/nvme/nvme_admin.c +++ b/sys/dev/disk/nvme/nvme_admin.c @@ -230,7 +230,7 @@ req->cmd.identify.cns = NVME_CNS_CTLR; req->cmd.identify.cntid = 0; bzero(req->info, sizeof(*req->info)); - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); /* XXX handle status */ @@ -316,7 +316,7 @@ req->cmd.setfeat.numqs.nsqr = niosubqs - 1; /* 0's based 0=1 */ req->cmd.setfeat.numqs.ncqr = niocomqs - 1; /* 0's based 0=1 */ - nvme_submit_request(req); + nvme_submit_admin_request(req); /* * Get response and set our operations mode. Limit the returned @@ -531,7 +531,7 @@ req->cmd.setfeat.intcoal.thr = 0; req->cmd.setfeat.intcoal.time = 0; - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); if (status) { device_printf(sc->dev, @@ -573,7 +573,7 @@ req->cmd.identify.cns = NVME_CNS_ANY_CTLR_LIST; req->cmd.identify.cntid = 0; bzero(req->info, sizeof(*req->info)); - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); kprintf("nsquery status %08x\n", status); @@ -595,7 +595,7 @@ req->cmd.identify.cns = NVME_CNS_ACT_NSLIST; req->cmd.identify.cntid = 0; bzero(req->info, sizeof(*req->info)); - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); kprintf("nsquery status %08x\n", status); /* XXX handle status */ @@ -626,7 +626,7 @@ req->cmd.identify.cntid = 0; req->cmd.identify.head.nsid = rp->nsids[i]; bzero(req->info, sizeof(*req->info)); - nvme_submit_request(req); + nvme_submit_admin_request(req); status = nvme_wait_request(req); if (status != 0) { kprintf("NS FAILED %08x\n", status);