Merge tag 'metag-for-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jhogan...
[deliverable/linux.git] / net / sched / sch_hfsc.c
index 1ac9f9f03fe31fdf8d63eccfad0c7a13939183c6..3ddc7bd74ecb38e76eb09060209df150c685319d 100644 (file)
@@ -115,9 +115,9 @@ struct hfsc_class {
        struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est64 rate_est;
-       unsigned int    level;          /* class level in hierarchy */
        struct tcf_proto __rcu *filter_list; /* filter list */
        unsigned int    filter_cnt;     /* filter count */
+       unsigned int    level;          /* class level in hierarchy */
 
        struct hfsc_sched *sched;       /* scheduler data */
        struct hfsc_class *cl_parent;   /* parent class */
@@ -130,7 +130,6 @@ struct hfsc_class {
        struct rb_node vt_node;         /* parent's vt_tree member */
        struct rb_root cf_tree;         /* active children sorted by cl_f */
        struct rb_node cf_node;         /* parent's cf_heap member */
-       struct list_head dlist;         /* drop list member */
 
        u64     cl_total;               /* total work in bytes */
        u64     cl_cumul;               /* cumulative work in bytes done by
@@ -166,10 +165,10 @@ struct hfsc_class {
        struct runtime_sc cl_virtual;   /* virtual curve */
        struct runtime_sc cl_ulimit;    /* upperlimit curve */
 
-       unsigned long   cl_flags;       /* which curves are valid */
-       unsigned long   cl_vtperiod;    /* vt period sequence number */
-       unsigned long   cl_parentperiod;/* parent's vt period sequence number*/
-       unsigned long   cl_nactive;     /* number of active children */
+       u8              cl_flags;       /* which curves are valid */
+       u32             cl_vtperiod;    /* vt period sequence number */
+       u32             cl_parentperiod;/* parent's vt period sequence number*/
+       u32             cl_nactive;     /* number of active children */
 };
 
 struct hfsc_sched {
@@ -177,8 +176,6 @@ struct hfsc_sched {
        struct hfsc_class root;                 /* root class */
        struct Qdisc_class_hash clhash;         /* class hash */
        struct rb_root eligible;                /* eligible tree */
-       struct list_head droplist;              /* active leaf class list (for
-                                                  dropping) */
        struct qdisc_watchdog watchdog;         /* watchdog timer */
 };
 
@@ -781,6 +778,20 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
                else
                        go_passive = 0;
 
+               /* update vt */
+               cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total)
+                           - cl->cl_vtoff + cl->cl_vtadj;
+
+               /*
+                * if vt of the class is smaller than cvtmin,
+                * the class was skipped in the past due to non-fit.
+                * if so, we need to adjust vtadj.
+                */
+               if (cl->cl_vt < cl->cl_parent->cl_cvtmin) {
+                       cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt;
+                       cl->cl_vt = cl->cl_parent->cl_cvtmin;
+               }
+
                if (go_passive) {
                        /* no more active child, going passive */
 
@@ -797,25 +808,10 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
                        continue;
                }
 
-               /*
-                * update vt and f
-                */
-               cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total)
-                           - cl->cl_vtoff + cl->cl_vtadj;
-
-               /*
-                * if vt of the class is smaller than cvtmin,
-                * the class was skipped in the past due to non-fit.
-                * if so, we need to adjust vtadj.
-                */
-               if (cl->cl_vt < cl->cl_parent->cl_cvtmin) {
-                       cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt;
-                       cl->cl_vt = cl->cl_parent->cl_cvtmin;
-               }
-
                /* update the vt tree */
                vttree_update(cl);
 
+               /* update f */
                if (cl->cl_flags & HFSC_USC) {
                        cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit,
                                                              cl->cl_total);
@@ -858,7 +854,6 @@ set_active(struct hfsc_class *cl, unsigned int len)
        if (cl->cl_flags & HFSC_FSC)
                init_vf(cl, len);
 
-       list_add_tail(&cl->dlist, &cl->sched->droplist);
 }
 
 static void
@@ -867,8 +862,6 @@ set_passive(struct hfsc_class *cl)
        if (cl->cl_flags & HFSC_RSC)
                eltree_remove(cl);
 
-       list_del(&cl->dlist);
-
        /*
         * vttree is now handled in update_vf() so that update_vf(cl, 0, 0)
         * needs to be called explicitly to remove a class from vttree.
@@ -882,7 +875,7 @@ qdisc_peek_len(struct Qdisc *sch)
        unsigned int len;
 
        skb = sch->ops->peek(sch);
-       if (skb == NULL) {
+       if (unlikely(skb == NULL)) {
                qdisc_warn_nonwc("qdisc_peek_len", sch);
                return 0;
        }
@@ -947,7 +940,7 @@ static void
 hfsc_change_fsc(struct hfsc_class *cl, struct tc_service_curve *fsc)
 {
        sc2isc(fsc, &cl->cl_fsc);
-       rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total);
+       rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vtoff + cl->cl_vt, cl->cl_total);
        cl->cl_flags |= HFSC_FSC;
 }
 
@@ -1015,11 +1008,10 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                cur_time = psched_get_time();
 
                if (tca[TCA_RATE]) {
-                       spinlock_t *lock = qdisc_root_sleeping_lock(sch);
-
                        err = gen_replace_estimator(&cl->bstats, NULL,
                                                    &cl->rate_est,
-                                                   lock,
+                                                   NULL,
+                                                   qdisc_root_sleeping_running(sch),
                                                    tca[TCA_RATE]);
                        if (err)
                                return err;
@@ -1068,7 +1060,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 
        if (tca[TCA_RATE]) {
                err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
-                                       qdisc_root_sleeping_lock(sch),
+                                       NULL,
+                                       qdisc_root_sleeping_running(sch),
                                        tca[TCA_RATE]);
                if (err) {
                        kfree(cl);
@@ -1373,7 +1366,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
        xstats.work    = cl->cl_total;
        xstats.rtwork  = cl->cl_cumul;
 
-       if (gnet_stats_copy_basic(d, NULL, &cl->bstats) < 0 ||
+       if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), d, NULL, &cl->bstats) < 0 ||
            gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
            gnet_stats_copy_queue(d, NULL, &cl->qstats, cl->qdisc->q.qlen) < 0)
                return -1;
@@ -1443,7 +1436,6 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
        if (err < 0)
                return err;
        q->eligible = RB_ROOT;
-       INIT_LIST_HEAD(&q->droplist);
 
        q->root.cl_common.classid = sch->handle;
        q->root.refcnt  = 1;
@@ -1527,7 +1519,6 @@ hfsc_reset_qdisc(struct Qdisc *sch)
                        hfsc_reset_class(cl);
        }
        q->eligible = RB_ROOT;
-       INIT_LIST_HEAD(&q->droplist);
        qdisc_watchdog_cancel(&q->watchdog);
        sch->qstats.backlog = 0;
        sch->q.qlen = 0;
@@ -1572,7 +1563,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
 }
 
 static int
-hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
 {
        struct hfsc_class *cl;
        int uninitialized_var(err);
@@ -1581,11 +1572,11 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (cl == NULL) {
                if (err & __NET_XMIT_BYPASS)
                        qdisc_qstats_drop(sch);
-               kfree_skb(skb);
+               __qdisc_drop(skb, to_free);
                return err;
        }
 
-       err = qdisc_enqueue(skb, cl->qdisc);
+       err = qdisc_enqueue(skb, cl->qdisc, to_free);
        if (unlikely(err != NET_XMIT_SUCCESS)) {
                if (net_xmit_drop_count(err)) {
                        cl->qstats.drops++;
@@ -1594,8 +1585,17 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
        }
 
-       if (cl->qdisc->q.qlen == 1)
+       if (cl->qdisc->q.qlen == 1) {
                set_active(cl, qdisc_pkt_len(skb));
+               /*
+                * If this is the first packet, isolate the head so an eventual
+                * head drop before the first dequeue operation has no chance
+                * to invalidate the deadline.
+                */
+               if (cl->cl_flags & HFSC_RSC)
+                       cl->qdisc->ops->peek(cl->qdisc);
+
+       }
 
        qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
@@ -1664,7 +1664,6 @@ hfsc_dequeue(struct Qdisc *sch)
                set_passive(cl);
        }
 
-       qdisc_unthrottled(sch);
        qdisc_bstats_update(sch, skb);
        qdisc_qstats_backlog_dec(sch, skb);
        sch->q.qlen--;
@@ -1672,32 +1671,6 @@ hfsc_dequeue(struct Qdisc *sch)
        return skb;
 }
 
-static unsigned int
-hfsc_drop(struct Qdisc *sch)
-{
-       struct hfsc_sched *q = qdisc_priv(sch);
-       struct hfsc_class *cl;
-       unsigned int len;
-
-       list_for_each_entry(cl, &q->droplist, dlist) {
-               if (cl->qdisc->ops->drop != NULL &&
-                   (len = cl->qdisc->ops->drop(cl->qdisc)) > 0) {
-                       if (cl->qdisc->q.qlen == 0) {
-                               update_vf(cl, 0, 0);
-                               set_passive(cl);
-                       } else {
-                               list_move_tail(&cl->dlist, &q->droplist);
-                       }
-                       cl->qstats.drops++;
-                       qdisc_qstats_drop(sch);
-                       sch->qstats.backlog -= len;
-                       sch->q.qlen--;
-                       return len;
-               }
-       }
-       return 0;
-}
-
 static const struct Qdisc_class_ops hfsc_class_ops = {
        .change         = hfsc_change_class,
        .delete         = hfsc_delete_class,
@@ -1724,7 +1697,6 @@ static struct Qdisc_ops hfsc_qdisc_ops __read_mostly = {
        .enqueue        = hfsc_enqueue,
        .dequeue        = hfsc_dequeue,
        .peek           = qdisc_peek_dequeued,
-       .drop           = hfsc_drop,
        .cl_ops         = &hfsc_class_ops,
        .priv_size      = sizeof(struct hfsc_sched),
        .owner          = THIS_MODULE
This page took 0.04488 seconds and 5 git commands to generate.