net_sched: fq_codel: defer skb freeing
authorEric Dumazet <edumazet@google.com>
Tue, 14 Jun 2016 03:21:54 +0000 (20:21 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Jun 2016 21:08:35 +0000 (14:08 -0700)
Both fq_codel_change() and fq_codel_reset() can use rtnl_kfree_skbs()

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_fq_codel.c

index a302e8ef549868b170a5fb27f56010896dd0fe8e..2dc0a849515a7b54e496f5eccb224e6847d97cbd 100644 (file)
@@ -336,6 +336,12 @@ begin:
        return skb;
 }
 
+static void fq_codel_flow_purge(struct fq_codel_flow *flow)
+{
+       rtnl_kfree_skbs(flow->head, flow->tail);
+       flow->head = NULL;
+}
+
 static void fq_codel_reset(struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
@@ -346,18 +352,13 @@ static void fq_codel_reset(struct Qdisc *sch)
        for (i = 0; i < q->flows_cnt; i++) {
                struct fq_codel_flow *flow = q->flows + i;
 
-               while (flow->head) {
-                       struct sk_buff *skb = dequeue_head(flow);
-
-                       qdisc_qstats_backlog_dec(sch, skb);
-                       kfree_skb(skb);
-               }
-
+               fq_codel_flow_purge(flow);
                INIT_LIST_HEAD(&flow->flowchain);
                codel_vars_init(&flow->cvars);
        }
        memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
        sch->q.qlen = 0;
+       sch->qstats.backlog = 0;
        q->memory_usage = 0;
 }
 
@@ -433,7 +434,7 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
                struct sk_buff *skb = fq_codel_dequeue(sch);
 
                q->cstats.drop_len += qdisc_pkt_len(skb);
-               kfree_skb(skb);
+               rtnl_kfree_skbs(skb, skb);
                q->cstats.drop_count++;
        }
        qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);