summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-11-25 00:46:08 +0100
committerDavid S. Miller <davem@davemloft.net>2008-11-25 00:46:08 +0100
commit3f0947c3ffaed33c1c38b79e4b17f75ba072d3e9 (patch)
treeaabc1d3fadbfbfb97b2fe56884fad70197e50d47
parentinfiniband: Kill directly reference of netdev->priv (diff)
downloadlinux-3f0947c3ffaed33c1c38b79e4b17f75ba072d3e9.tar.xz
linux-3f0947c3ffaed33c1c38b79e4b17f75ba072d3e9.zip
pkt_sched: sch_drr: fix drr_dequeue loop()
Jarek Poplawski points out: If all child qdiscs of sch_drr are non-work-conserving (e.g. sch_tbf) drr_dequeue() will busy-loop waiting for skbs instead of leaving the job for a watchdog. Checking for list_empty() in each loop isn't necessary either, because this can never be true except the first time. Using non-work-conserving qdiscs as children of DRR makes no sense, simply bail out in that case. Reported-by: Jarek Poplawski <jarkao2@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/sch_drr.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 37e6ab99bbea..e7a7e87b141a 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -373,11 +373,13 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
struct sk_buff *skb;
unsigned int len;
- while (!list_empty(&q->active)) {
+ if (list_empty(&q->active))
+ goto out;
+ while (1) {
cl = list_first_entry(&q->active, struct drr_class, alist);
skb = cl->qdisc->ops->peek(cl->qdisc);
if (skb == NULL)
- goto skip;
+ goto out;
len = qdisc_pkt_len(skb);
if (len <= cl->deficit) {
@@ -390,9 +392,9 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
}
cl->deficit += cl->quantum;
-skip:
list_move_tail(&cl->alist, &q->active);
}
+out:
return NULL;
}