Commit e5f0e8f8 authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

net: sched: introduce and use qdisc tree flush/purge helpers

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: c5ad119f ("net: sched: pfifo_fast use skb_array")
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5dd431b6
...@@ -941,6 +941,23 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen, ...@@ -941,6 +941,23 @@ static inline void qdisc_qstats_qlen_backlog(struct Qdisc *sch, __u32 *qlen,
*backlog = qstats.backlog; *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) static inline void qdisc_skb_head_init(struct qdisc_skb_head *qh)
{ {
qh->head = NULL; qh->head = NULL;
...@@ -1124,13 +1141,8 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new, ...@@ -1124,13 +1141,8 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
sch_tree_lock(sch); sch_tree_lock(sch);
old = *pold; old = *pold;
*pold = new; *pold = new;
if (old != NULL) { if (old != NULL)
unsigned int qlen = old->q.qlen; qdisc_tree_flush_backlog(old);
unsigned int backlog = old->qstats.backlog;
qdisc_reset(old);
qdisc_tree_reduce_backlog(old, qlen, backlog);
}
sch_tree_unlock(sch); sch_tree_unlock(sch);
return old; return old;
......
...@@ -1667,17 +1667,13 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) ...@@ -1667,17 +1667,13 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{ {
struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class *)arg; struct cbq_class *cl = (struct cbq_class *)arg;
unsigned int qlen, backlog;
if (cl->filters || cl->children || cl == &q->link) if (cl->filters || cl->children || cl == &q->link)
return -EBUSY; return -EBUSY;
sch_tree_lock(sch); sch_tree_lock(sch);
qlen = cl->q->q.qlen; qdisc_purge_queue(cl->q);
backlog = cl->q->qstats.backlog;
qdisc_reset(cl->q);
qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
if (cl->next_alive) if (cl->next_alive)
cbq_deactivate_class(cl); cbq_deactivate_class(cl);
......
...@@ -50,15 +50,6 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid) ...@@ -50,15 +50,6 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
return container_of(clc, struct drr_class, common); 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] = { static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
[TCA_DRR_QUANTUM] = { .type = NLA_U32 }, [TCA_DRR_QUANTUM] = { .type = NLA_U32 },
}; };
...@@ -167,7 +158,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg) ...@@ -167,7 +158,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)
sch_tree_lock(sch); sch_tree_lock(sch);
drr_purge_queue(cl); qdisc_purge_queue(cl->qdisc);
qdisc_class_hash_remove(&q->clhash, &cl->common); qdisc_class_hash_remove(&q->clhash, &cl->common);
sch_tree_unlock(sch); sch_tree_unlock(sch);
......
...@@ -844,16 +844,6 @@ qdisc_peek_len(struct Qdisc *sch) ...@@ -844,16 +844,6 @@ qdisc_peek_len(struct Qdisc *sch)
return len; 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 static void
hfsc_adjust_levels(struct hfsc_class *cl) hfsc_adjust_levels(struct hfsc_class *cl)
{ {
...@@ -1076,7 +1066,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1076,7 +1066,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
qdisc_class_hash_insert(&q->clhash, &cl->cl_common); qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
list_add_tail(&cl->siblings, &parent->children); list_add_tail(&cl->siblings, &parent->children);
if (parent->level == 0) if (parent->level == 0)
hfsc_purge_queue(sch, parent); qdisc_purge_queue(parent->qdisc);
hfsc_adjust_levels(parent); hfsc_adjust_levels(parent);
sch_tree_unlock(sch); sch_tree_unlock(sch);
...@@ -1112,7 +1102,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg) ...@@ -1112,7 +1102,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
list_del(&cl->siblings); list_del(&cl->siblings);
hfsc_adjust_levels(cl->cl_parent); 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); qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
sch_tree_unlock(sch); sch_tree_unlock(sch);
......
...@@ -1269,13 +1269,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) ...@@ -1269,13 +1269,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
sch_tree_lock(sch); sch_tree_lock(sch);
if (!cl->level) { if (!cl->level)
unsigned int qlen = cl->leaf.q->q.qlen; qdisc_purge_queue(cl->leaf.q);
unsigned int backlog = cl->leaf.q->qstats.backlog;
qdisc_reset(cl->leaf.q);
qdisc_tree_reduce_backlog(cl->leaf.q, qlen, backlog);
}
/* delete from hash and active; remainder in destroy_class */ /* delete from hash and active; remainder in destroy_class */
qdisc_class_hash_remove(&q->clhash, &cl->common); qdisc_class_hash_remove(&q->clhash, &cl->common);
...@@ -1403,12 +1398,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1403,12 +1398,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
classid, NULL); classid, NULL);
sch_tree_lock(sch); sch_tree_lock(sch);
if (parent && !parent->level) { 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 */ /* turn parent into inner node */
qdisc_reset(parent->leaf.q); qdisc_purge_queue(parent->leaf.q);
qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog);
qdisc_put(parent->leaf.q); qdisc_put(parent->leaf.q);
if (parent->prio_activity) if (parent->prio_activity)
htb_deactivate(q, parent); htb_deactivate(q, parent);
......
...@@ -201,9 +201,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, ...@@ -201,9 +201,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
for (i = q->bands; i < q->max_bands; i++) { for (i = q->bands; i < q->max_bands; i++) {
if (q->queues[i] != &noop_qdisc) { if (q->queues[i] != &noop_qdisc) {
struct Qdisc *child = q->queues[i]; struct Qdisc *child = q->queues[i];
q->queues[i] = &noop_qdisc; q->queues[i] = &noop_qdisc;
qdisc_tree_reduce_backlog(child, child->q.qlen, qdisc_tree_flush_backlog(child);
child->qstats.backlog);
qdisc_put(child); qdisc_put(child);
} }
} }
...@@ -225,9 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, ...@@ -225,9 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
qdisc_hash_add(child, true); qdisc_hash_add(child, true);
if (old != &noop_qdisc) { if (old != &noop_qdisc) {
qdisc_tree_reduce_backlog(old, qdisc_tree_flush_backlog(old);
old->q.qlen,
old->qstats.backlog);
qdisc_put(old); qdisc_put(old);
} }
sch_tree_unlock(sch); sch_tree_unlock(sch);
......
...@@ -216,12 +216,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, ...@@ -216,12 +216,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
q->bands = qopt->bands; q->bands = qopt->bands;
memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
for (i = q->bands; i < oldbands; i++) { for (i = q->bands; i < oldbands; i++)
struct Qdisc *child = q->queues[i]; qdisc_tree_flush_backlog(q->queues[i]);
qdisc_tree_reduce_backlog(child, child->q.qlen,
child->qstats.backlog);
}
for (i = oldbands; i < q->bands; i++) { for (i = oldbands; i < q->bands; i++) {
q->queues[i] = queues[i]; q->queues[i] = queues[i];
......
...@@ -217,15 +217,6 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid) ...@@ -217,15 +217,6 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
return container_of(clc, struct qfq_class, common); 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] = { static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
[TCA_QFQ_WEIGHT] = { .type = NLA_U32 }, [TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
[TCA_QFQ_LMAX] = { .type = NLA_U32 }, [TCA_QFQ_LMAX] = { .type = NLA_U32 },
...@@ -551,7 +542,7 @@ static int qfq_delete_class(struct Qdisc *sch, unsigned long arg) ...@@ -551,7 +542,7 @@ static int qfq_delete_class(struct Qdisc *sch, unsigned long arg)
sch_tree_lock(sch); sch_tree_lock(sch);
qfq_purge_queue(cl); qdisc_purge_queue(cl->qdisc);
qdisc_class_hash_remove(&q->clhash, &cl->common); qdisc_class_hash_remove(&q->clhash, &cl->common);
sch_tree_unlock(sch); sch_tree_unlock(sch);
......
...@@ -233,8 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt, ...@@ -233,8 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
q->flags = ctl->flags; q->flags = ctl->flags;
q->limit = ctl->limit; q->limit = ctl->limit;
if (child) { if (child) {
qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, qdisc_tree_flush_backlog(q->qdisc);
q->qdisc->qstats.backlog);
old_child = q->qdisc; old_child = q->qdisc;
q->qdisc = child; q->qdisc = child;
} }
......
...@@ -521,8 +521,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt, ...@@ -521,8 +521,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
qdisc_hash_add(child, true); qdisc_hash_add(child, true);
sch_tree_lock(sch); sch_tree_lock(sch);
qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, qdisc_tree_flush_backlog(q->qdisc);
q->qdisc->qstats.backlog);
qdisc_put(q->qdisc); qdisc_put(q->qdisc);
q->qdisc = child; q->qdisc = child;
......
...@@ -391,8 +391,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, ...@@ -391,8 +391,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
sch_tree_lock(sch); sch_tree_lock(sch);
if (child) { if (child) {
qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, qdisc_tree_flush_backlog(q->qdisc);
q->qdisc->qstats.backlog);
qdisc_put(q->qdisc); qdisc_put(q->qdisc);
q->qdisc = child; q->qdisc = child;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment