string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / net / sched / sch_drr.c
index 37e6ab9..a65604f 100644 (file)
@@ -22,7 +22,7 @@ struct drr_class {
        unsigned int                    refcnt;
        unsigned int                    filter_cnt;
 
-       struct gnet_stats_basic         bstats;
+       struct gnet_stats_basic_packed          bstats;
        struct gnet_stats_queue         qstats;
        struct gnet_stats_rate_est      rate_est;
        struct list_head                alist;
@@ -66,11 +66,15 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 {
        struct drr_sched *q = qdisc_priv(sch);
        struct drr_class *cl = (struct drr_class *)*arg;
+       struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_DRR_MAX + 1];
        u32 quantum;
        int err;
 
-       err = nla_parse_nested(tb, TCA_DRR_MAX, tca[TCA_OPTIONS], drr_policy);
+       if (!opt)
+               return -EINVAL;
+
+       err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy);
        if (err < 0)
                return err;
 
@@ -82,15 +86,19 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                quantum = psched_mtu(qdisc_dev(sch));
 
        if (cl != NULL) {
+               if (tca[TCA_RATE]) {
+                       err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+                                                   qdisc_root_sleeping_lock(sch),
+                                                   tca[TCA_RATE]);
+                       if (err)
+                               return err;
+               }
+
                sch_tree_lock(sch);
                if (tb[TCA_DRR_QUANTUM])
                        cl->quantum = quantum;
                sch_tree_unlock(sch);
 
-               if (tca[TCA_RATE])
-                       gen_replace_estimator(&cl->bstats, &cl->rate_est,
-                                             qdisc_root_sleeping_lock(sch),
-                                             tca[TCA_RATE]);
                return 0;
        }
 
@@ -106,10 +114,16 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
        if (cl->qdisc == NULL)
                cl->qdisc = &noop_qdisc;
 
-       if (tca[TCA_RATE])
-               gen_replace_estimator(&cl->bstats, &cl->rate_est,
-                                     qdisc_root_sleeping_lock(sch),
-                                     tca[TCA_RATE]);
+       if (tca[TCA_RATE]) {
+               err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+                                           qdisc_root_sleeping_lock(sch),
+                                           tca[TCA_RATE]);
+               if (err) {
+                       qdisc_destroy(cl->qdisc);
+                       kfree(cl);
+                       return err;
+               }
+       }
 
        sch_tree_lock(sch);
        qdisc_class_hash_insert(&q->clhash, &cl->common);
@@ -141,8 +155,11 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)
        drr_purge_queue(cl);
        qdisc_class_hash_remove(&q->clhash, &cl->common);
 
-       if (--cl->refcnt == 0)
-               drr_destroy_class(sch, cl);
+       BUG_ON(--cl->refcnt == 0);
+       /*
+        * This shouldn't happen: we "hold" one cops->get() when called
+        * from tc_ctl_tclass; the destroy method is done from cops->put().
+        */
 
        sch_tree_unlock(sch);
        return 0;
@@ -257,11 +274,13 @@ static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg,
        struct tc_drr_stats xstats;
 
        memset(&xstats, 0, sizeof(xstats));
-       if (cl->qdisc->q.qlen)
+       if (cl->qdisc->q.qlen) {
                xstats.deficit = cl->deficit;
+               cl->qdisc->qstats.qlen = cl->qdisc->q.qlen;
+       }
 
        if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-           gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+           gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
            gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
                return -1;
 
@@ -373,11 +392,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 +411,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;
 }