mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 14:34:27 -05:00 
			
		
		
		
	Should fix recently reported data corruption issues Signed-off-by: Felix Fietkau <nbd@nbd.name>
		
			
				
	
	
		
			59 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			59 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Felix Fietkau <nbd@nbd.name>
 | 
						|
Date: Thu, 8 Mar 2018 21:00:56 +0100
 | 
						|
Subject: [PATCH] mac80211: fix memory accounting with A-MSDU aggregation
 | 
						|
 | 
						|
fq uses skb->truesize for memory usage tracking. Increments/decrements
 | 
						|
are done on enqueue/dequeue.
 | 
						|
When A-MSDU aggregation is performed on tx side, the packet is
 | 
						|
aggregated with the last packet in the queue belonging to the same flow.
 | 
						|
There are multiple bugs here:
 | 
						|
- The truesize field of the aggregated packet isn't updated, so memory
 | 
						|
usage is underestimated
 | 
						|
- fq->memory_usage isn't adjusted.
 | 
						|
 | 
						|
Because of the combination of both bugs, this only causes tx issues in
 | 
						|
rare cases, mainly when the A-MSDU head needs to be reallocated.
 | 
						|
 | 
						|
Fix this by adjusting both truesize of the A-MSDU head and adding the
 | 
						|
truesize delta to fq->memory_usage.
 | 
						|
 | 
						|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
 | 
						|
---
 | 
						|
 | 
						|
--- a/net/mac80211/tx.c
 | 
						|
+++ b/net/mac80211/tx.c
 | 
						|
@@ -3171,6 +3171,7 @@ static bool ieee80211_amsdu_aggregate(st
 | 
						|
 	u8 max_subframes = sta->sta.max_amsdu_subframes;
 | 
						|
 	int max_frags = local->hw.max_tx_fragments;
 | 
						|
 	int max_amsdu_len = sta->sta.max_amsdu_len;
 | 
						|
+	int orig_truesize;
 | 
						|
 	__be16 len;
 | 
						|
 	void *data;
 | 
						|
 	bool ret = false;
 | 
						|
@@ -3201,12 +3202,13 @@ static bool ieee80211_amsdu_aggregate(st
 | 
						|
 	flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
 | 
						|
 	head = skb_peek_tail(&flow->queue);
 | 
						|
 	if (!head)
 | 
						|
-		goto out;
 | 
						|
+		goto unlock;
 | 
						|
 
 | 
						|
+	orig_truesize = head->truesize;
 | 
						|
 	orig_len = head->len;
 | 
						|
 
 | 
						|
 	if (skb->len + head->len > max_amsdu_len)
 | 
						|
-		goto out;
 | 
						|
+		goto unlock;
 | 
						|
 
 | 
						|
 	if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
 | 
						|
 		goto out;
 | 
						|
@@ -3249,6 +3251,9 @@ static bool ieee80211_amsdu_aggregate(st
 | 
						|
 	fq_recalc_backlog(fq, tin, flow);
 | 
						|
 
 | 
						|
 out:
 | 
						|
+	fq->memory_usage += head->truesize - orig_truesize;
 | 
						|
+
 | 
						|
+unlock:
 | 
						|
 	spin_unlock_bh(&fq->lock);
 | 
						|
 
 | 
						|
 	return ret;
 |