From: Rosen Penev Date: Fri, 5 Jun 2026 00:56:27 +0000 (-0700) Subject: wifi: mac80211: fold tid_ampdu_rx allocations into a flexible array X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b978c424cbfb1f5ab024db12cf7b813fa4e23ca0;p=thirdparty%2Flinux.git wifi: mac80211: fold tid_ampdu_rx allocations into a flexible array Convert the separately-allocated reorder_buf pointer to a C99 flexible array member at the end of struct tid_ampdu_rx, with both the sk_buff_head and the jiffies timestamp in each array element. This collapses three allocations into one and removes the corresponding kfree() pairs from the error and free paths. Assisted-by: opencode:big-pickle Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260605005627.317194-1-rosenp@gmail.com [fix kernel-doc] Signed-off-by: Johannes Berg --- diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 0140ac826b23..9629e00069a1 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -49,9 +49,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) int i; for (i = 0; i < tid_rx->buf_size; i++) - __skb_queue_purge(&tid_rx->reorder_buf[i]); - kfree(tid_rx->reorder_buf); - kfree(tid_rx->reorder_time); + __skb_queue_purge(&tid_rx->reorder[i].buf); kfree(tid_rx); } @@ -412,7 +410,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, } /* prepare A-MPDU MLME for Rx aggregation */ - tid_agg_rx = kzalloc_obj(*tid_agg_rx); + tid_agg_rx = kzalloc_flex(*tid_agg_rx, reorder, buf_size); if (!tid_agg_rx) goto end; @@ -426,27 +424,13 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, timer_setup(&tid_agg_rx->reorder_timer, sta_rx_agg_reorder_timer_expired, 0); - /* prepare reordering buffer */ - tid_agg_rx->reorder_buf = - kzalloc_objs(struct sk_buff_head, buf_size); - tid_agg_rx->reorder_time = - kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); - if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { - kfree(tid_agg_rx->reorder_buf); - kfree(tid_agg_rx->reorder_time); - kfree(tid_agg_rx); - goto end; - } - for (i = 0; i < buf_size; i++) - __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); + __skb_queue_head_init(&tid_agg_rx->reorder[i].buf); ret = drv_ampdu_action(local, sta->sdata, ¶ms); ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", sta->sta.addr, tid, ret); if (ret) { - kfree(tid_agg_rx->reorder_buf); - kfree(tid_agg_rx->reorder_time); kfree(tid_agg_rx); goto end; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index db421edfd54c..fb9a3574afe9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1188,7 +1188,7 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx, int index) { - struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index]; + struct sk_buff_head *frames = &tid_agg_rx->reorder[index].buf; struct sk_buff *tail = skb_peek_tail(frames); struct ieee80211_rx_status *status; @@ -1211,7 +1211,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, int index, struct sk_buff_head *frames) { - struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; + struct sk_buff_head *skb_list = &tid_agg_rx->reorder[index].buf; struct sk_buff *skb; struct ieee80211_rx_status *status; @@ -1290,14 +1290,14 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, continue; } if (skipped && - !time_after(jiffies, tid_agg_rx->reorder_time[j] + + !time_after(jiffies, tid_agg_rx->reorder[j].time + HT_RX_REORDER_BUF_TIMEOUT)) goto set_release_timer; /* don't leave incomplete A-MSDUs around */ for (i = (index + 1) % tid_agg_rx->buf_size; i != j; i = (i + 1) % tid_agg_rx->buf_size) - __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); + __skb_queue_purge(&tid_agg_rx->reorder[i].buf); ht_dbg_ratelimited(sdata, "release an RX reorder frame due to timeout on earlier frames\n"); @@ -1331,7 +1331,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, if (!tid_agg_rx->removed) mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + 1 + + tid_agg_rx->reorder[j].time + 1 + HT_RX_REORDER_BUF_TIMEOUT); } else { timer_delete(&tid_agg_rx->reorder_timer); @@ -1426,9 +1426,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata } /* put the frame in the reordering buffer */ - __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); + __skb_queue_tail(&tid_agg_rx->reorder[index].buf, skb); if (!(status->flag & RX_FLAG_AMSDU_MORE)) { - tid_agg_rx->reorder_time[index] = jiffies; + tid_agg_rx->reorder[index].time = jiffies; tid_agg_rx->stored_mpdu_num++; ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 26138934b72e..5da3142d8516 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -207,11 +207,8 @@ struct tid_ampdu_tx { /** * struct tid_ampdu_rx - TID aggregation information (Rx). * - * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an - * A-MSDU with individually reported subframes. * @reorder_buf_filtered: bitmap indicating where there are filtered frames in * the reorder buffer that should be ignored when releasing frames - * @reorder_time: jiffies when skb was added * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) * @reorder_timer: releases expired frames from the reorder buffer. * @sta: station we are attached to @@ -228,6 +225,10 @@ struct tid_ampdu_tx { * and ssn. * @removed: this session is removed (but might have been found due to RCU) * @started: this session has started (head ssn or higher was received) + * @reorder: reorder buffer entries + * @reorder.buf: &struct sk_buff_head for the frames, since there could be + * multiple at each entry from an A-MSDU reported as individual subframes + * @reorder.time: time when this entry was filled (jiffies) * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -241,8 +242,6 @@ struct tid_ampdu_rx { struct rcu_head rcu_head; spinlock_t reorder_lock; u64 reorder_buf_filtered; - struct sk_buff_head *reorder_buf; - unsigned long *reorder_time; struct sta_info *sta; struct timer_list session_timer; struct timer_list reorder_timer; @@ -256,6 +255,10 @@ struct tid_ampdu_rx { u8 auto_seq:1, removed:1, started:1; + struct { + struct sk_buff_head buf; + unsigned long time; + } reorder[]; }; /**