Commit e488eafc authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NET_SCHED]: Fix endless loops (part 5): netem/tbf/hfsc ->requeue failures

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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 256d61b8
...@@ -946,6 +946,7 @@ qdisc_peek_len(struct Qdisc *sch) ...@@ -946,6 +946,7 @@ qdisc_peek_len(struct Qdisc *sch)
if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) {
if (net_ratelimit()) if (net_ratelimit())
printk("qdisc_peek_len: failed to requeue\n"); printk("qdisc_peek_len: failed to requeue\n");
qdisc_tree_decrease_qlen(sch, 1);
return 0; return 0;
} }
return len; return len;
......
...@@ -287,13 +287,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) ...@@ -287,13 +287,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now); psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);
if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
qdisc_tree_decrease_qlen(q->qdisc, 1);
sch->qstats.drops++; sch->qstats.drops++;
/* After this qlen is confused */
printk(KERN_ERR "netem: queue discpline %s could not requeue\n", printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
q->qdisc->ops->id); q->qdisc->ops->id);
sch->q.qlen--;
} }
mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay)); mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
......
...@@ -250,7 +250,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) ...@@ -250,7 +250,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
/* When requeue fails skb is dropped */ /* When requeue fails skb is dropped */
sch->q.qlen--; qdisc_tree_decrease_qlen(q->qdisc, 1);
sch->qstats.drops++; sch->qstats.drops++;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment