[NET_SCHED]: Fix endless loops (part 5): netem/tbf/hfsc ->requeue failures
authorPatrick McHardy <kaber@trash.net>
Thu, 30 Nov 2006 01:37:42 +0000 (17:37 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Sun, 3 Dec 2006 05:31:46 +0000 (21:31 -0800)
When peeking at the next packet in a child qdisc by calling dequeue/requeue,
the upper qdisc qlen counter may get out of sync in case the requeue fails.
The qdisc and the child qdisc both have their counter decremented, but since
no packet is given to the upper qdisc it won't decrement its counter itself.

requeue should not fail, so this is mostly for "correctness".

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

index 2d437447e0855a50bef5776aca292c80727d43df..6eefa69957772956628a5d74888570af99e01ee0 100644 (file)
@@ -946,6 +946,7 @@ qdisc_peek_len(struct Qdisc *sch)
        if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) {
                if (net_ratelimit())
                        printk("qdisc_peek_len: failed to requeue\n");
+               qdisc_tree_decrease_qlen(sch, 1);
                return 0;
        }
        return len;
index 672c35445793dbd130f55f57e80b6dabe9cafb8a..79542af9dab1fb3213778011d3222e34bd202e0c 100644 (file)
@@ -287,13 +287,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                        psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);
 
                        if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
+                               qdisc_tree_decrease_qlen(q->qdisc, 1);
                                sch->qstats.drops++;
-
-                               /* After this qlen is confused */
                                printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
                                       q->qdisc->ops->id);
-
-                               sch->q.qlen--;
                        }
 
                        mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
index 23b7624354f573058b48ac0d5f8dd1cb8738e312..ed9b6d93854086e004979a41e3b68a79135a02b5 100644 (file)
@@ -250,7 +250,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 
                if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
                        /* When requeue fails skb is dropped */
-                       sch->q.qlen--;
+                       qdisc_tree_decrease_qlen(q->qdisc, 1);
                        sch->qstats.drops++;
                }