Commit 096acddf authored by Patrick McHardy's avatar Patrick McHardy

[NET_SCHED]: Fix requeueing in HFSC scheduler.

Requeued packets are kept in a high-priority queue
which is always dequeued first.
parent 18a678c4
...@@ -181,12 +181,11 @@ struct hfsc_sched ...@@ -181,12 +181,11 @@ struct hfsc_sched
{ {
u16 defcls; /* default class id */ u16 defcls; /* default class id */
struct hfsc_class root; /* root class */ struct hfsc_class root; /* root class */
struct hfsc_class *last_xmit; /* class that transmitted last
packet (for requeueing) */
struct list_head clhash[HFSC_HSIZE]; /* class hash */ struct list_head clhash[HFSC_HSIZE]; /* class hash */
struct list_head eligible; /* eligible list */ struct list_head eligible; /* eligible list */
struct list_head droplist; /* active leaf class list (for struct list_head droplist; /* active leaf class list (for
dropping) */ dropping) */
struct sk_buff_head requeue; /* requeued packet */
struct timer_list wd_timer; /* watchdog timer */ struct timer_list wd_timer; /* watchdog timer */
}; };
...@@ -1228,9 +1227,6 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg) ...@@ -1228,9 +1227,6 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
list_del(&cl->siblings); list_del(&cl->siblings);
hfsc_adjust_levels(cl->cl_parent); hfsc_adjust_levels(cl->cl_parent);
hfsc_purge_queue(sch, cl); hfsc_purge_queue(sch, cl);
if (q->last_xmit == cl)
q->last_xmit = NULL;
if (--cl->refcnt == 0) if (--cl->refcnt == 0)
hfsc_destroy_class(sch, cl); hfsc_destroy_class(sch, cl);
...@@ -1538,6 +1534,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) ...@@ -1538,6 +1534,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
INIT_LIST_HEAD(&q->clhash[i]); INIT_LIST_HEAD(&q->clhash[i]);
INIT_LIST_HEAD(&q->eligible); INIT_LIST_HEAD(&q->eligible);
INIT_LIST_HEAD(&q->droplist); INIT_LIST_HEAD(&q->droplist);
skb_queue_head_init(&q->requeue);
q->root.refcnt = 1; q->root.refcnt = 1;
q->root.classid = sch->handle; q->root.classid = sch->handle;
...@@ -1616,10 +1613,9 @@ hfsc_reset_qdisc(struct Qdisc *sch) ...@@ -1616,10 +1613,9 @@ hfsc_reset_qdisc(struct Qdisc *sch)
list_for_each_entry(cl, &q->clhash[i], hlist) list_for_each_entry(cl, &q->clhash[i], hlist)
hfsc_reset_class(cl); hfsc_reset_class(cl);
} }
__skb_queue_purge(&q->requeue);
INIT_LIST_HEAD(&q->eligible); INIT_LIST_HEAD(&q->eligible);
INIT_LIST_HEAD(&q->droplist); INIT_LIST_HEAD(&q->droplist);
q->last_xmit = NULL;
del_timer(&q->wd_timer); del_timer(&q->wd_timer);
sch->flags &= ~TCQ_F_THROTTLED; sch->flags &= ~TCQ_F_THROTTLED;
sch->q.qlen = 0; sch->q.qlen = 0;
...@@ -1636,7 +1632,7 @@ hfsc_destroy_qdisc(struct Qdisc *sch) ...@@ -1636,7 +1632,7 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) list_for_each_entry_safe(cl, next, &q->clhash[i], hlist)
hfsc_destroy_class(sch, cl); hfsc_destroy_class(sch, cl);
} }
__skb_queue_purge(&q->requeue);
del_timer(&q->wd_timer); del_timer(&q->wd_timer);
} }
...@@ -1705,6 +1701,8 @@ hfsc_dequeue(struct Qdisc *sch) ...@@ -1705,6 +1701,8 @@ hfsc_dequeue(struct Qdisc *sch)
if (sch->q.qlen == 0) if (sch->q.qlen == 0)
return NULL; return NULL;
if ((skb = __skb_dequeue(&q->requeue)))
goto out;
PSCHED_GET_TIME(cur_time); PSCHED_GET_TIME(cur_time);
...@@ -1754,7 +1752,7 @@ hfsc_dequeue(struct Qdisc *sch) ...@@ -1754,7 +1752,7 @@ hfsc_dequeue(struct Qdisc *sch)
set_passive(cl); set_passive(cl);
} }
q->last_xmit = cl; out:
sch->flags &= ~TCQ_F_THROTTLED; sch->flags &= ~TCQ_F_THROTTLED;
sch->q.qlen--; sch->q.qlen--;
...@@ -1765,28 +1763,10 @@ static int ...@@ -1765,28 +1763,10 @@ static int
hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch) hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch)
{ {
struct hfsc_sched *q = (struct hfsc_sched *)sch->data; struct hfsc_sched *q = (struct hfsc_sched *)sch->data;
struct hfsc_class *cl = q->last_xmit;
unsigned int len = skb->len;
int ret;
if (cl == NULL) { __skb_queue_head(&q->requeue, skb);
kfree_skb(skb); sch->q.qlen++;
sch->stats.drops++; return NET_XMIT_SUCCESS;
return NET_XMIT_DROP;
}
ret = cl->qdisc->ops->requeue(skb, cl->qdisc);
if (ret == NET_XMIT_SUCCESS) {
if (cl->qdisc->q.qlen == 1)
set_active(cl, len);
sch->q.qlen++;
} else {
cl->stats.drops++;
sch->stats.drops++;
}
q->last_xmit = NULL;
return ret;
} }
static unsigned int static unsigned int
......
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