diff options
author | Patrick McHardy <kaber@trash.net> | 2006-11-29 20:37:42 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:31:46 -0500 |
commit | e488eafcc50be296f0d1e1fd67c6b5d865183011 (patch) | |
tree | 792549530bf6d6e36cf48c9192194bccad158e2d /net/sched | |
parent | 256d61b87b2c2ac6fc333c1654d1abea61979006 (diff) |
[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: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_hfsc.c | 1 | ||||
-rw-r--r-- | net/sched/sch_netem.c | 5 | ||||
-rw-r--r-- | net/sched/sch_tbf.c | 2 |
3 files changed, 3 insertions, 5 deletions
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 2d437447e085..6eefa6995777 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
@@ -946,6 +946,7 @@ qdisc_peek_len(struct Qdisc *sch) | |||
946 | if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { | 946 | if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { |
947 | if (net_ratelimit()) | 947 | if (net_ratelimit()) |
948 | printk("qdisc_peek_len: failed to requeue\n"); | 948 | printk("qdisc_peek_len: failed to requeue\n"); |
949 | qdisc_tree_decrease_qlen(sch, 1); | ||
949 | return 0; | 950 | return 0; |
950 | } | 951 | } |
951 | return len; | 952 | return len; |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 672c35445793..79542af9dab1 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -287,13 +287,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) | |||
287 | psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now); | 287 | psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now); |
288 | 288 | ||
289 | if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { | 289 | if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { |
290 | qdisc_tree_decrease_qlen(q->qdisc, 1); | ||
290 | sch->qstats.drops++; | 291 | sch->qstats.drops++; |
291 | |||
292 | /* After this qlen is confused */ | ||
293 | printk(KERN_ERR "netem: queue discpline %s could not requeue\n", | 292 | printk(KERN_ERR "netem: queue discpline %s could not requeue\n", |
294 | q->qdisc->ops->id); | 293 | q->qdisc->ops->id); |
295 | |||
296 | sch->q.qlen--; | ||
297 | } | 294 | } |
298 | 295 | ||
299 | mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay)); | 296 | mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay)); |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 23b7624354f5..ed9b6d938540 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
@@ -250,7 +250,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) | |||
250 | 250 | ||
251 | if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { | 251 | if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { |
252 | /* When requeue fails skb is dropped */ | 252 | /* When requeue fails skb is dropped */ |
253 | sch->q.qlen--; | 253 | qdisc_tree_decrease_qlen(q->qdisc, 1); |
254 | sch->qstats.drops++; | 254 | sch->qstats.drops++; |
255 | } | 255 | } |
256 | 256 | ||