The branch main has been updated by jaeyoon: URL: https://cgit.FreeBSD.org/src/commit/?id=1258ae2bcb559854c966e425f4c5c48668d3cf7b
commit 1258ae2bcb559854c966e425f4c5c48668d3cf7b Author: Jaeyoon Choi <[email protected]> AuthorDate: 2026-08-27 04:58:21 +0000 Commit: Jaeyoon Choi <[email protected]> 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)
