]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
net_sched: update hierarchical backlog too
authorWANG Cong <xiyou.wangcong@gmail.com>
Thu, 25 Feb 2016 22:55:01 +0000 (14:55 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 29 Feb 2016 22:02:33 +0000 (17:02 -0500)
When the bottom qdisc decides to, for example, drop some packet,
it calls qdisc_tree_decrease_qlen() to update the queue length
for all its ancestors, we need to update the backlog too to
keep the stats on root qdisc accurate.

Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
21 files changed:
include/net/codel.h
include/net/sch_generic.h
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sched/sch_choke.c
net/sched/sch_codel.c
net/sched/sch_drr.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_hfsc.c
net/sched/sch_hhf.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_pie.c
net/sched/sch_prio.c
net/sched/sch_qfq.c
net/sched/sch_red.c
net/sched/sch_sfb.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c

index 267e70210061d82c22b4b2e91a9ab69cbb2b7ce7..d168aca115ccf0ff4c4ca98107327c533314c618 100644 (file)
@@ -162,12 +162,14 @@ struct codel_vars {
  * struct codel_stats - contains codel shared variables and stats
  * @maxpacket: largest packet we've seen so far
  * @drop_count:        temp count of dropped packets in dequeue()
+ * @drop_len:  bytes of dropped packets in dequeue()
  * ecn_mark:   number of packets we ECN marked instead of dropping
  * ce_mark:    number of packets CE marked because sojourn time was above ce_threshold
  */
 struct codel_stats {
        u32             maxpacket;
        u32             drop_count;
+       u32             drop_len;
        u32             ecn_mark;
        u32             ce_mark;
 };
@@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                                                                  vars->rec_inv_sqrt);
                                        goto end;
                                }
+                               stats->drop_len += qdisc_pkt_len(skb);
                                qdisc_drop(skb, sch);
                                stats->drop_count++;
                                skb = dequeue_func(vars, sch);
@@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                if (params->ecn && INET_ECN_set_ce(skb)) {
                        stats->ecn_mark++;
                } else {
+                       stats->drop_len += qdisc_pkt_len(skb);
                        qdisc_drop(skb, sch);
                        stats->drop_count++;
 
index 8fdad9f7a2fb8a659637b0ede57d3744e6c8dfc0..e5bba897d20649223bf393b94a66677177e0f554 100644 (file)
@@ -396,7 +396,8 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
                              struct Qdisc *qdisc);
 void qdisc_reset(struct Qdisc *qdisc);
 void qdisc_destroy(struct Qdisc *qdisc);
-void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
+void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
+                              unsigned int len);
 struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
                          const struct Qdisc_ops *ops);
 struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
@@ -716,7 +717,7 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
        old = *pold;
        *pold = new;
        if (old != NULL) {
-               qdisc_tree_decrease_qlen(old, old->q.qlen);
+               qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
                qdisc_reset(old);
        }
        sch_tree_unlock(sch);
index de1e176e35ccf5bc3d6ba886304b870e720f88d8..3b180ff72f79f838deac16ce9fc69e9ef28b2c0c 100644 (file)
@@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net_device *dev)
        return 0;
 }
 
-void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
+void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
+                              unsigned int len)
 {
        const struct Qdisc_class_ops *cops;
        unsigned long cl;
        u32 parentid;
        int drops;
 
-       if (n == 0)
+       if (n == 0 && len == 0)
                return;
        drops = max_t(int, n, 0);
        rcu_read_lock();
@@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
                        cops->put(sch, cl);
                }
                sch->q.qlen -= n;
+               sch->qstats.backlog -= len;
                __qdisc_qstats_drop(sch, drops);
        }
        rcu_read_unlock();
 }
-EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
+EXPORT_SYMBOL(qdisc_tree_reduce_backlog);
 
 static void notify_and_destroy(struct net *net, struct sk_buff *skb,
                               struct nlmsghdr *n, u32 clid,
index 7f8474cdce329b4fea382cab83bc00ab0952e72a..baafddf229ce98e8a4b4f2d1351845df269847fc 100644 (file)
@@ -1909,7 +1909,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
        struct cbq_class *cl = (struct cbq_class *)arg;
-       unsigned int qlen;
+       unsigned int qlen, backlog;
 
        if (cl->filters || cl->children || cl == &q->link)
                return -EBUSY;
@@ -1917,8 +1917,9 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        qlen = cl->q->q.qlen;
+       backlog = cl->q->qstats.backlog;
        qdisc_reset(cl->q);
-       qdisc_tree_decrease_qlen(cl->q, qlen);
+       qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
 
        if (cl->next_alive)
                cbq_deactivate_class(cl);
index 5ffb8b8337c7320368303e21a4bbd1fc0e4c5168..0a08c860eee4f35905907ce1eab38d6152c4487c 100644 (file)
@@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
                choke_zap_tail_holes(q);
 
        qdisc_qstats_backlog_dec(sch, skb);
+       qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
        qdisc_drop(skb, sch);
-       qdisc_tree_decrease_qlen(sch, 1);
        --sch->q.qlen;
 }
 
@@ -456,6 +456,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                old = q->tab;
                if (old) {
                        unsigned int oqlen = sch->q.qlen, tail = 0;
+                       unsigned dropped = 0;
 
                        while (q->head != q->tail) {
                                struct sk_buff *skb = q->tab[q->head];
@@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                                        ntab[tail++] = skb;
                                        continue;
                                }
+                               dropped += qdisc_pkt_len(skb);
                                qdisc_qstats_backlog_dec(sch, skb);
                                --sch->q.qlen;
                                qdisc_drop(skb, sch);
                        }
-                       qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen);
+                       qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped);
                        q->head = 0;
                        q->tail = tail;
                }
index 535007d5f0b523b13bffac7e314710f58d9ce7ef..9b7e2980ee5c64c18477d003957fedd10c1718d5 100644 (file)
@@ -79,12 +79,13 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
 
        skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue);
 
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->stats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->stats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
                q->stats.drop_count = 0;
+               q->stats.drop_len = 0;
        }
        if (skb)
                qdisc_bstats_update(sch, skb);
@@ -116,7 +117,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct codel_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_CODEL_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -156,10 +157,11 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index b96c9a8e70abca3b7a0a331d76b7baeebfadc59d..a63e879e89758fe954ab778fe776ddf6fc4e3536 100644 (file)
@@ -53,9 +53,10 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
 static void drr_purge_queue(struct drr_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
index 109b2322778f2353d82ebfbc8e40578e80ae7099..3c6a47d66a047da8765c9e90b808629a87afc0ea 100644 (file)
@@ -662,6 +662,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
        struct fq_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_FQ_MAX + 1];
        int err, drop_count = 0;
+       unsigned drop_len = 0;
        u32 fq_log;
 
        if (!opt)
@@ -736,10 +737,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 
                if (!skb)
                        break;
+               drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, drop_count);
+       qdisc_tree_reduce_backlog(sch, drop_count, drop_len);
 
        sch_tree_unlock(sch);
        return err;
index 4c834e93dafbe27bea51435113552819f7496d5b..d3fc8f9dd3d464a23f9ea924fc00154a861eda26 100644 (file)
@@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
 static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
-       unsigned int idx;
+       unsigned int idx, prev_backlog;
        struct fq_codel_flow *flow;
        int uninitialized_var(ret);
 
@@ -203,6 +203,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
@@ -211,7 +212,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -241,6 +242,7 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
        struct fq_codel_flow *flow;
        struct list_head *head;
        u32 prev_drop_count, prev_ecn_mark;
+       unsigned int prev_backlog;
 
 begin:
        head = &q->new_flows;
@@ -259,6 +261,7 @@ begin:
 
        prev_drop_count = q->cstats.drop_count;
        prev_ecn_mark = q->cstats.ecn_mark;
+       prev_backlog = sch->qstats.backlog;
 
        skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats,
                            dequeue);
@@ -276,12 +279,14 @@ begin:
        }
        qdisc_bstats_update(sch, skb);
        flow->deficit -= qdisc_pkt_len(skb);
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->cstats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
+                                         q->cstats.drop_len);
                q->cstats.drop_count = 0;
+               q->cstats.drop_len = 0;
        }
        return skb;
 }
@@ -372,11 +377,13 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_codel_dequeue(sch);
 
+               q->cstats.drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                q->cstats.drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+       qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);
        q->cstats.drop_count = 0;
+       q->cstats.drop_len = 0;
 
        sch_tree_unlock(sch);
        return 0;
index 089f3b667d3607f7b73f38a59c0895c1eb72fb64..d783d7cc33487f284677e107f5083588f559f742 100644 (file)
@@ -895,9 +895,10 @@ static void
 hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static void
index 86b04e31e60b76027214b85ee0c4c0e0de1b04c4..13d6f83ec4913f6eb8cdefa1bf3c363792c0a510 100644 (file)
@@ -382,6 +382,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        struct hhf_sched_data *q = qdisc_priv(sch);
        enum wdrr_bucket_idx idx;
        struct wdrr_bucket *bucket;
+       unsigned int prev_backlog;
 
        idx = hhf_classify(skb, sch);
 
@@ -409,6 +410,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet from this
         * bucket.
@@ -417,7 +419,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this. */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -527,7 +529,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct hhf_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_HHF_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, prev_backlog;
        int err;
        u64 non_hh_quantum;
        u32 new_quantum = q->quantum;
@@ -577,12 +579,14 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
        }
 
        qlen = sch->q.qlen;
+       prev_backlog = sch->qstats.backlog;
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = hhf_dequeue(sch);
 
                kfree_skb(skb);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen,
+                                 prev_backlog - sch->qstats.backlog);
 
        sch_tree_unlock(sch);
        return 0;
index 0efbcf358cd0d314d7f7c7d81855d60908af5d8f..846a7f98cef96886410e885a0c1c1b03f54f3f13 100644 (file)
@@ -1265,7 +1265,6 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)arg;
-       unsigned int qlen;
        struct Qdisc *new_q = NULL;
        int last_child = 0;
 
@@ -1285,9 +1284,11 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        if (!cl->level) {
-               qlen = cl->un.leaf.q->q.qlen;
+               unsigned int qlen = cl->un.leaf.q->q.qlen;
+               unsigned int backlog = cl->un.leaf.q->qstats.backlog;
+
                qdisc_reset(cl->un.leaf.q);
-               qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen);
+               qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog);
        }
 
        /* delete from hash and active; remainder in destroy_class */
@@ -1421,10 +1422,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                sch_tree_lock(sch);
                if (parent && !parent->level) {
                        unsigned int qlen = parent->un.leaf.q->q.qlen;
+                       unsigned int backlog = parent->un.leaf.q->qstats.backlog;
 
                        /* turn parent into inner node */
                        qdisc_reset(parent->un.leaf.q);
-                       qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen);
+                       qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog);
                        qdisc_destroy(parent->un.leaf.q);
                        if (parent->prio_activity)
                                htb_deactivate(q, parent);
index a0103a138563349ffb3530b412adeffc1b7f99a8..bcdd54bb101cc8f25c1b6202a7aaef9b3293d996 100644 (file)
@@ -218,7 +218,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                if (q->queues[i] != &noop_qdisc) {
                        struct Qdisc *child = q->queues[i];
                        q->queues[i] = &noop_qdisc;
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen,
+                                                 child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -238,8 +239,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
index 0a6ddaf7f56142cbab4fe0df225e90d78c106117..9640bb39a5d293d55a96edc5164d369c1cded127 100644 (file)
@@ -598,7 +598,8 @@ deliver:
                                if (unlikely(err != NET_XMIT_SUCCESS)) {
                                        if (net_xmit_drop_count(err)) {
                                                qdisc_qstats_drop(sch);
-                                               qdisc_tree_decrease_qlen(sch, 1);
+                                               qdisc_tree_reduce_backlog(sch, 1,
+                                                                         qdisc_pkt_len(skb));
                                        }
                                }
                                goto tfifo_dequeue;
index b783a446d884d85af054c9a139f91a63a162bc9f..71ae3b9629f94f8520e557f21962fc9ab34366fb 100644 (file)
@@ -183,7 +183,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct pie_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_PIE_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -232,10 +232,11 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index 1b4aaec64a24a1916deb698735c413c0f1264fe0..fee1b15506b299755c685502a4a33283b458fef5 100644 (file)
@@ -191,7 +191,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                struct Qdisc *child = q->queues[i];
                q->queues[i] = &noop_qdisc;
                if (child != &noop_qdisc) {
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -210,8 +210,9 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
index b5c52caf2e735d1d3efb528f0a96efd4f6b04af8..8d2d8d953432e83d8523cc42923793eb852f599c 100644 (file)
@@ -220,9 +220,10 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
 static void qfq_purge_queue(struct qfq_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
index d5abcee454d8c12ee960853668695550f5b458ba..8c0508c0e287742a8fbbcbf49134e76e9e52b807 100644 (file)
@@ -210,7 +210,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
        q->flags = ctl->flags;
        q->limit = ctl->limit;
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }
index 0e74e55fda158fb04e776a660c03d1e880ec3faf..c69611640fa528f340ac7948b25ae24432df6343 100644 (file)
@@ -510,7 +510,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
 
-       qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+       qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                 q->qdisc->qstats.backlog);
        qdisc_destroy(q->qdisc);
        q->qdisc = child;
 
index 3abab534eb5cd3646ea476b77433b10215602099..498f0a2cb47fca72bf504a712fdc8742cc947a1d 100644 (file)
@@ -346,7 +346,7 @@ static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned int hash;
+       unsigned int hash, dropped;
        sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
@@ -461,7 +461,7 @@ enqueue:
                return NET_XMIT_SUCCESS;
 
        qlen = slot->qlen;
-       sfq_drop(sch);
+       dropped = sfq_drop(sch);
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
         */
@@ -469,7 +469,7 @@ enqueue:
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, dropped);
        return NET_XMIT_SUCCESS;
 }
 
@@ -537,6 +537,7 @@ static void sfq_rehash(struct Qdisc *sch)
        struct sfq_slot *slot;
        struct sk_buff_head list;
        int dropped = 0;
+       unsigned int drop_len = 0;
 
        __skb_queue_head_init(&list);
 
@@ -565,6 +566,7 @@ static void sfq_rehash(struct Qdisc *sch)
                        if (x >= SFQ_MAX_FLOWS) {
 drop:
                                qdisc_qstats_backlog_dec(sch, skb);
+                               drop_len += qdisc_pkt_len(skb);
                                kfree_skb(skb);
                                dropped++;
                                continue;
@@ -594,7 +596,7 @@ drop:
                }
        }
        sch->q.qlen -= dropped;
-       qdisc_tree_decrease_qlen(sch, dropped);
+       qdisc_tree_reduce_backlog(sch, dropped, drop_len);
 }
 
 static void sfq_perturbation(unsigned long arg)
@@ -618,7 +620,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        struct sfq_sched_data *q = qdisc_priv(sch);
        struct tc_sfq_qopt *ctl = nla_data(opt);
        struct tc_sfq_qopt_v1 *ctl_v1 = NULL;
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        struct red_parms *p = NULL;
 
        if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
@@ -667,8 +669,8 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
 
        qlen = sch->q.qlen;
        while (sch->q.qlen > q->limit)
-               sfq_drop(sch);
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+               dropped += sfq_drop(sch);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        del_timer(&q->perturb_timer);
        if (q->perturb_period) {
index 56a1aef3495f43aa0bada3e7d46e303e5d237562..c2fbde742f37347d6974ed87368fd3af4425de74 100644 (file)
@@ -160,6 +160,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        struct tbf_sched_data *q = qdisc_priv(sch);
        struct sk_buff *segs, *nskb;
        netdev_features_t features = netif_skb_features(skb);
+       unsigned int len = 0, prev_len = qdisc_pkt_len(skb);
        int ret, nb;
 
        segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
@@ -172,6 +173,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
                nskb = segs->next;
                segs->next = NULL;
                qdisc_skb_cb(segs)->pkt_len = segs->len;
+               len += segs->len;
                ret = qdisc_enqueue(segs, q->qdisc);
                if (ret != NET_XMIT_SUCCESS) {
                        if (net_xmit_drop_count(ret))
@@ -183,7 +185,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        }
        sch->q.qlen += nb;
        if (nb > 1)
-               qdisc_tree_decrease_qlen(sch, 1 - nb);
+               qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len);
        consume_skb(skb);
        return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
 }
@@ -399,7 +401,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }