aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorstephen hemminger <stephen@networkplumber.org>2013-10-06 15:16:49 -0700
committerDavid S. Miller <davem@davemloft.net>2013-10-11 17:30:38 -0400
commitff704050f2fc0f3382b5a70bba56a51a3feca79d (patch)
treed4ba003c5b40b929ab08a50d720a9df2e69be58a /net
parent638a52b801e40ed276ceb69b73579ad99365361a (diff)
downloadlinux-ff704050f2fc0f3382b5a70bba56a51a3feca79d.tar.gz
netem: free skb's in tree on reset
Netem can leak memory because packets get stored in red-black tree and it is not cleared on reset. Reported by: Сергеев Сергей <adron@yapic.net> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_netem.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 6b75b6733e8..b87e83d0747 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -358,6 +358,21 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche
return PSCHED_NS2TICKS(ticks);
}
+static void tfifo_reset(struct Qdisc *sch)
+{
+ struct netem_sched_data *q = qdisc_priv(sch);
+ struct rb_node *p;
+
+ while ((p = rb_first(&q->t_root))) {
+ struct sk_buff *skb = netem_rb_to_skb(p);
+
+ rb_erase(p, &q->t_root);
+ skb->next = NULL;
+ skb->prev = NULL;
+ kfree_skb(skb);
+ }
+}
+
static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
{
struct netem_sched_data *q = qdisc_priv(sch);
@@ -610,6 +625,7 @@ static void netem_reset(struct Qdisc *sch)
struct netem_sched_data *q = qdisc_priv(sch);
qdisc_reset_queue(sch);
+ tfifo_reset(sch);
if (q->qdisc)
qdisc_reset(q->qdisc);
qdisc_watchdog_cancel(&q->watchdog);