git: 1258ae2bcb55 - main - ufshci: run the controller fail path only once
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 27 Aug 2026 05:12:45 UTC
The branch main has been updated by jaeyoon:
URL: https://cgit.FreeBSD.org/src/commit/?id=1258ae2bcb559854c966e425f4c5c48668d3cf7b
commit 1258ae2bcb559854c966e425f4c5c48668d3cf7b
Author: Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-08-27 04:58:21 +0000
Commit: Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-08-27 05:08:37 +0000
ufshci: run the controller fail path only once
Two threads could run ufshci_ctrlr_fail() at the same time.
Each one walked the queues and completed the same trackers
again, which caused a double free and a panic.
Turn is_failed into an atomic gate, so only the first caller
walks the queues. The reset task now returns early on a failed
controller instead of re-enabling it.
Reviewed by: imp (mentor)
Sponsored by: Samsung Electronics
Differential Revision: https://reviews.freebsd.org/D58944
---
sys/dev/ufshci/ufshci_ctrlr.c | 12 +++++++++++-
sys/dev/ufshci/ufshci_private.h | 2 +-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index bb07ad5f76da..2f930d55a295 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -15,7 +15,13 @@
static void
ufshci_ctrlr_fail(struct ufshci_controller *ctrlr)
{
- ctrlr->is_failed = true;
+ /*
+ * The attach thread and the reset task can both fail the
+ * controller. A second queue walk would complete the same
+ * trackers again.
+ */
+ if (atomic_swap_32(&ctrlr->is_failed, 1) != 0)
+ return;
ufshci_req_queue_fail(ctrlr, &ctrlr->task_mgmt_req_queue);
ufshci_req_queue_fail(ctrlr, &ctrlr->transfer_req_queue);
@@ -312,6 +318,10 @@ ufshci_ctrlr_reset_task(void *arg, int pending)
struct ufshci_controller *ctrlr = arg;
int error;
+ /* A failed controller must not be re-enabled. */
+ if (ctrlr->is_failed)
+ return;
+
/* Release resources */
ufshci_utmr_req_queue_disable(ctrlr);
ufshci_utr_req_queue_disable(ctrlr);
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index d87651a46a2a..d65c1b126cd6 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -409,7 +409,7 @@ struct ufshci_controller {
uint32_t max_tx_lanes;
uint32_t max_rx_lanes;
- bool is_failed;
+ uint32_t is_failed;
};
#define ufshci_mmio_offsetof(reg) offsetof(struct ufshci_registers, reg)