Skip to content

Commit

Permalink
net: sched: introduce and use qdisc tree flush/purge helpers
Browse files Browse the repository at this point in the history
The same code to flush qdisc tree and purge the qdisc queue
is duplicated in many places and in most cases it does not
respect NOLOCK qdisc: the global backlog len is used and the
per CPU values are ignored.

This change addresses the above, factoring-out the relevant
code and using the helpers introduced by the previous patch
to fetch the correct backlog len.

Fixes: c5ad119 ("net: sched: pfifo_fast use skb_array")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Paolo Abeni authored and davem330 committed Apr 1, 2019
1 parent 5dd431b commit e5f0e8f
Show file tree
Hide file tree
Showing 11 changed files with 35 additions and 73 deletions.
26 changes: 19 additions & 7 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,23 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen,
*backlog = qstats.backlog;
}

static inline void qdisc_tree_flush_backlog(struct Qdisc *sch)
{
__u32 qlen, backlog;

qdisc_qstats_qlen_backlog(sch, &qlen, &backlog);
qdisc_tree_reduce_backlog(sch, qlen, backlog);
}

static inline void qdisc_purge_queue(struct Qdisc *sch)
{
__u32 qlen, backlog;

qdisc_qstats_qlen_backlog(sch, &qlen, &backlog);
qdisc_reset(sch);
qdisc_tree_reduce_backlog(sch, qlen, backlog);
}

static inline void qdisc_skb_head_init(struct qdisc_skb_head *qh)
{
qh->head = NULL;
Expand Down Expand Up @@ -1124,13 +1141,8 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
sch_tree_lock(sch);
old = *pold;
*pold = new;
if (old != NULL) {
unsigned int qlen = old->q.qlen;
unsigned int backlog = old->qstats.backlog;

qdisc_reset(old);
qdisc_tree_reduce_backlog(old, qlen, backlog);
}
if (old != NULL)
qdisc_tree_flush_backlog(old);
sch_tree_unlock(sch);

return old;
Expand Down
6 changes: 1 addition & 5 deletions net/sched/sch_cbq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1667,17 +1667,13 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class *)arg;
unsigned int qlen, backlog;

if (cl->filters || cl->children || cl == &q->link)
return -EBUSY;

sch_tree_lock(sch);

qlen = cl->q->q.qlen;
backlog = cl->q->qstats.backlog;
qdisc_reset(cl->q);
qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
qdisc_purge_queue(cl->q);

if (cl->next_alive)
cbq_deactivate_class(cl);
Expand Down
11 changes: 1 addition & 10 deletions net/sched/sch_drr.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
return container_of(clc, struct drr_class, common);
}

static void drr_purge_queue(struct drr_class *cl)
{
unsigned int len = cl->qdisc->q.qlen;
unsigned int backlog = cl->qdisc->qstats.backlog;

qdisc_reset(cl->qdisc);
qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
}

static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
[TCA_DRR_QUANTUM] = { .type = NLA_U32 },
};
Expand Down Expand Up @@ -167,7 +158,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)

sch_tree_lock(sch);

drr_purge_queue(cl);
qdisc_purge_queue(cl->qdisc);
qdisc_class_hash_remove(&q->clhash, &cl->common);

sch_tree_unlock(sch);
Expand Down
14 changes: 2 additions & 12 deletions net/sched/sch_hfsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,16 +844,6 @@ qdisc_peek_len(struct Qdisc *sch)
return len;
}

static void
hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
{
unsigned int len = cl->qdisc->q.qlen;
unsigned int backlog = cl->qdisc->qstats.backlog;

qdisc_reset(cl->qdisc);
qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
}

static void
hfsc_adjust_levels(struct hfsc_class *cl)
{
Expand Down Expand Up @@ -1076,7 +1066,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
list_add_tail(&cl->siblings, &parent->children);
if (parent->level == 0)
hfsc_purge_queue(sch, parent);
qdisc_purge_queue(parent->qdisc);
hfsc_adjust_levels(parent);
sch_tree_unlock(sch);

Expand Down Expand Up @@ -1112,7 +1102,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
list_del(&cl->siblings);
hfsc_adjust_levels(cl->cl_parent);

hfsc_purge_queue(sch, cl);
qdisc_purge_queue(cl->qdisc);
qdisc_class_hash_remove(&q->clhash, &cl->cl_common);

sch_tree_unlock(sch);
Expand Down
15 changes: 3 additions & 12 deletions net/sched/sch_htb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1269,13 +1269,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)

sch_tree_lock(sch);

if (!cl->level) {
unsigned int qlen = cl->leaf.q->q.qlen;
unsigned int backlog = cl->leaf.q->qstats.backlog;

qdisc_reset(cl->leaf.q);
qdisc_tree_reduce_backlog(cl->leaf.q, qlen, backlog);
}
if (!cl->level)
qdisc_purge_queue(cl->leaf.q);

/* delete from hash and active; remainder in destroy_class */
qdisc_class_hash_remove(&q->clhash, &cl->common);
Expand Down Expand Up @@ -1403,12 +1398,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
classid, NULL);
sch_tree_lock(sch);
if (parent && !parent->level) {
unsigned int qlen = parent->leaf.q->q.qlen;
unsigned int backlog = parent->leaf.q->qstats.backlog;

/* turn parent into inner node */
qdisc_reset(parent->leaf.q);
qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog);
qdisc_purge_queue(parent->leaf.q);
qdisc_put(parent->leaf.q);
if (parent->prio_activity)
htb_deactivate(q, parent);
Expand Down
8 changes: 3 additions & 5 deletions net/sched/sch_multiq.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
for (i = q->bands; i < q->max_bands; i++) {
if (q->queues[i] != &noop_qdisc) {
struct Qdisc *child = q->queues[i];

q->queues[i] = &noop_qdisc;
qdisc_tree_reduce_backlog(child, child->q.qlen,
child->qstats.backlog);
qdisc_tree_flush_backlog(child);
qdisc_put(child);
}
}
Expand All @@ -225,9 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
qdisc_hash_add(child, true);

if (old != &noop_qdisc) {
qdisc_tree_reduce_backlog(old,
old->q.qlen,
old->qstats.backlog);
qdisc_tree_flush_backlog(old);
qdisc_put(old);
}
sch_tree_unlock(sch);
Expand Down
8 changes: 2 additions & 6 deletions net/sched/sch_prio.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
q->bands = qopt->bands;
memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);

for (i = q->bands; i < oldbands; i++) {
struct Qdisc *child = q->queues[i];

qdisc_tree_reduce_backlog(child, child->q.qlen,
child->qstats.backlog);
}
for (i = q->bands; i < oldbands; i++)
qdisc_tree_flush_backlog(q->queues[i]);

for (i = oldbands; i < q->bands; i++) {
q->queues[i] = queues[i];
Expand Down
11 changes: 1 addition & 10 deletions net/sched/sch_qfq.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,6 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
return container_of(clc, struct qfq_class, common);
}

static void qfq_purge_queue(struct qfq_class *cl)
{
unsigned int len = cl->qdisc->q.qlen;
unsigned int backlog = cl->qdisc->qstats.backlog;

qdisc_reset(cl->qdisc);
qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
}

static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
[TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
[TCA_QFQ_LMAX] = { .type = NLA_U32 },
Expand Down Expand Up @@ -551,7 +542,7 @@ static int qfq_delete_class(struct Qdisc *sch, unsigned long arg)

sch_tree_lock(sch);

qfq_purge_queue(cl);
qdisc_purge_queue(cl->qdisc);
qdisc_class_hash_remove(&q->clhash, &cl->common);

sch_tree_unlock(sch);
Expand Down
3 changes: 1 addition & 2 deletions net/sched/sch_red.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
q->flags = ctl->flags;
q->limit = ctl->limit;
if (child) {
qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
q->qdisc->qstats.backlog);
qdisc_tree_flush_backlog(q->qdisc);
old_child = q->qdisc;
q->qdisc = child;
}
Expand Down
3 changes: 1 addition & 2 deletions net/sched/sch_sfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
qdisc_hash_add(child, true);
sch_tree_lock(sch);

qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
q->qdisc->qstats.backlog);
qdisc_tree_flush_backlog(q->qdisc);
qdisc_put(q->qdisc);
q->qdisc = child;

Expand Down
3 changes: 1 addition & 2 deletions net/sched/sch_tbf.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,

sch_tree_lock(sch);
if (child) {
qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
q->qdisc->qstats.backlog);
qdisc_tree_flush_backlog(q->qdisc);
qdisc_put(q->qdisc);
q->qdisc = child;
}
Expand Down

0 comments on commit e5f0e8f

Please sign in to comment.