mac80211: fix a tx queue memory accounting error
Fixes rare hard to trigger tx hangs after some time Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
b7b14fd64e
commit
6011f7bcf0
1 changed files with 66 additions and 0 deletions
|
@ -0,0 +1,66 @@
|
||||||
|
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;
|
||||||
|
@@ -3241,6 +3243,7 @@ static bool ieee80211_amsdu_aggregate(st
|
||||||
|
|
||||||
|
head->len += skb->len;
|
||||||
|
head->data_len += skb->len;
|
||||||
|
+ head->truesize += skb->truesize;
|
||||||
|
*frag_tail = skb;
|
||||||
|
|
||||||
|
flow->backlog += head->len - orig_len;
|
||||||
|
@@ -3249,6 +3252,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;
|
Loading…
Reference in a new issue