net_sched: call qlen_notify only if child qdisc is empty
authorKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Tue, 15 Aug 2017 13:39:59 +0000 (16:39 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Aug 2017 17:55:34 +0000 (10:55 -0700)
This callback is used for deactivating class in parent qdisc.
This is cheaper to test queue length right here.

Also this allows to catch draining screwed backlog and prevent
second deactivation of already inactive parent class which will
crash kernel for sure. Kernel with print warning at destruction
of child qdisc where no packets but backlog is not zero.

Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_qfq.c

index 361377fbd78098c64853576da065731a7487b5bd..0fea0c50b7636b75b57ddf408c45ecce344813f4 100644 (file)
@@ -749,6 +749,7 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
        const struct Qdisc_class_ops *cops;
        unsigned long cl;
        u32 parentid;
+       bool notify;
        int drops;
 
        if (n == 0 && len == 0)
@@ -761,6 +762,13 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
 
                if (sch->flags & TCQ_F_NOPARENT)
                        break;
+               /* Notify parent qdisc only if child qdisc becomes empty.
+                *
+                * If child was empty even before update then backlog
+                * counter is screwed and we skip notification because
+                * parent class is already passive.
+                */
+               notify = !sch->q.qlen && !WARN_ON_ONCE(!n);
                /* TODO: perform the search on a per txq basis */
                sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
                if (sch == NULL) {
@@ -768,7 +776,7 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
                        break;
                }
                cops = sch->ops->cl_ops;
-               if (cops->qlen_notify) {
+               if (notify && cops->qlen_notify) {
                        cl = cops->get(sch, parentid);
                        cops->qlen_notify(sch, cl);
                        cops->put(sch, cl);
index 780db43300b16284192b24006b0ae8677adbe505..1bdb0106f34228553bc0a60a5a7e4c98af7579c1 100644 (file)
@@ -1385,8 +1385,7 @@ static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
 {
        struct cbq_class *cl = (struct cbq_class *)arg;
 
-       if (cl->q->q.qlen == 0)
-               cbq_deactivate_class(cl);
+       cbq_deactivate_class(cl);
 }
 
 static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
index a413dc1c209803d6fbc69c3bb7d0524ad7acb2aa..1d2f6235dfcf5a342aea1e006c870bd68ac90538 100644 (file)
@@ -246,8 +246,7 @@ static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg)
 {
        struct drr_class *cl = (struct drr_class *)arg;
 
-       if (cl->qdisc->q.qlen == 0)
-               list_del(&cl->alist);
+       list_del(&cl->alist);
 }
 
 static int drr_dump_class(struct Qdisc *sch, unsigned long arg,
index fd15200f86273add7d6c8c4a18aaef912aba7411..14c99870cdb60e1f34c87b3dfeae19f59b2fba34 100644 (file)
@@ -1221,10 +1221,8 @@ hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg)
 {
        struct hfsc_class *cl = (struct hfsc_class *)arg;
 
-       if (cl->qdisc->q.qlen == 0) {
-               update_vf(cl, 0, 0);
-               set_passive(cl);
-       }
+       update_vf(cl, 0, 0);
+       set_passive(cl);
 }
 
 static unsigned long
index 5d65ec5207e91202d501a83c983793f2e923f075..dcf3c85e1f4fad55b945e98089cc68bad17f0fa8 100644 (file)
@@ -1186,8 +1186,7 @@ static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg)
 {
        struct htb_class *cl = (struct htb_class *)arg;
 
-       if (cl->un.leaf.q->q.qlen == 0)
-               htb_deactivate(qdisc_priv(sch), cl);
+       htb_deactivate(qdisc_priv(sch), cl);
 }
 
 static unsigned long htb_get(struct Qdisc *sch, u32 classid)
index 0e16dfda0bd7f43b83dbd3b46de270e7864e154c..9caa959f91e1d7dffd64927cd60ca96bd03705e0 100644 (file)
@@ -1428,8 +1428,7 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg)
        struct qfq_sched *q = qdisc_priv(sch);
        struct qfq_class *cl = (struct qfq_class *)arg;
 
-       if (cl->qdisc->q.qlen == 0)
-               qfq_deactivate_class(q, cl);
+       qfq_deactivate_class(q, cl);
 }
 
 static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt)