diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 361377fbd78098c64853576da065731a7487b5bd..0fea0c50b7636b75b57ddf408c45ecce344813f4 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -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); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 780db43300b16284192b24006b0ae8677adbe505..1bdb0106f34228553bc0a60a5a7e4c98af7579c1 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -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) diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index a413dc1c209803d6fbc69c3bb7d0524ad7acb2aa..1d2f6235dfcf5a342aea1e006c870bd68ac90538 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -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, diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index fd15200f86273add7d6c8c4a18aaef912aba7411..14c99870cdb60e1f34c87b3dfeae19f59b2fba34 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -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 diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 5d65ec5207e91202d501a83c983793f2e923f075..dcf3c85e1f4fad55b945e98089cc68bad17f0fa8 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -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) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 0e16dfda0bd7f43b83dbd3b46de270e7864e154c..9caa959f91e1d7dffd64927cd60ca96bd03705e0 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -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)