From: Felix Fietkau Date: Thu, 8 Mar 2018 20:13:25 +0000 (+0100) Subject: mac80211: fix a tx queue memory accounting error X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=6011f7bcf0bfab0d65fb0522de0c210565fe4e74;p=openwrt%2Fstaging%2Flinusw.git mac80211: fix a tx queue memory accounting error Fixes rare hard to trigger tx hangs after some time Signed-off-by: Felix Fietkau --- diff --git a/package/kernel/mac80211/patches/378-mac80211-fix-memory-accounting-with-A-MSDU-aggregati.patch b/package/kernel/mac80211/patches/378-mac80211-fix-memory-accounting-with-A-MSDU-aggregati.patch new file mode 100644 index 0000000000..af98f6162a --- /dev/null +++ b/package/kernel/mac80211/patches/378-mac80211-fix-memory-accounting-with-A-MSDU-aggregati.patch @@ -0,0 +1,66 @@ +From: Felix Fietkau +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 +--- + +--- 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;