[NET_SCHED]: Fix endless loops (part 3): HFSC
authorPatrick McHardy <kaber@trash.net>
Thu, 30 Nov 2006 01:36:43 +0000 (17:36 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sun, 3 Dec 2006 05:31:44 +0000 (21:31 -0800)
Convert HFSC to use qdisc_tree_decrease_len() and add a callback
for deactivating a class when its child queue becomes empty.

All queue purging goes through hfsc_purge_queue(), which is used in
three cases: grafting, class creation (when a leaf class is turned
into an intermediate class by attaching a new class) and class
deletion. In all cases qdisc_tree_decrease_len() is needed.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_hfsc.c

index 1142d29..2d43744 100644 (file)
@@ -957,11 +957,7 @@ hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
        unsigned int len = cl->qdisc->q.qlen;
 
        qdisc_reset(cl->qdisc);
-       if (len > 0) {
-               update_vf(cl, 0, 0);
-               set_passive(cl);
-               sch->q.qlen -= len;
-       }
+       qdisc_tree_decrease_qlen(cl->qdisc, len);
 }
 
 static void
@@ -1295,6 +1291,17 @@ hfsc_class_leaf(struct Qdisc *sch, unsigned long arg)
        return NULL;
 }
 
+static void
+hfsc_qlen_notify(struct Qdisc *sch, unsigned long arg)
+{
+       struct hfsc_class *cl = (struct hfsc_class *)arg;
+
+       if (cl->qdisc->q.qlen == 0) {
+               update_vf(cl, 0, 0);
+               set_passive(cl);
+       }
+}
+
 static unsigned long
 hfsc_get_class(struct Qdisc *sch, u32 classid)
 {
@@ -1779,6 +1786,7 @@ static struct Qdisc_class_ops hfsc_class_ops = {
        .delete         = hfsc_delete_class,
        .graft          = hfsc_graft_class,
        .leaf           = hfsc_class_leaf,
+       .qlen_notify    = hfsc_qlen_notify,
        .get            = hfsc_get_class,
        .put            = hfsc_put_class,
        .bind_tcf       = hfsc_bind_tcf,