* [PATCH v2 1/5] wifi: ath10k: avoid IDR mutation during TX cleanup
2026-10-03 9:20 [PATCH v2 0/5] wifi: ath: avoid IDR mutation while iterating Jiale Yao
@ 2026-10-03 9:20 ` Jiale Yao
2026-10-03 9:20 ` [PATCH v2 2/5] wifi: ath11k: avoid IDR mutation during pending mgmt " Jiale Yao
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jiale Yao @ 2026-10-03 9:20 UTC (permalink / raw)
To: Jeff Johnson, Michal Kazior, Kalle Valo, linux-wireless, ath10k,
linux-kernel
Cc: Jiale Yao
ath10k_htt_flush_tx_queue() walks pending_tx with idr_for_each().
Its callback calls ath10k_txrx_tx_unref(), which removes the current
entry from pending_tx through ath10k_htt_tx_free_msdu_id().
idr_for_each() keeps radix-tree iterator state across the callback.
Removing the current entry can therefore invalidate that state and
make the remaining walk unsafe.
Use idr_for_each_entry(), which starts a fresh lookup after each
callback. The current entry can then be removed safely, while the
following idr_destroy() continues to release the IDR itself.
Fixes: 89d6d83565e9 ("ath10k: use idr api for msdu_ids")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/net/wireless/ath/ath10k/htt_tx.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index e46f579d745d..9993c5a2f96c 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -535,8 +535,13 @@ void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
static void ath10k_htt_flush_tx_queue(struct ath10k_htt *htt)
{
+ struct sk_buff *msdu;
+ int msdu_id;
+
ath10k_htc_stop_hl(htt->ar);
- idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
+
+ idr_for_each_entry(&htt->pending_tx, msdu, msdu_id)
+ ath10k_htt_tx_clean_up_pending(msdu_id, msdu, htt->ar);
}
void ath10k_htt_tx_stop(struct ath10k_htt *htt)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 2/5] wifi: ath11k: avoid IDR mutation during pending mgmt TX cleanup
2026-10-03 9:20 [PATCH v2 0/5] wifi: ath: avoid IDR mutation while iterating Jiale Yao
2026-10-03 9:20 ` [PATCH v2 1/5] wifi: ath10k: avoid IDR mutation during TX cleanup Jiale Yao
@ 2026-10-03 9:20 ` Jiale Yao
2026-10-03 9:21 ` [PATCH v2 3/5] wifi: ath11k: avoid IDR mutation during vif " Jiale Yao
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jiale Yao @ 2026-10-03 9:20 UTC (permalink / raw)
To: Jeff Johnson, Manikanta Pubbisetty, kbuild test robot,
Vasanthakumar Thiagarajan, Maharaja Kennadyrajan,
Rajkumar Manoharan, linux-wireless, ath11k, linux-kernel
Cc: Jiale Yao
The pending management TX cleanup walks txmgmt_idr with idr_for_each(),
and its callback removes the current entry. This can invalidate the
radix-tree iterator retained by idr_for_each().
Use idr_for_each_entry() so every iteration starts with a fresh lookup.
Continue to remove each entry under txmgmt_idr_lock before freeing its skb,
preventing concurrent TX completion from finding a stale skb pointer.
Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/net/wireless/ath/ath11k/core.c | 3 +--
drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------
drivers/net/wireless/ath/ath11k/mac.h | 2 +-
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 8039124e7832..31ac17c51036 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -2449,8 +2449,7 @@ void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
complete(&ar->thermal.wmi_sync);
wake_up(&ar->dp.tx_empty_waitq);
- idr_for_each(&ar->txmgmt_idr,
- ath11k_mac_tx_mgmt_pending_free, ar);
+ ath11k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
wake_up(&ar->txmgmt_empty_waitq);
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index ae91b57c8422..f9af403a2f0d 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -6167,13 +6167,13 @@ static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
ath11k_mgmt_over_wmi_tx_drop(ar, msdu);
}
-int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+void ath11k_mac_tx_mgmt_pending_free(struct ath11k *ar)
{
- struct ath11k *ar = ctx;
-
- ath11k_mac_tx_mgmt_free(ar, buf_id);
+ struct sk_buff *msdu;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, msdu, buf_id)
+ ath11k_mac_tx_mgmt_free(ar, buf_id);
}
static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
@@ -10417,7 +10417,7 @@ static void __ath11k_mac_unregister(struct ath11k *ar)
ieee80211_unregister_hw(ar->hw);
- idr_for_each(&ar->txmgmt_idr, ath11k_mac_tx_mgmt_pending_free, ar);
+ ath11k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h
index 59f83c7175fd..127cb476b44b 100644
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -162,7 +162,7 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
void ath11k_mac_drain_tx(struct ath11k *ar);
void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
-int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
+void ath11k_mac_tx_mgmt_pending_free(struct ath11k *ar);
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw);
enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi);
enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 3/5] wifi: ath11k: avoid IDR mutation during vif mgmt TX cleanup
2026-10-03 9:20 [PATCH v2 0/5] wifi: ath: avoid IDR mutation while iterating Jiale Yao
2026-10-03 9:20 ` [PATCH v2 1/5] wifi: ath10k: avoid IDR mutation during TX cleanup Jiale Yao
2026-10-03 9:20 ` [PATCH v2 2/5] wifi: ath11k: avoid IDR mutation during pending mgmt " Jiale Yao
@ 2026-10-03 9:21 ` Jiale Yao
2026-10-03 9:21 ` [PATCH v2 4/5] wifi: ath12k: avoid IDR mutation during pending " Jiale Yao
2026-10-03 9:21 ` [PATCH v2 5/5] wifi: ath12k: avoid IDR mutation during vif " Jiale Yao
4 siblings, 0 replies; 6+ messages in thread
From: Jiale Yao @ 2026-10-03 9:21 UTC (permalink / raw)
To: Jeff Johnson, Maharaja Kennadyrajan, Govindaraj Saminathan,
Karthikeyan Periyasamy, Rajkumar Manoharan, Sriram R,
linux-wireless, ath11k, linux-kernel
Cc: Jiale Yao
ath11k_mac_op_remove_interface() walks txmgmt_idr with idr_for_each(),
and its callback removes each entry belonging to the interface. Removing
the current entry can invalidate the radix-tree iterator retained by
idr_for_each().
Move the walk into a helper that uses idr_for_each_entry(). It performs a
fresh lookup for every iteration, so each matching entry can be removed
through the locked removal helper without retaining iterator state across
the removal.
Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/net/wireless/ath/ath11k/mac.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index f9af403a2f0d..e7ece258f142 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -6176,16 +6176,18 @@ void ath11k_mac_tx_mgmt_pending_free(struct ath11k *ar)
ath11k_mac_tx_mgmt_free(ar, buf_id);
}
-static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
+static void ath11k_mac_vif_txmgmt_cleanup(struct ath11k *ar,
+ struct ieee80211_vif *vif)
{
- struct ieee80211_vif *vif = ctx;
- struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
- struct ath11k *ar = skb_cb->ar;
-
- if (skb_cb->vif == vif)
- ath11k_mac_tx_mgmt_free(ar, buf_id);
+ struct ath11k_skb_cb *skb_cb;
+ struct sk_buff *skb;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, skb, buf_id) {
+ skb_cb = ATH11K_SKB_CB(skb);
+ if (skb_cb->vif == vif)
+ ath11k_mac_tx_mgmt_free(ar, buf_id);
+ }
}
static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
@@ -7416,8 +7418,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
ath11k_peer_cleanup(ar, arvif->vdev_id);
- idr_for_each(&ar->txmgmt_idr,
- ath11k_mac_vif_txmgmt_idr_remove, vif);
+ ath11k_mac_vif_txmgmt_cleanup(ar, vif);
for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) {
spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 4/5] wifi: ath12k: avoid IDR mutation during pending mgmt TX cleanup
2026-10-03 9:20 [PATCH v2 0/5] wifi: ath: avoid IDR mutation while iterating Jiale Yao
` (2 preceding siblings ...)
2026-10-03 9:21 ` [PATCH v2 3/5] wifi: ath11k: avoid IDR mutation during vif " Jiale Yao
@ 2026-10-03 9:21 ` Jiale Yao
2026-10-03 9:21 ` [PATCH v2 5/5] wifi: ath12k: avoid IDR mutation during vif " Jiale Yao
4 siblings, 0 replies; 6+ messages in thread
From: Jiale Yao @ 2026-10-03 9:21 UTC (permalink / raw)
To: Jeff Johnson, Carl Huang, Baochen Qiang, Pradeep Kumar Chitrapu,
Wen Gong, Kalle Valo, linux-wireless, ath12k, linux-kernel
Cc: Jiale Yao
The pending management TX cleanup walks txmgmt_idr with idr_for_each(),
and its callback removes the current entry. This can invalidate the
radix-tree iterator retained by idr_for_each().
Use idr_for_each_entry() so every iteration starts with a fresh lookup.
Continue to remove each entry under txmgmt_idr_lock before freeing its skb,
preventing concurrent TX completion from finding a stale skb pointer.
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/net/wireless/ath/ath12k/core.c | 3 +--
drivers/net/wireless/ath/ath12k/mac.c | 12 ++++++------
drivers/net/wireless/ath/ath12k/mac.h | 2 +-
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 262a2045309b..e9aa5e4e999d 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1514,8 +1514,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
complete_all(&ar->thermal.wmi_sync);
wake_up(&ar->dp.tx_empty_waitq);
- idr_for_each(&ar->txmgmt_idr,
- ath12k_mac_tx_mgmt_pending_free, ar);
+ ath12k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
wake_up(&ar->txmgmt_empty_waitq);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 99bf5cf79d10..c0acb92b7320 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -9187,13 +9187,13 @@ static void ath12k_mac_tx_mgmt_free(struct ath12k *ar, int buf_id)
ath12k_mgmt_over_wmi_tx_drop(ar, msdu);
}
-int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+void ath12k_mac_tx_mgmt_pending_free(struct ath12k *ar)
{
- struct ath12k *ar = ctx;
-
- ath12k_mac_tx_mgmt_free(ar, buf_id);
+ struct sk_buff *msdu;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, msdu, buf_id)
+ ath12k_mac_tx_mgmt_free(ar, buf_id);
}
static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
@@ -14725,7 +14725,7 @@ static struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = {
static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
{
- idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar);
+ ath12k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index aba98afd4365..ae44ebfd9bd9 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -173,7 +173,7 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
void ath12k_mac_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah);
-int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
+void ath12k_mac_tx_mgmt_pending_free(struct ath12k *ar);
enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 5/5] wifi: ath12k: avoid IDR mutation during vif mgmt TX cleanup
2026-10-03 9:20 [PATCH v2 0/5] wifi: ath: avoid IDR mutation while iterating Jiale Yao
` (3 preceding siblings ...)
2026-10-03 9:21 ` [PATCH v2 4/5] wifi: ath12k: avoid IDR mutation during pending " Jiale Yao
@ 2026-10-03 9:21 ` Jiale Yao
4 siblings, 0 replies; 6+ messages in thread
From: Jiale Yao @ 2026-10-03 9:21 UTC (permalink / raw)
To: Jeff Johnson, Vasanthakumar Thiagarajan, Balamurugan Selvarajan,
Sriram R, Carl Huang, linux-wireless, ath12k, linux-kernel
Cc: Jiale Yao
ath12k_mac_vdev_delete() walks txmgmt_idr with idr_for_each(), and its
callback removes each entry belonging to the interface. Removing the
current entry can invalidate the radix-tree iterator retained by
idr_for_each().
Move the walk into a helper that uses idr_for_each_entry(). It performs a
fresh lookup for every iteration, so each matching entry can be removed
through the locked removal helper without retaining iterator state across
the removal.
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index c0acb92b7320..108ace48cc97 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -9196,16 +9196,18 @@ void ath12k_mac_tx_mgmt_pending_free(struct ath12k *ar)
ath12k_mac_tx_mgmt_free(ar, buf_id);
}
-static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
+static void ath12k_mac_vif_txmgmt_cleanup(struct ath12k *ar,
+ struct ieee80211_vif *vif)
{
- struct ieee80211_vif *vif = ctx;
- struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
- struct ath12k *ar = skb_cb->ar;
-
- if (skb_cb->vif == vif)
- ath12k_mac_tx_mgmt_free(ar, buf_id);
+ struct ath12k_skb_cb *skb_cb;
+ struct sk_buff *skb;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, skb, buf_id) {
+ skb_cb = ATH12K_SKB_CB(skb);
+ if (skb_cb->vif == vif)
+ ath12k_mac_tx_mgmt_free(ar, buf_id);
+ }
}
static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif,
@@ -10967,8 +10969,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arv
ath12k_peer_cleanup(ar, arvif->vdev_id);
ath12k_ahvif_put_link_cache(ahvif, arvif->link_id);
- idr_for_each(&ar->txmgmt_idr,
- ath12k_mac_vif_txmgmt_idr_remove, vif);
+ ath12k_mac_vif_txmgmt_cleanup(ar, vif);
ath12k_mac_vif_unref(ath12k_ab_to_dp(ab), vif);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread