Re: [PATCH ath-current v2] wifi: ath11k: cleanup arsta in ath11k_mac_peer_cleanup_all()

Rameshkumar Sundaram <[email protected]> Fri, 31 Jul 2026 09:56:31 +0530
Newsgroups org.infradead.lists.ath11k,org.kernel.vger.linux-wireless
Message-ID <[email protected]>
On 7/30/2026 7:32 PM, Nicolas Escande wrote:
> When mac80211 removes a sta, it calls .sta_state() which in turn calls
> ath11k_mac_station_remove(). In that function we clean up both  peers &
> arsta related resources.
> 
> But when the firmware crashes, ath11k calls ieee80211_restart_hw(), which
> assumes that all driver related resources are cleanup up beforehand. This

nit: s/cleanup up/cleaned up

> cleanup is supposedly done by ath11k_mac_peer_cleanup_all() but does not
> in fact free arsta->rx_stats / tx_stats.
> 
> So lets extract the arsta cleanup from ath11k_mac_station_remove() into a

nit: So lets, ... or just Extract the arsta ... to be more imperative

> new ath11k_mac_station_cleanup() and call it from both there and
> ath11k_mac_peer_cleanup_all().
> 
> This should handle kmemleaks reports like:
> 	unreferenced object 0xffffff801ae66400 (size 1024):
> 	  comm "hostapd", pid 1306, jiffies 4295011565
> 	  hex dump (first 32 bytes):
> 	    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> 	    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> 	  backtrace (crc d61c08ec):
> 	    kmemleak_alloc+0x3c/0x50
> 	    __kmalloc_cache_noprof+0x2b0/0x3e0
> 	    ath11k_mac_op_sta_state+0x1dc/0xb10
> 	    drv_sta_state+0xac/0x6f8
> 	    sta_info_insert_rcu+0x314/0x5e0
> 	    sta_info_insert+0x14/0x38
> 	    ieee80211_add_station+0x10c/0x1a0
> 	    nl80211_new_station+0x3e8/0x680
> 	    genl_family_rcv_msg_doit+0xc0/0x120
> 	    genl_rcv_msg+0x1b4/0x258
> 	    netlink_rcv_skb+0x4c/0x108
> 	    genl_rcv+0x38/0x60
> 	    netlink_unicast+0x190/0x278
> 	    netlink_sendmsg+0x15c/0x370
> 	    ____sys_sendmsg+0x120/0x290
> 	    ___sys_sendmsg+0x70/0xa0
> 
> Tested-on: QCN9074 PCI WLAN.HK.2.9.0.1-01977-QCAHKSWPL_SILICONZ-1
> 
> Fixes: 9d5f28c1366f ("wifi: ath11k: fix connection failure due to unexpected peer delete")

As Baochen mentioned this should point to d5c65159f289 ath11k: driver 
for Qualcomm IEEE 802.11ax devices

older stable trees before 9d5f28c1366f would need a small contextual
backport: add the helper and replace the direct frees in 
ath11k_mac_op_sta_state() rather than in ath11k_mac_station_remove().

> Signed-off-by: Nicolas Escande <[email protected]>
> ---
>   Note: this problem is in fact older that the referenced commit, but as
>   it would need another patch to backport to older kernel and the leak is
>   quite minimal & seldom happens, I was hopping to not have to do it.
> 
> v2:
> 	- rebased on ath/master
> 	- no code change
> ---
>   drivers/net/wireless/ath/ath11k/mac.c | 25 ++++++++++++++++++-------
>   1 file changed, 18 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
> index 2d55cdc4d165..ae91b57c8422 100644
> --- a/drivers/net/wireless/ath/ath11k/mac.c
> +++ b/drivers/net/wireless/ath/ath11k/mac.c
> @@ -873,6 +873,22 @@ static int ath11k_mac_set_kickout(struct ath11k_vif *arvif)
>   	return 0;
>   }
>   
> +static void ath11k_mac_station_cleanup(struct ieee80211_sta *sta)
> +{
> +	struct ath11k_sta *arsta;
> +
> +	if (!sta)
> +		return;
> +
> +	arsta = ath11k_sta_to_arsta(sta);
> +
> +	kfree(arsta->tx_stats);
> +	arsta->tx_stats = NULL;
> +
> +	kfree(arsta->rx_stats);
> +	arsta->rx_stats = NULL;
> +}
> +
>   void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
>   {
>   	struct ath11k_peer *peer, *tmp;
> @@ -885,6 +901,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
>   	list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
>   		ath11k_peer_rx_tid_cleanup(ar, peer);
>   		ath11k_peer_rhash_delete(ab, peer);
> +		ath11k_mac_station_cleanup(peer->sta);
>   		list_del(&peer->list);
>   		kfree(peer);
>   	}
> @@ -9892,7 +9909,6 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
>   {
>   	struct ath11k_base *ab = ar->ab;
>   	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
> -	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
>   	int ret;
>   
>   	if (ab->hw_params.vdev_start_delay &&
> @@ -9916,12 +9932,7 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
>   			   sta->addr, arvif->vdev_id);
>   
>   	ath11k_mac_dec_num_stations(arvif, sta);
> -
> -	kfree(arsta->tx_stats);
> -	arsta->tx_stats = NULL;
> -
> -	kfree(arsta->rx_stats);
> -	arsta->rx_stats = NULL;
> +	ath11k_mac_station_cleanup(sta);
>   
>   	return ret;
>   }

Actual change looks fine to me