Skip to content
19 changes: 5 additions & 14 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,15 +767,12 @@ static u32 qdisc_alloc_handle(struct net_device *dev)

void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
{
bool qdisc_is_offloaded = sch->flags & TCQ_F_OFFLOADED;
const struct Qdisc_class_ops *cops;
unsigned long cl;
u32 parentid;
bool notify;
int drops;

if (n == 0 && len == 0)
return;
drops = max_t(int, n, 0);
rcu_read_lock();
while ((parentid = sch->parent)) {
Expand All @@ -784,17 +781,8 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)

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.
*
* If the original child was offloaded then it is allowed
* to be seem as empty, so the parent is notified anyway.
*/
notify = !sch->q.qlen && !WARN_ON_ONCE(!n &&
!qdisc_is_offloaded);
/* Notify parent qdisc only if child qdisc becomes empty. */
notify = !sch->q.qlen;
/* TODO: perform the search on a per txq basis */
sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
if (sch == NULL) {
Expand All @@ -803,6 +791,9 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
}
cops = sch->ops->cl_ops;
if (notify && cops->qlen_notify) {
/* Note that qlen_notify must be idempotent as it may get called
* multiple times.
*/
cl = cops->find(sch, parentid);
cops->qlen_notify(sch, cl);
}
Expand Down
42 changes: 23 additions & 19 deletions net/sched/sch_ets.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ static void ets_class_qlen_notify(struct Qdisc *sch, unsigned long arg)
* to remove them.
*/
if (!ets_class_is_strict(q, cl) && sch->q.qlen)
list_del(&cl->alist);
list_del_init(&cl->alist);
}

static int ets_class_dump(struct Qdisc *sch, unsigned long arg,
Expand Down Expand Up @@ -497,7 +497,7 @@ static struct sk_buff *ets_qdisc_dequeue(struct Qdisc *sch)
if (unlikely(!skb))
goto out;
if (cl->qdisc->q.qlen == 0)
list_del(&cl->alist);
list_del_init(&cl->alist);
return ets_qdisc_dequeue_skb(sch, skb);
}

Expand Down Expand Up @@ -662,23 +662,24 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,

sch_tree_lock(sch);

q->nbands = nbands;
for (i = nbands; i < oldbands; i++) {
if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
list_del_init(&q->classes[i].alist);
qdisc_purge_queue(q->classes[i].qdisc);
}

WRITE_ONCE(q->nbands, nbands);
for (i = nstrict; i < q->nstrict; i++) {
if (q->classes[i].qdisc->q.qlen) {
list_add_tail(&q->classes[i].alist, &q->active);
q->classes[i].deficit = quanta[i];
}
}
for (i = q->nbands; i < oldbands; i++) {
if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
list_del(&q->classes[i].alist);
qdisc_tree_flush_backlog(q->classes[i].qdisc);
}
q->nstrict = nstrict;
WRITE_ONCE(q->nstrict, nstrict);
memcpy(q->prio2band, priomap, sizeof(priomap));

for (i = 0; i < q->nbands; i++)
q->classes[i].quantum = quanta[i];
WRITE_ONCE(q->classes[i].quantum, quanta[i]);

for (i = oldbands; i < q->nbands; i++) {
q->classes[i].qdisc = queues[i];
Expand All @@ -692,7 +693,7 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
for (i = q->nbands; i < oldbands; i++) {
qdisc_put(q->classes[i].qdisc);
q->classes[i].qdisc = NULL;
q->classes[i].quantum = 0;
WRITE_ONCE(q->classes[i].quantum, 0);
q->classes[i].deficit = 0;
memset(&q->classes[i].bstats, 0, sizeof(q->classes[i].bstats));
memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats));
Expand Down Expand Up @@ -727,7 +728,7 @@ static void ets_qdisc_reset(struct Qdisc *sch)

for (band = q->nstrict; band < q->nbands; band++) {
if (q->classes[band].qdisc->q.qlen)
list_del(&q->classes[band].alist);
list_del_init(&q->classes[band].alist);
}
for (band = 0; band < q->nbands; band++)
qdisc_reset(q->classes[band].qdisc);
Expand All @@ -749,6 +750,7 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb)
struct ets_sched *q = qdisc_priv(sch);
struct nlattr *opts;
struct nlattr *nest;
u8 nbands, nstrict;
int band;
int prio;
int err;
Expand All @@ -761,21 +763,22 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb)
if (!opts)
goto nla_err;

if (nla_put_u8(skb, TCA_ETS_NBANDS, q->nbands))
nbands = READ_ONCE(q->nbands);
if (nla_put_u8(skb, TCA_ETS_NBANDS, nbands))
goto nla_err;

if (q->nstrict &&
nla_put_u8(skb, TCA_ETS_NSTRICT, q->nstrict))
nstrict = READ_ONCE(q->nstrict);
if (nstrict && nla_put_u8(skb, TCA_ETS_NSTRICT, nstrict))
goto nla_err;

if (q->nbands > q->nstrict) {
if (nbands > nstrict) {
nest = nla_nest_start(skb, TCA_ETS_QUANTA);
if (!nest)
goto nla_err;

for (band = q->nstrict; band < q->nbands; band++) {
for (band = nstrict; band < nbands; band++) {
if (nla_put_u32(skb, TCA_ETS_QUANTA_BAND,
q->classes[band].quantum))
READ_ONCE(q->classes[band].quantum)))
goto nla_err;
}

Expand All @@ -787,7 +790,8 @@ static int ets_qdisc_dump(struct Qdisc *sch, struct sk_buff *skb)
goto nla_err;

for (prio = 0; prio <= TC_PRIO_MAX; prio++) {
if (nla_put_u8(skb, TCA_ETS_PRIOMAP_BAND, q->prio2band[prio]))
if (nla_put_u8(skb, TCA_ETS_PRIOMAP_BAND,
READ_ONCE(q->prio2band[prio])))
goto nla_err;
}

Expand Down
6 changes: 3 additions & 3 deletions net/sched/sch_hfsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,9 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
return err;
}

sch->qstats.backlog += len;
sch->q.qlen++;

if (first && !cl_in_el_or_vttree(cl)) {
if (cl->cl_flags & HFSC_RSC)
init_ed(cl, len);
Expand All @@ -1594,9 +1597,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)

}

sch->qstats.backlog += len;
sch->q.qlen++;

return NET_XMIT_SUCCESS;
}

Expand Down
6 changes: 4 additions & 2 deletions net/sched/sch_tbf.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
struct nlattr *tb[TCA_TBF_MAX + 1];
struct tc_tbf_qopt *qopt;
struct Qdisc *child = NULL;
struct Qdisc *old = NULL;
struct psched_ratecfg rate;
struct psched_ratecfg peak;
u64 max_size;
Expand Down Expand Up @@ -435,8 +436,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,

sch_tree_lock(sch);
if (child) {
qdisc_tree_flush_backlog(q->qdisc);
qdisc_put(q->qdisc);
qdisc_purge_queue(q->qdisc);
old = q->qdisc;
q->qdisc = child;
}
q->limit = qopt->limit;
Expand All @@ -456,6 +457,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));

sch_tree_unlock(sch);
qdisc_put(old);
err = 0;

tbf_offload_change(sch);
Expand Down