OSDN Git Service

net: sched: introduce and use qdisc tree flush/purge helpers
authorPaolo Abeni <pabeni@redhat.com>
Thu, 28 Mar 2019 15:53:13 +0000 (16:53 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 1 Apr 2019 21:50:13 +0000 (14:50 -0700)
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: c5ad119fb6c0 ("net: sched: pfifo_fast use skb_array")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sch_generic.h
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_prio.c
net/sched/sch_qfq.c
net/sched/sch_red.c
net/sched/sch_sfb.c
net/sched/sch_tbf.c

index 43e4e17..a2b38b3 100644 (file)
@@ -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;
@@ -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;
index 651879c..114b904 100644 (file)
@@ -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);
index 8a18159..430df9a 100644 (file)
@@ -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 },
 };
@@ -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);
index a946a41..d2ab463 100644 (file)
@@ -845,16 +845,6 @@ qdisc_peek_len(struct Qdisc *sch)
 }
 
 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)
 {
        struct hfsc_class *p;
@@ -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);
 
@@ -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);
index ed92836..2f9883b 100644 (file)
@@ -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);
@@ -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);
index 53c918a..35b03ae 100644 (file)
@@ -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);
                }
        }
@@ -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);
index dfb06d5..d519b21 100644 (file)
@@ -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];
index 9fbda3e..1589364 100644 (file)
@@ -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 },
@@ -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);
index 9df9942..4e8c0ab 100644 (file)
@@ -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;
        }
index bab506b..2419fdb 100644 (file)
@@ -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;
 
index 7f272a9..f71578d 100644 (file)
@@ -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;
        }