summary refs log tree commit diff
diff options
context:
space:
mode:
authorJarek Poplawski <jarkao2@gmail.com>2008-04-14 15:10:42 -0700
committerDavid S. Miller <davem@davemloft.net>2008-04-14 15:10:42 -0700
commit066a3b5b2346febf9a655b444567b7138e3bb939 (patch)
tree84d824c9b5e31bfaa8a4b06ba3a96f5ac68e14c5
parent159d83363b629c91d020734207c1bc788b96af5a (diff)
downloadlinux-066a3b5b2346febf9a655b444567b7138e3bb939.tar.gz
[NET_SCHED] sch_api: fix qdisc_tree_decrease_qlen() loop
TC_H_MAJ(parentid) for root classes is the same as for ingress, and if
ingress qdisc is created qdisc_lookup() returns its pointer (without
ingress NULL is returned). After this all qdisc_lookups give the same,
and we get endless loop. (I don't know how this could hide for so long
- it should trigger with every leaf class deleted if it's qdisc isn't
empty.)

After this fix qdisc_lookup() is omitted both for ingress and root
parents, but looking for root is only wasting a little time here...
Many thanks to Enrico Demarin for finding a test for catching this
bug, which probably bothered quite a lot of admins.
 
Reported-by: Enrico Demarin <enrico@superclick.com>,
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/sch_api.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 7e3c048ba9b1..fc8708a0a25e 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -386,6 +386,9 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
 	if (n == 0)
 		return;
 	while ((parentid = sch->parent)) {
+		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
+			return;
+
 		sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid));
 		if (sch == NULL) {
 			WARN_ON(parentid != TC_H_ROOT);