Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,15 +770,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 @@ -787,17 +784,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 @@ -806,6 +794,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 @@ -291,7 +291,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 @@ -493,7 +493,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 @@ -658,23 +658,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 @@ -688,7 +689,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;
gnet_stats_basic_sync_init(&q->classes[i].bstats);
memset(&q->classes[i].qstats, 0, sizeof(q->classes[i].qstats));
Expand Down Expand Up @@ -723,7 +724,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 @@ -747,6 +748,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 @@ -759,21 +761,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 @@ -785,7 +788,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 @@ -1584,6 +1584,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 @@ -1599,9 +1602,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