summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Wang <sean.wang@mediatek.com>2025-12-16 04:38:49 +0300
committerFelix Fietkau <nbd@nbd.name>2026-03-23 12:23:01 +0300
commitdd08ca3f092f4185ece69ce2a835c23198b1628a (patch)
treeb982cc51f4ea545524b2f831c1c6907275aae9b4
parent8c7e19612b01567f641d3ffe21e47fa21c331171 (diff)
downloadlinux-dd08ca3f092f4185ece69ce2a835c23198b1628a.tar.xz
wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync
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() -> mt7925_mac_sta_remove_link() -> mt7925_mac_link_sta_remove() -> mt7925_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: 45064d19fd3a ("wifi: mt76: mt7925: 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/20251216013849.17976-1-sean.wang@kernel.org Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 4220db3f7216..afcc0fa4aa35 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -461,12 +461,16 @@ void mt7925_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,
- mt7925_roc_iter, (void *)phy);
+
+ cancel_work(&phy->roc_work);
+
+ ieee80211_iterate_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7925_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync);