wifi: ath10k: avoid IDR mutation during TX cleanup

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: 89d6d83565 ("ath10k: use idr api for msdu_ids")
Signed-off-by: Jiale Yao <yaojiale02@163.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Link: https://patch.msgid.link/20261003092104.520135-2-yaojiale02@163.com
[changed ath10k_htt_tx_clean_up_pending() signature]
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
Jiale Yao 2026-10-03 17:20:58 +08:00 committed by Jeff Johnson
parent ebc938ba1d
commit 1c1a208e65

View File

@ -505,9 +505,8 @@ int ath10k_htt_tx_start(struct ath10k_htt *htt)
return ret;
}
static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
static void ath10k_htt_tx_clean_up_pending(int msdu_id, struct ath10k *ar)
{
struct ath10k *ar = ctx;
struct ath10k_htt *htt = &ar->htt;
struct htt_tx_done tx_done = {};
@ -517,8 +516,6 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
ath10k_txrx_tx_unref(htt, &tx_done);
return 0;
}
void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
@ -535,8 +532,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, htt->ar);
}
void ath10k_htt_tx_stop(struct ath10k_htt *htt)