]> git.hungrycats.org Git - linux/commitdiff
[NET_SCHED]: Fix requeueing in HFSC scheduler.
authorPatrick McHardy <kaber@trash.net>
Thu, 18 Mar 2004 12:39:50 +0000 (04:39 -0800)
committerPatrick McHardy <kaber@trash.net>
Thu, 18 Mar 2004 12:39:50 +0000 (04:39 -0800)
Requeued packets are kept in a high-priority queue
which is always dequeued first.

net/sched/sch_hfsc.c

index 1913a79c997d04441dfa791d48633e2d8770291d..46073c3f04bf81599fd7f6392fe5298cbee995ae 100644 (file)
@@ -181,12 +181,11 @@ struct hfsc_sched
 {
        u16     defcls;                         /* default class id */
        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 eligible;              /* eligible list */
        struct list_head droplist;              /* active leaf class list (for
                                                   dropping) */
+       struct sk_buff_head requeue;            /* requeued packet */
        struct timer_list wd_timer;             /* watchdog timer */
 };
 
@@ -1228,9 +1227,6 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
        list_del(&cl->siblings);
        hfsc_adjust_levels(cl->cl_parent);
        hfsc_purge_queue(sch, cl);
-       if (q->last_xmit == cl)
-               q->last_xmit = NULL;
-
        if (--cl->refcnt == 0)
                hfsc_destroy_class(sch, cl);
 
@@ -1538,6 +1534,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
                INIT_LIST_HEAD(&q->clhash[i]);
        INIT_LIST_HEAD(&q->eligible);
        INIT_LIST_HEAD(&q->droplist);
+       skb_queue_head_init(&q->requeue);
 
        q->root.refcnt  = 1;
        q->root.classid = sch->handle;
@@ -1616,10 +1613,9 @@ hfsc_reset_qdisc(struct Qdisc *sch)
                list_for_each_entry(cl, &q->clhash[i], hlist)
                        hfsc_reset_class(cl);
        }
-
+       __skb_queue_purge(&q->requeue);
        INIT_LIST_HEAD(&q->eligible);
        INIT_LIST_HEAD(&q->droplist);
-       q->last_xmit = NULL;
        del_timer(&q->wd_timer);
        sch->flags &= ~TCQ_F_THROTTLED;
        sch->q.qlen = 0;
@@ -1636,7 +1632,7 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
                list_for_each_entry_safe(cl, next, &q->clhash[i], hlist)
                        hfsc_destroy_class(sch, cl);
        }
-
+       __skb_queue_purge(&q->requeue);
        del_timer(&q->wd_timer);
 }
 
@@ -1705,6 +1701,8 @@ hfsc_dequeue(struct Qdisc *sch)
 
        if (sch->q.qlen == 0)
                return NULL;
+       if ((skb = __skb_dequeue(&q->requeue)))
+               goto out;
 
        PSCHED_GET_TIME(cur_time);
 
@@ -1754,7 +1752,7 @@ hfsc_dequeue(struct Qdisc *sch)
                set_passive(cl);
        }
 
-       q->last_xmit = cl;
+ out:
        sch->flags &= ~TCQ_F_THROTTLED;
        sch->q.qlen--;
 
@@ -1765,28 +1763,10 @@ static int
 hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
        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) {
-               kfree_skb(skb);
-               sch->stats.drops++;
-               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;
+       __skb_queue_head(&q->requeue, skb);
+       sch->q.qlen++;
+       return NET_XMIT_SUCCESS;
 }
 
 static unsigned int