Convert the separately-allocated reorder_buf pointer to a C99 flexible array member at the end of struct tid_ampdu_rx, and place reorder_time in the same allocation immediately after it. This collapses three allocations into one and removes the corresponding kfree() pairs from the error and free paths. Assisted-by: Claude:Opus-4.7 Signed-off-by: Rosen Penev --- net/mac80211/agg-rx.c | 23 ++++++----------------- net/mac80211/sta_info.h | 6 +++--- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index cecd1c917e45..20669cd8a34f 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -50,8 +50,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) 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); kfree(tid_rx); } @@ -294,6 +292,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, }; int i, ret = -EOPNOTSUPP; u16 status = WLAN_STATUS_REQUEST_DECLINED; + size_t alloc_size; u16 max_buf_size; lockdep_assert_wiphy(sta->local->hw.wiphy); @@ -412,10 +411,14 @@ 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); + alloc_size = struct_size(tid_agg_rx, reorder_buf, buf_size); + alloc_size += sizeof(*tid_agg_rx->reorder_time) * buf_size; + tid_agg_rx = kzalloc(alloc_size, GFP_KERNEL); if (!tid_agg_rx) goto end; + tid_agg_rx->reorder_time = (void *)(tid_agg_rx->reorder_buf + buf_size); + spin_lock_init(&tid_agg_rx->reorder_lock); /* rx timer */ @@ -426,18 +429,6 @@ 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]); @@ -445,8 +436,6 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, 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/sta_info.h b/net/mac80211/sta_info.h index 39608a0abbb5..66adfc5c89b2 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -207,8 +207,6 @@ 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 @@ -228,6 +226,8 @@ 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_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an + * A-MSDU with individually reported subframes. * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -241,7 +241,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; @@ -256,6 +255,7 @@ struct tid_ampdu_rx { u8 auto_seq:1, removed:1, started:1; + struct sk_buff_head reorder_buf[]; }; /** -- 2.54.0