]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7921: fix potential deadlock in mt7921_roc_abort_sync
authorSean Wang <sean.wang@mediatek.com>
Mon, 26 Jan 2026 18:00:13 +0000 (12:00 -0600)
committerFelix Fietkau <nbd@nbd.name>
Mon, 23 Mar 2026 09:23:01 +0000 (09:23 +0000)
roc_abort_sync() can deadlock with roc_work(). roc_work() holds
dev->mt76.mutex, while cancel_work_sync() waits for roc_work()
to finish. If the caller already owns the same mutex, both
sides block and no progress is possible.

This deadlock can occur during station removal when
mt76_sta_state() -> mt76_sta_remove() -> mt7921_mac_sta_remove() ->
mt7921_roc_abort_sync() invokes cancel_work_sync() while
roc_work() is still running and holding dev->mt76.mutex.

This avoids the mutex deadlock and preserves exactly-once
work ownership.

Fixes: 352d966126e6 ("wifi: mt76: mt7921: fix a potential association failure upon resuming")
Co-developed-by: Quan Zhou <quan.zhou@mediatek.com>
Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Link: https://patch.msgid.link/20260126180013.8167-1-sean.wang@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7921/main.c

index f42e40f9663d8e03303a7b72c7c60c2ff6fdcce9..42b9514e04e716fc910b2eb27b8b18c5ac706d8a 100644 (file)
@@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev)
 {
        struct mt792x_phy *phy = &dev->phy;
 
+       if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+               return;
+
        timer_delete_sync(&phy->roc_timer);
-       cancel_work_sync(&phy->roc_work);
-       if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
-               ieee80211_iterate_interfaces(mt76_hw(dev),
-                                            IEEE80211_IFACE_ITER_RESUME_ALL,
-                                            mt7921_roc_iter, (void *)phy);
+       cancel_work(&phy->roc_work);
+
+       ieee80211_iterate_interfaces(mt76_hw(dev),
+                                    IEEE80211_IFACE_ITER_RESUME_ALL,
+                                    mt7921_roc_iter, (void *)phy);
 }
 EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync);