ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch b/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch
new file mode 100644
index 0000000..05a8880
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch
@@ -0,0 +1,95 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Nov 2020 18:03:46 +0100
+Subject: [PATCH] net/fq_impl: bulk-free packets from a flow on overmemory
+
+This is similar to what sch_fq_codel does. It also amortizes the worst
+case cost of a follow-up patch that changes the selection of the biggest
+flow for dropping packets
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/fq_impl.h
++++ b/include/net/fq_impl.h
+@@ -11,17 +11,25 @@
+ 
+ /* functions that are embedded into includer */
+ 
++
++static void
++__fq_adjust_removal(struct fq *fq, struct fq_flow *flow, unsigned int packets,
++		    unsigned int bytes, unsigned int truesize)
++{
++	struct fq_tin *tin = flow->tin;
++
++	tin->backlog_bytes -= bytes;
++	tin->backlog_packets -= packets;
++	flow->backlog -= bytes;
++	fq->backlog -= packets;
++	fq->memory_usage -= truesize;
++}
++
+ static void fq_adjust_removal(struct fq *fq,
+ 			      struct fq_flow *flow,
+ 			      struct sk_buff *skb)
+ {
+-	struct fq_tin *tin = flow->tin;
+-
+-	tin->backlog_bytes -= skb->len;
+-	tin->backlog_packets--;
+-	flow->backlog -= skb->len;
+-	fq->backlog--;
+-	fq->memory_usage -= skb->truesize;
++	__fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize);
+ }
+ 
+ static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
+@@ -59,6 +67,34 @@ static struct sk_buff *fq_flow_dequeue(s
+ 	return skb;
+ }
+ 
++static int fq_flow_drop(struct fq *fq, struct fq_flow *flow,
++			fq_skb_free_t free_func)
++{
++	unsigned int packets = 0, bytes = 0, truesize = 0;
++	struct fq_tin *tin = flow->tin;
++	struct sk_buff *skb;
++	int pending;
++
++	lockdep_assert_held(&fq->lock);
++
++	pending = min_t(int, 32, skb_queue_len(&flow->queue) / 2);
++	do {
++		skb = __skb_dequeue(&flow->queue);
++		if (!skb)
++			break;
++
++		packets++;
++		bytes += skb->len;
++		truesize += skb->truesize;
++		free_func(fq, tin, flow, skb);
++	} while (packets < pending);
++
++	__fq_adjust_removal(fq, flow, packets, bytes, truesize);
++	fq_rejigger_backlog(fq, flow);
++
++	return packets;
++}
++
+ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
+ 				      struct fq_tin *tin,
+ 				      fq_tin_dequeue_t dequeue_func)
+@@ -190,12 +226,9 @@ static void fq_tin_enqueue(struct fq *fq
+ 		if (!flow)
+ 			return;
+ 
+-		skb = fq_flow_dequeue(fq, flow);
+-		if (!skb)
++		if (!fq_flow_drop(fq, flow, free_func))
+ 			return;
+ 
+-		free_func(fq, flow->tin, flow, skb);
+-
+ 		flow->tin->overlimit++;
+ 		fq->overlimit++;
+ 		if (oom) {