4e83ff1ea068c0c64c938e507e46bb82d660557d
[oweals/openwrt.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Thu, 8 Mar 2018 21:00:56 +0100
3 Subject: [PATCH] mac80211: fix memory accounting with A-MSDU aggregation
4
5 fq uses skb->truesize for memory usage tracking. Increments/decrements
6 are done on enqueue/dequeue.
7 When A-MSDU aggregation is performed on tx side, the packet is
8 aggregated with the last packet in the queue belonging to the same flow.
9 There are multiple bugs here:
10 - The truesize field of the aggregated packet isn't updated, so memory
11 usage is underestimated
12 - fq->memory_usage isn't adjusted.
13
14 Because of the combination of both bugs, this only causes tx issues in
15 rare cases, mainly when the A-MSDU head needs to be reallocated.
16
17 Fix this by adjusting both truesize of the A-MSDU head and adding the
18 truesize delta to fq->memory_usage.
19
20 Signed-off-by: Felix Fietkau <nbd@nbd.name>
21 ---
22
23 --- a/net/mac80211/tx.c
24 +++ b/net/mac80211/tx.c
25 @@ -3194,6 +3194,7 @@ static bool ieee80211_amsdu_aggregate(st
26         u8 max_subframes = sta->sta.max_amsdu_subframes;
27         int max_frags = local->hw.max_tx_fragments;
28         int max_amsdu_len = sta->sta.max_amsdu_len;
29 +       int orig_truesize;
30         __be16 len;
31         void *data;
32         bool ret = false;
33 @@ -3225,12 +3226,13 @@ static bool ieee80211_amsdu_aggregate(st
34         flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
35         head = skb_peek_tail(&flow->queue);
36         if (!head)
37 -               goto out;
38 +               goto unlock;
39  
40 +       orig_truesize = head->truesize;
41         orig_len = head->len;
42  
43         if (skb->len + head->len > max_amsdu_len)
44 -               goto out;
45 +               goto unlock;
46  
47         nfrags = 1 + skb_shinfo(skb)->nr_frags;
48         nfrags += 1 + skb_shinfo(head)->nr_frags;
49 @@ -3288,6 +3290,9 @@ out_recalc:
50                 fq_recalc_backlog(fq, tin, flow);
51         }
52  out:
53 +       fq->memory_usage += head->truesize - orig_truesize;
54 +
55 +unlock:
56         spin_unlock_bh(&fq->lock);
57  
58         return ret;