summaryrefslogtreecommitdiff
path: root/net/sched/sch_dsmark.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-03-28 21:31:36 +0200
committerAdrian Bunk <bunk@stusta.de>2007-03-28 21:31:36 +0200
commit39740872332b2dd28b479d9d8333c42c32465953 (patch)
tree9cd54571212e6cffc911f9e8724d27c141e036cf /net/sched/sch_dsmark.c
parent921e8ebfc8b0e41dc724ea52f4b95b7c44f6e880 (diff)
[NET_SCHED]: Fix endless loops caused by inaccurate qlen counters
There are multiple problems related to qlen adjustment that can lead to an upper qdisc getting out of sync with the real number of packets queued, leading to endless dequeueing attempts by the upper layer code. All qdiscs must maintain an accurate q.qlen counter. There are basically two groups of operations affecting the qlen: operations that propagate down the tree (enqueue, dequeue, requeue, drop, reset) beginning at the root qdisc and operations only affecting a subtree or single qdisc (change, graft, delete class). Since qlen changes during operations from the second group don't propagate to ancestor qdiscs, their qlen values become desynchronized. This patch adds a function to propagate qlen changes up the qdisc tree, optionally calling a callback function to perform qdisc-internal maintenance when the child qdisc is deactivated, and converts all qdiscs to use this where necessary. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Adrian Bunk <bunk@stusta.de>
Diffstat (limited to 'net/sched/sch_dsmark.c')
-rw-r--r--net/sched/sch_dsmark.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 13e0e7b3856b..3e0e5b91cb4b 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -89,15 +89,16 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
sch, p, new, old);
if (new == NULL) {
- new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+ new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ sch->handle);
if (new == NULL)
new = &noop_qdisc;
}
sch_tree_lock(sch);
*old = xchg(&p->q, new);
+ qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
- sch->q.qlen = 0;
sch_tree_unlock(sch);
return 0;
@@ -388,7 +389,7 @@ static int dsmark_init(struct Qdisc *sch, struct rtattr *opt)
p->default_index = default_index;
p->set_tc_index = RTA_GET_FLAG(tb[TCA_DSMARK_SET_TC_INDEX-1]);
- p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
+ p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
if (p->q == NULL)
p->q = &noop_qdisc;