diff options
author | Patrick McHardy <kaber@trash.net> | 2006-11-29 20:37:05 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:31:45 -0500 |
commit | 256d61b87b2c2ac6fc333c1654d1abea61979006 (patch) | |
tree | 6c84f11bfc4e3179eabb21d445fe9252c5fc1b76 | |
parent | f973b913e18ab5a4795738ddf8a8666ac306ee12 (diff) |
[NET_SCHED]: Fix endless loops (part 4): HTB
Convert HTB to use qdisc_tree_decrease_len() and add a callback
for deactivating a class when its child queue becomes empty.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/sched/sch_htb.c | 24 |
1 files changed, 17 insertions, 7 deletions
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 3b36e9d60c20..215e68c2b615 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1230,11 +1230,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1230 | return -ENOBUFS; | 1230 | return -ENOBUFS; |
1231 | sch_tree_lock(sch); | 1231 | sch_tree_lock(sch); |
1232 | if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { | 1232 | if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { |
1233 | if (cl->prio_activity) | 1233 | qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); |
1234 | htb_deactivate(qdisc_priv(sch), cl); | ||
1235 | |||
1236 | /* TODO: is it correct ? Why CBQ doesn't do it ? */ | ||
1237 | sch->q.qlen -= (*old)->q.qlen; | ||
1238 | qdisc_reset(*old); | 1234 | qdisc_reset(*old); |
1239 | } | 1235 | } |
1240 | sch_tree_unlock(sch); | 1236 | sch_tree_unlock(sch); |
@@ -1249,6 +1245,14 @@ static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg) | |||
1249 | return (cl && !cl->level) ? cl->un.leaf.q : NULL; | 1245 | return (cl && !cl->level) ? cl->un.leaf.q : NULL; |
1250 | } | 1246 | } |
1251 | 1247 | ||
1248 | static void htb_qlen_notify(struct Qdisc *sch, unsigned long arg) | ||
1249 | { | ||
1250 | struct htb_class *cl = (struct htb_class *)arg; | ||
1251 | |||
1252 | if (cl->un.leaf.q->q.qlen == 0) | ||
1253 | htb_deactivate(qdisc_priv(sch), cl); | ||
1254 | } | ||
1255 | |||
1252 | static unsigned long htb_get(struct Qdisc *sch, u32 classid) | 1256 | static unsigned long htb_get(struct Qdisc *sch, u32 classid) |
1253 | { | 1257 | { |
1254 | struct htb_class *cl = htb_find(classid, sch); | 1258 | struct htb_class *cl = htb_find(classid, sch); |
@@ -1323,6 +1327,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1323 | { | 1327 | { |
1324 | struct htb_sched *q = qdisc_priv(sch); | 1328 | struct htb_sched *q = qdisc_priv(sch); |
1325 | struct htb_class *cl = (struct htb_class *)arg; | 1329 | struct htb_class *cl = (struct htb_class *)arg; |
1330 | unsigned int qlen; | ||
1326 | 1331 | ||
1327 | // TODO: why don't allow to delete subtree ? references ? does | 1332 | // TODO: why don't allow to delete subtree ? references ? does |
1328 | // tc subsys quarantee us that in htb_destroy it holds no class | 1333 | // tc subsys quarantee us that in htb_destroy it holds no class |
@@ -1336,8 +1341,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1336 | hlist_del_init(&cl->hlist); | 1341 | hlist_del_init(&cl->hlist); |
1337 | 1342 | ||
1338 | if (!cl->level) { | 1343 | if (!cl->level) { |
1339 | sch->q.qlen -= cl->un.leaf.q->q.qlen; | 1344 | qlen = cl->un.leaf.q->q.qlen; |
1340 | qdisc_reset(cl->un.leaf.q); | 1345 | qdisc_reset(cl->un.leaf.q); |
1346 | qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen); | ||
1341 | } | 1347 | } |
1342 | 1348 | ||
1343 | if (cl->prio_activity) | 1349 | if (cl->prio_activity) |
@@ -1419,8 +1425,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1419 | new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); | 1425 | new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); |
1420 | sch_tree_lock(sch); | 1426 | sch_tree_lock(sch); |
1421 | if (parent && !parent->level) { | 1427 | if (parent && !parent->level) { |
1428 | unsigned int qlen = parent->un.leaf.q->q.qlen; | ||
1429 | |||
1422 | /* turn parent into inner node */ | 1430 | /* turn parent into inner node */ |
1423 | sch->q.qlen -= parent->un.leaf.q->q.qlen; | 1431 | qdisc_reset(parent->un.leaf.q); |
1432 | qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen); | ||
1424 | qdisc_destroy(parent->un.leaf.q); | 1433 | qdisc_destroy(parent->un.leaf.q); |
1425 | if (parent->prio_activity) | 1434 | if (parent->prio_activity) |
1426 | htb_deactivate(q, parent); | 1435 | htb_deactivate(q, parent); |
@@ -1568,6 +1577,7 @@ static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) | |||
1568 | static struct Qdisc_class_ops htb_class_ops = { | 1577 | static struct Qdisc_class_ops htb_class_ops = { |
1569 | .graft = htb_graft, | 1578 | .graft = htb_graft, |
1570 | .leaf = htb_leaf, | 1579 | .leaf = htb_leaf, |
1580 | .qlen_notify = htb_qlen_notify, | ||
1571 | .get = htb_get, | 1581 | .get = htb_get, |
1572 | .put = htb_put, | 1582 | .put = htb_put, |
1573 | .change = htb_change_class, | 1583 | .change = htb_change_class, |