⬢ DragonFlyBSD Kernel Audit
DF-4528 / fix.diff
← back to finding ↓ download raw
--- 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);