diff options
author | Toke Høiland-Jørgensen <toke@toke.dk> | 2016-09-23 15:59:09 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2016-09-30 07:29:21 -0400 |
commit | 097b065b5cbfa3fd57b47f3c86d6baa96c30bf31 (patch) | |
tree | 8d048e1596a0bc2b438cd5e823ab2c5233c323dc | |
parent | 92bc43bce2849c814cece258694f167d28524fbd (diff) |
fq.h: Port memory limit mechanism from fq_codel
The reusable fairness queueing implementation (fq.h) lacks the memory
usage limit that the fq_codel qdisc has. This means that small
devices (e.g. WiFi routers) can run out of memory when flooded with a
large number of packets. This ports the memory limit feature from
fq_codel to fq.h.
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/fq.h | 3 | ||||
-rw-r--r-- | include/net/fq_impl.h | 7 |
2 files changed, 9 insertions, 1 deletions
diff --git a/include/net/fq.h b/include/net/fq.h index 268b49049c37..6d8521a30c5c 100644 --- a/include/net/fq.h +++ b/include/net/fq.h | |||
@@ -72,9 +72,12 @@ struct fq { | |||
72 | u32 flows_cnt; | 72 | u32 flows_cnt; |
73 | u32 perturbation; | 73 | u32 perturbation; |
74 | u32 limit; | 74 | u32 limit; |
75 | u32 memory_limit; | ||
76 | u32 memory_usage; | ||
75 | u32 quantum; | 77 | u32 quantum; |
76 | u32 backlog; | 78 | u32 backlog; |
77 | u32 overlimit; | 79 | u32 overlimit; |
80 | u32 overmemory; | ||
78 | u32 collisions; | 81 | u32 collisions; |
79 | }; | 82 | }; |
80 | 83 | ||
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h index 163f3ed0f05a..4e6131cd3f43 100644 --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h | |||
@@ -29,6 +29,7 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq, | |||
29 | tin->backlog_packets--; | 29 | tin->backlog_packets--; |
30 | flow->backlog -= skb->len; | 30 | flow->backlog -= skb->len; |
31 | fq->backlog--; | 31 | fq->backlog--; |
32 | fq->memory_usage -= skb->truesize; | ||
32 | 33 | ||
33 | if (flow->backlog == 0) { | 34 | if (flow->backlog == 0) { |
34 | list_del_init(&flow->backlogchain); | 35 | list_del_init(&flow->backlogchain); |
@@ -154,6 +155,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
154 | flow->backlog += skb->len; | 155 | flow->backlog += skb->len; |
155 | tin->backlog_bytes += skb->len; | 156 | tin->backlog_bytes += skb->len; |
156 | tin->backlog_packets++; | 157 | tin->backlog_packets++; |
158 | fq->memory_usage += skb->truesize; | ||
157 | fq->backlog++; | 159 | fq->backlog++; |
158 | 160 | ||
159 | fq_recalc_backlog(fq, tin, flow); | 161 | fq_recalc_backlog(fq, tin, flow); |
@@ -166,7 +168,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
166 | 168 | ||
167 | __skb_queue_tail(&flow->queue, skb); | 169 | __skb_queue_tail(&flow->queue, skb); |
168 | 170 | ||
169 | if (fq->backlog > fq->limit) { | 171 | if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { |
170 | flow = list_first_entry_or_null(&fq->backlogs, | 172 | flow = list_first_entry_or_null(&fq->backlogs, |
171 | struct fq_flow, | 173 | struct fq_flow, |
172 | backlogchain); | 174 | backlogchain); |
@@ -181,6 +183,8 @@ static void fq_tin_enqueue(struct fq *fq, | |||
181 | 183 | ||
182 | flow->tin->overlimit++; | 184 | flow->tin->overlimit++; |
183 | fq->overlimit++; | 185 | fq->overlimit++; |
186 | if (fq->memory_usage > fq->memory_limit) | ||
187 | fq->overmemory++; | ||
184 | } | 188 | } |
185 | } | 189 | } |
186 | 190 | ||
@@ -251,6 +255,7 @@ static int fq_init(struct fq *fq, int flows_cnt) | |||
251 | fq->perturbation = prandom_u32(); | 255 | fq->perturbation = prandom_u32(); |
252 | fq->quantum = 300; | 256 | fq->quantum = 300; |
253 | fq->limit = 8192; | 257 | fq->limit = 8192; |
258 | fq->memory_limit = 16 << 20; /* 16 MBytes */ | ||
254 | 259 | ||
255 | fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); | 260 | fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); |
256 | if (!fq->flows) | 261 | if (!fq->flows) |