git: 24c2ead33b44 - main - ufshci: tolerate partially constructed queues in SDB teardown
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 10 Aug 2026 02:31:23 UTC
The branch main has been updated by jaeyoon:
URL: https://cgit.FreeBSD.org/src/commit/?id=24c2ead33b44ca5db2605b462c935236f3a73443
commit 24c2ead33b44ca5db2605b462c935236f3a73443
Author: Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-08-10 01:42:16 +0000
Commit: Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-08-10 02:28:50 +0000
ufshci: tolerate partially constructed queues in SDB teardown
When attach fails, ufshci_req_sdb_destroy() runs on a partially
constructed queue, and it runs twice: once from the construct error
path and once from the controller destructor.
Make that safe: NULL-check each resource before freeing it and clear
the pointer afterwards, so a second call finds nothing to do. The
construct error label no longer frees the command descriptors itself,
which fixes a double free of ucd_bus_addr. Also destroy the payload
DMA tag, which was previously leaked. Drop the mtx_initialized()
checks: the locks are always set up before any failure path can reach
the destroy.
Attach can also fail before the queues were constructed at all. The
destructor would then call a NULL qops.destroy pointer, so skip the
destroy when the queue was never set up.
Sponsored by: Samsung Electronics
Reviewed by: imp (mentor)
Differential Revision: https://reviews.freebsd.org/D58660
---
sys/dev/ufshci/ufshci_req_queue.c | 8 +++++++
sys/dev/ufshci/ufshci_req_sdb.c | 44 +++++++++++++++++++++++----------------
2 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index 371b9c520979..d8d86070c18c 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -72,6 +72,10 @@ ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr)
void
ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr)
{
+ /* Attach may fail before the queue ops are set up. */
+ if (ctrlr->task_mgmt_req_queue.qops.destroy == NULL)
+ return;
+
ctrlr->task_mgmt_req_queue.qops.destroy(ctrlr,
&ctrlr->task_mgmt_req_queue);
}
@@ -114,6 +118,10 @@ ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr)
void
ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr)
{
+ /* Attach may fail before the queue ops are set up. */
+ if (ctrlr->transfer_req_queue.qops.destroy == NULL)
+ return;
+
ctrlr->transfer_req_queue.qops.destroy(ctrlr,
&ctrlr->transfer_req_queue);
}
diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c
index cc99b645331c..c7bf033ddc37 100644
--- a/sys/dev/ufshci/ufshci_req_sdb.c
+++ b/sys/dev/ufshci/ufshci_req_sdb.c
@@ -22,10 +22,16 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue)
struct ufshci_tracker *tr;
int i;
- for (i = 0; i < req_queue->num_trackers; i++) {
- tr = hwq->act_tr[i];
- bus_dmamap_destroy(req_queue->dma_tag_payload,
- tr->payload_dma_map);
+ if (req_queue->dma_tag_payload != NULL) {
+ for (i = 0; i < req_queue->num_trackers; i++) {
+ tr = hwq->act_tr[i];
+ if (tr->payload_dma_map != NULL)
+ bus_dmamap_destroy(req_queue->dma_tag_payload,
+ tr->payload_dma_map);
+ }
+
+ bus_dma_tag_destroy(req_queue->dma_tag_payload);
+ req_queue->dma_tag_payload = NULL;
}
if (req_queue->ucd) {
@@ -42,6 +48,7 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue)
}
free(req_queue->hwq->ucd_bus_addr, M_UFSHCI);
+ req_queue->hwq->ucd_bus_addr = NULL;
}
static void
@@ -145,7 +152,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
return (0);
out:
- ufshci_req_sdb_cmd_desc_destroy(req_queue);
return (ENOMEM);
}
@@ -297,24 +303,27 @@ void
ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
struct ufshci_req_queue *req_queue)
{
- struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q];
- struct ufshci_tracker *tr;
+ struct ufshci_hw_queue *hwq;
int i;
+ if (req_queue->hwq == NULL)
+ return;
+
+ hwq = &req_queue->hwq[UFSHCI_SDB_Q];
+
mtx_lock(&hwq->recovery_lock);
hwq->timer_armed = false;
mtx_unlock(&hwq->recovery_lock);
callout_drain(&hwq->timer);
- if (!req_queue->is_task_mgmt)
- ufshci_req_sdb_cmd_desc_destroy(&ctrlr->transfer_req_queue);
+ if (hwq->act_tr != NULL) {
+ if (!req_queue->is_task_mgmt)
+ ufshci_req_sdb_cmd_desc_destroy(
+ &ctrlr->transfer_req_queue);
- for (i = 0; i < req_queue->num_trackers; i++) {
- tr = hwq->act_tr[i];
- free(tr, M_UFSHCI);
- }
+ for (i = 0; i < req_queue->num_trackers; i++)
+ free(hwq->act_tr[i], M_UFSHCI);
- if (hwq->act_tr) {
free(hwq->act_tr, M_UFSHCI);
hwq->act_tr = NULL;
}
@@ -331,12 +340,11 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
hwq->dma_tag_queue = NULL;
}
- if (mtx_initialized(&hwq->recovery_lock))
- mtx_destroy(&hwq->recovery_lock);
- if (mtx_initialized(&hwq->qlock))
- mtx_destroy(&hwq->qlock);
+ mtx_destroy(&hwq->recovery_lock);
+ mtx_destroy(&hwq->qlock);
free(req_queue->hwq, M_UFSHCI);
+ req_queue->hwq = NULL;
}
struct ufshci_hw_queue *