summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2019-03-28 11:53:13 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-01 17:50:13 -0400
commite5f0e8f8e456589d56e4955154ed5d468cd6d286 (patch)
tree394e064316a0965588c3784a36a24fca3a7b352d /net
parent5dd431b6b92c0db324d134d2a4006dd4f87f2261 (diff)
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: 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>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_cbq.c6
-rw-r--r--net/sched/sch_drr.c11
-rw-r--r--net/sched/sch_hfsc.c14
-rw-r--r--net/sched/sch_htb.c15
-rw-r--r--net/sched/sch_multiq.c8
-rw-r--r--net/sched/sch_prio.c8
-rw-r--r--net/sched/sch_qfq.c11
-rw-r--r--net/sched/sch_red.c3
-rw-r--r--net/sched/sch_sfb.c3
-rw-r--r--net/sched/sch_tbf.c3
10 files changed, 16 insertions, 66 deletions
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 651879c1b655..114b9048ea7e 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1667,17 +1667,13 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
1667{ 1667{
1668 struct cbq_sched_data *q = qdisc_priv(sch); 1668 struct cbq_sched_data *q = qdisc_priv(sch);
1669 struct cbq_class *cl = (struct cbq_class *)arg; 1669 struct cbq_class *cl = (struct cbq_class *)arg;
1670 unsigned int qlen, backlog;
1671 1670
1672 if (cl->filters || cl->children || cl == &q->link) 1671 if (cl->filters || cl->children || cl == &q->link)
1673 return -EBUSY; 1672 return -EBUSY;
1674 1673
1675 sch_tree_lock(sch); 1674 sch_tree_lock(sch);
1676 1675
1677 qlen = cl->q->q.qlen; 1676 qdisc_purge_queue(cl->q);
1678 backlog = cl->q->qstats.backlog;
1679 qdisc_reset(cl->q);
1680 qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
1681 1677
1682 if (cl->next_alive) 1678 if (cl->next_alive)
1683 cbq_deactivate_class(cl); 1679 cbq_deactivate_class(cl);
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 8a181591b0ea..430df9a55ec4 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -50,15 +50,6 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
50 return container_of(clc, struct drr_class, common); 50 return container_of(clc, struct drr_class, common);
51} 51}
52 52
53static void drr_purge_queue(struct drr_class *cl)
54{
55 unsigned int len = cl->qdisc->q.qlen;
56 unsigned int backlog = cl->qdisc->qstats.backlog;
57
58 qdisc_reset(cl->qdisc);
59 qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
60}
61
62static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = { 53static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
63 [TCA_DRR_QUANTUM] = { .type = NLA_U32 }, 54 [TCA_DRR_QUANTUM] = { .type = NLA_U32 },
64}; 55};
@@ -167,7 +158,7 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)
167 158
168 sch_tree_lock(sch); 159 sch_tree_lock(sch);
169 160
170 drr_purge_queue(cl); 161 qdisc_purge_queue(cl->qdisc);
171 qdisc_class_hash_remove(&q->clhash, &cl->common); 162 qdisc_class_hash_remove(&q->clhash, &cl->common);
172 163
173 sch_tree_unlock(sch); 164 sch_tree_unlock(sch);
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index a946a419d717..d2ab463f22ae 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -845,16 +845,6 @@ qdisc_peek_len(struct Qdisc *sch)
845} 845}
846 846
847static void 847static void
848hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
849{
850 unsigned int len = cl->qdisc->q.qlen;
851 unsigned int backlog = cl->qdisc->qstats.backlog;
852
853 qdisc_reset(cl->qdisc);
854 qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
855}
856
857static void
858hfsc_adjust_levels(struct hfsc_class *cl) 848hfsc_adjust_levels(struct hfsc_class *cl)
859{ 849{
860 struct hfsc_class *p; 850 struct hfsc_class *p;
@@ -1076,7 +1066,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
1076 qdisc_class_hash_insert(&q->clhash, &cl->cl_common); 1066 qdisc_class_hash_insert(&q->clhash, &cl->cl_common);
1077 list_add_tail(&cl->siblings, &parent->children); 1067 list_add_tail(&cl->siblings, &parent->children);
1078 if (parent->level == 0) 1068 if (parent->level == 0)
1079 hfsc_purge_queue(sch, parent); 1069 qdisc_purge_queue(parent->qdisc);
1080 hfsc_adjust_levels(parent); 1070 hfsc_adjust_levels(parent);
1081 sch_tree_unlock(sch); 1071 sch_tree_unlock(sch);
1082 1072
@@ -1112,7 +1102,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
1112 list_del(&cl->siblings); 1102 list_del(&cl->siblings);
1113 hfsc_adjust_levels(cl->cl_parent); 1103 hfsc_adjust_levels(cl->cl_parent);
1114 1104
1115 hfsc_purge_queue(sch, cl); 1105 qdisc_purge_queue(cl->qdisc);
1116 qdisc_class_hash_remove(&q->clhash, &cl->cl_common); 1106 qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
1117 1107
1118 sch_tree_unlock(sch); 1108 sch_tree_unlock(sch);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index ed92836f528a..2f9883b196e8 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1269,13 +1269,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1269 1269
1270 sch_tree_lock(sch); 1270 sch_tree_lock(sch);
1271 1271
1272 if (!cl->level) { 1272 if (!cl->level)
1273 unsigned int qlen = cl->leaf.q->q.qlen; 1273 qdisc_purge_queue(cl->leaf.q);
1274 unsigned int backlog = cl->leaf.q->qstats.backlog;
1275
1276 qdisc_reset(cl->leaf.q);
1277 qdisc_tree_reduce_backlog(cl->leaf.q, qlen, backlog);
1278 }
1279 1274
1280 /* delete from hash and active; remainder in destroy_class */ 1275 /* delete from hash and active; remainder in destroy_class */
1281 qdisc_class_hash_remove(&q->clhash, &cl->common); 1276 qdisc_class_hash_remove(&q->clhash, &cl->common);
@@ -1403,12 +1398,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1403 classid, NULL); 1398 classid, NULL);
1404 sch_tree_lock(sch); 1399 sch_tree_lock(sch);
1405 if (parent && !parent->level) { 1400 if (parent && !parent->level) {
1406 unsigned int qlen = parent->leaf.q->q.qlen;
1407 unsigned int backlog = parent->leaf.q->qstats.backlog;
1408
1409 /* turn parent into inner node */ 1401 /* turn parent into inner node */
1410 qdisc_reset(parent->leaf.q); 1402 qdisc_purge_queue(parent->leaf.q);
1411 qdisc_tree_reduce_backlog(parent->leaf.q, qlen, backlog);
1412 qdisc_put(parent->leaf.q); 1403 qdisc_put(parent->leaf.q);
1413 if (parent->prio_activity) 1404 if (parent->prio_activity)
1414 htb_deactivate(q, parent); 1405 htb_deactivate(q, parent);
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 53c918a11378..35b03ae08e0f 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -201,9 +201,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
201 for (i = q->bands; i < q->max_bands; i++) { 201 for (i = q->bands; i < q->max_bands; i++) {
202 if (q->queues[i] != &noop_qdisc) { 202 if (q->queues[i] != &noop_qdisc) {
203 struct Qdisc *child = q->queues[i]; 203 struct Qdisc *child = q->queues[i];
204
204 q->queues[i] = &noop_qdisc; 205 q->queues[i] = &noop_qdisc;
205 qdisc_tree_reduce_backlog(child, child->q.qlen, 206 qdisc_tree_flush_backlog(child);
206 child->qstats.backlog);
207 qdisc_put(child); 207 qdisc_put(child);
208 } 208 }
209 } 209 }
@@ -225,9 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
225 qdisc_hash_add(child, true); 225 qdisc_hash_add(child, true);
226 226
227 if (old != &noop_qdisc) { 227 if (old != &noop_qdisc) {
228 qdisc_tree_reduce_backlog(old, 228 qdisc_tree_flush_backlog(old);
229 old->q.qlen,
230 old->qstats.backlog);
231 qdisc_put(old); 229 qdisc_put(old);
232 } 230 }
233 sch_tree_unlock(sch); 231 sch_tree_unlock(sch);
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index dfb06d5bfacc..d519b21535b3 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -216,12 +216,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
216 q->bands = qopt->bands; 216 q->bands = qopt->bands;
217 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); 217 memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
218 218
219 for (i = q->bands; i < oldbands; i++) { 219 for (i = q->bands; i < oldbands; i++)
220 struct Qdisc *child = q->queues[i]; 220 qdisc_tree_flush_backlog(q->queues[i]);
221
222 qdisc_tree_reduce_backlog(child, child->q.qlen,
223 child->qstats.backlog);
224 }
225 221
226 for (i = oldbands; i < q->bands; i++) { 222 for (i = oldbands; i < q->bands; i++) {
227 q->queues[i] = queues[i]; 223 q->queues[i] = queues[i];
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 9fbda3ec5861..1589364b54da 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -217,15 +217,6 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
217 return container_of(clc, struct qfq_class, common); 217 return container_of(clc, struct qfq_class, common);
218} 218}
219 219
220static void qfq_purge_queue(struct qfq_class *cl)
221{
222 unsigned int len = cl->qdisc->q.qlen;
223 unsigned int backlog = cl->qdisc->qstats.backlog;
224
225 qdisc_reset(cl->qdisc);
226 qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
227}
228
229static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = { 220static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
230 [TCA_QFQ_WEIGHT] = { .type = NLA_U32 }, 221 [TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
231 [TCA_QFQ_LMAX] = { .type = NLA_U32 }, 222 [TCA_QFQ_LMAX] = { .type = NLA_U32 },
@@ -551,7 +542,7 @@ static int qfq_delete_class(struct Qdisc *sch, unsigned long arg)
551 542
552 sch_tree_lock(sch); 543 sch_tree_lock(sch);
553 544
554 qfq_purge_queue(cl); 545 qdisc_purge_queue(cl->qdisc);
555 qdisc_class_hash_remove(&q->clhash, &cl->common); 546 qdisc_class_hash_remove(&q->clhash, &cl->common);
556 547
557 sch_tree_unlock(sch); 548 sch_tree_unlock(sch);
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 9df9942340ea..4e8c0abf6194 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -233,8 +233,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
233 q->flags = ctl->flags; 233 q->flags = ctl->flags;
234 q->limit = ctl->limit; 234 q->limit = ctl->limit;
235 if (child) { 235 if (child) {
236 qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, 236 qdisc_tree_flush_backlog(q->qdisc);
237 q->qdisc->qstats.backlog);
238 old_child = q->qdisc; 237 old_child = q->qdisc;
239 q->qdisc = child; 238 q->qdisc = child;
240 } 239 }
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index bab506b01a32..2419fdb75966 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -521,8 +521,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
521 qdisc_hash_add(child, true); 521 qdisc_hash_add(child, true);
522 sch_tree_lock(sch); 522 sch_tree_lock(sch);
523 523
524 qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, 524 qdisc_tree_flush_backlog(q->qdisc);
525 q->qdisc->qstats.backlog);
526 qdisc_put(q->qdisc); 525 qdisc_put(q->qdisc);
527 q->qdisc = child; 526 q->qdisc = child;
528 527
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 7f272a9070c5..f71578dbb9e3 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -391,8 +391,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
391 391
392 sch_tree_lock(sch); 392 sch_tree_lock(sch);
393 if (child) { 393 if (child) {
394 qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen, 394 qdisc_tree_flush_backlog(q->qdisc);
395 q->qdisc->qstats.backlog);
396 qdisc_put(q->qdisc); 395 qdisc_put(q->qdisc);
397 q->qdisc = child; 396 q->qdisc = child;
398 } 397 }