mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
net_sched: call qlen_notify only if child qdisc is empty
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>
This commit is contained in:
parent
869cec99b4
commit
959466588a
6 changed files with 15 additions and 13 deletions
|
@ -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);
|
||||
|
|
|
@ -1385,7 +1385,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1221,11 +1221,9 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
hfsc_get_class(struct Qdisc *sch, u32 classid)
|
||||
|
|
|
@ -1186,7 +1186,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1428,7 +1428,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue