[NET_SCHED]: Fix endless loops (part 2): "simple" qdiscs
authorPatrick McHardy <kaber@trash.net>
Thu, 30 Nov 2006 01:36:20 +0000 (17:36 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sun, 3 Dec 2006 05:31:43 +0000 (21:31 -0800)
Convert the "simple" qdiscs to use qdisc_tree_decrease_qlen() where
necessary:

- all graft operations
- destruction of old child qdiscs in prio, red and tbf change operation
- purging of queue in sfq change operation

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/sch_cbq.c
net/sched/sch_dsmark.c
net/sched/sch_netem.c
net/sched/sch_prio.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c

index 908b10d..ba82dfa 100644 (file)
@@ -1687,7 +1687,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                sch_tree_lock(sch);
                *old = cl->q;
                cl->q = new;
-               sch->q.qlen -= (*old)->q.qlen;
+               qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
                qdisc_reset(*old);
                sch_tree_unlock(sch);
 
index afedd92..d542181 100644 (file)
@@ -96,8 +96,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
 
        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;
index 90aeeb7..672c354 100644 (file)
@@ -662,8 +662,8 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        sch_tree_lock(sch);
        *old = xchg(&q->qdisc, new);
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
-       sch->q.qlen = 0;
        sch_tree_unlock(sch);
 
        return 0;
index 3fc0c0f..2567b4c 100644 (file)
@@ -222,8 +222,10 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
 
        for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
                struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
-               if (child != &noop_qdisc)
+               if (child != &noop_qdisc) {
+                       qdisc_tree_decrease_qlen(child, child->q.qlen);
                        qdisc_destroy(child);
+               }
        }
        sch_tree_unlock(sch);
 
@@ -236,8 +238,11 @@ static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
                                sch_tree_lock(sch);
                                child = xchg(&q->queues[i], child);
 
-                               if (child != &noop_qdisc)
+                               if (child != &noop_qdisc) {
+                                       qdisc_tree_decrease_qlen(child,
+                                                                child->q.qlen);
                                        qdisc_destroy(child);
+                               }
                                sch_tree_unlock(sch);
                        }
                }
@@ -295,7 +300,7 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        sch_tree_lock(sch);
        *old = q->queues[band];
        q->queues[band] = new;
-       sch->q.qlen -= (*old)->q.qlen;
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
        sch_tree_unlock(sch);
 
index ee66c5c..acddad0 100644 (file)
@@ -229,8 +229,10 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
        sch_tree_lock(sch);
        q->flags = ctl->flags;
        q->limit = ctl->limit;
-       if (child)
+       if (child) {
+               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
                qdisc_destroy(xchg(&q->qdisc, child));
+       }
 
        red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
                                 ctl->Plog, ctl->Scell_log,
@@ -308,8 +310,8 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        sch_tree_lock(sch);
        *old = xchg(&q->qdisc, new);
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
-       sch->q.qlen = 0;
        sch_tree_unlock(sch);
        return 0;
 }
index d0d6e59..459cda2 100644 (file)
@@ -393,6 +393,7 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
        struct tc_sfq_qopt *ctl = RTA_DATA(opt);
+       unsigned int qlen;
 
        if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
                return -EINVAL;
@@ -403,8 +404,10 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
        if (ctl->limit)
                q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
 
+       qlen = sch->q.qlen;
        while (sch->q.qlen >= q->limit-1)
                sfq_drop(sch);
+       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
 
        del_timer(&q->perturb_timer);
        if (q->perturb_period) {
index 2562a60..23b7624 100644 (file)
@@ -348,8 +348,10 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
        }
 
        sch_tree_lock(sch);
-       if (child)
+       if (child) {
+               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
                qdisc_destroy(xchg(&q->qdisc, child));
+       }
        q->limit = qopt->limit;
        q->mtu = qopt->mtu;
        q->max_size = max_size;
@@ -451,8 +453,8 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        sch_tree_lock(sch);
        *old = xchg(&q->qdisc, new);
+       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
        qdisc_reset(*old);
-       sch->q.qlen = 0;
        sch_tree_unlock(sch);
 
        return 0;