[MIPS] malta_int.c: make 4 variables static
[safe/jmp/linux-2.6] / net / sched / sch_htb.c
index 4d84200..66148cc 100644 (file)
  * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $
  */
 #include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
 #include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/route.h>
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/compiler.h>
-#include <net/sock.h>
-#include <net/pkt_sched.h>
 #include <linux/rbtree.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
 
 /* HTB algorithm.
     Author: devik@cdi.cz
@@ -68,8 +53,6 @@
 */
 
 #define HTB_HSIZE 16           /* classid hash size */
-#define HTB_EWMAC 2            /* rate average over HTB_EWMAC*HTB_HSIZE sec */
-#define HTB_RATECM 1           /* whether to use rate computer */
 #define HTB_HYSTERESIS 1       /* whether to use mode hysteresis for speedup */
 #define HTB_VER 0x30011                /* major must be matched with number suplied by TC as version */
 
@@ -94,12 +77,6 @@ struct htb_class {
        struct tc_htb_xstats xstats;    /* our special stats */
        int refcnt;             /* usage count of this class */
 
-#ifdef HTB_RATECM
-       /* rate measurement counters */
-       unsigned long rate_bytes, sum_bytes;
-       unsigned long rate_packets, sum_packets;
-#endif
-
        /* topology */
        int level;              /* our level (see above) */
        struct htb_class *parent;       /* parent class */
@@ -152,16 +129,11 @@ struct htb_class {
                                /* of un.leaf originals should be done. */
 };
 
-/* TODO: maybe compute rate when size is too large .. or drop ? */
 static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
                           int size)
 {
-       int slot = size >> rate->rate.cell_log;
-       if (slot > 255) {
-               cl->xstats.giants++;
-               slot = 255;
-       }
-       return rate->data[slot];
+       long result = qdisc_l2t(rate, size);
+       return result;
 }
 
 struct htb_sched {
@@ -193,10 +165,6 @@ struct htb_sched {
        int rate2quantum;       /* quant = rate / rate2quantum */
        psched_time_t now;      /* cached dequeue time */
        struct qdisc_watchdog watchdog;
-#ifdef HTB_RATECM
-       struct timer_list rttim;        /* rate computer timer */
-       int recmp_bucket;       /* which hash bucket to recompute next */
-#endif
 
        /* non shaped skbs; let them go directly thru */
        struct sk_buff_head direct_queue;
@@ -246,10 +214,6 @@ static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
  * then finish and return direct queue.
  */
 #define HTB_DIRECT (struct htb_class*)-1
-static inline u32 htb_classid(struct htb_class *cl)
-{
-       return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC;
-}
 
 static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
                                      int *qerr)
@@ -279,9 +243,6 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
                case TC_ACT_SHOT:
                        return NULL;
                }
-#elif defined(CONFIG_NET_CLS_POLICE)
-               if (result == TC_POLICE_SHOT)
-                       return HTB_DIRECT;
 #endif
                if ((cl = (void *)res.class) == NULL) {
                        if (res.classid == sch->handle)
@@ -633,13 +594,14 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                cl->qstats.drops++;
                return NET_XMIT_DROP;
        } else {
-               cl->bstats.packets++;
+               cl->bstats.packets +=
+                       skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
                cl->bstats.bytes += skb->len;
                htb_activate(q, cl);
        }
 
        sch->q.qlen++;
-       sch->bstats.packets++;
+       sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
        sch->bstats.bytes += skb->len;
        return NET_XMIT_SUCCESS;
 }
@@ -647,14 +609,14 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 /* TODO: requeuing packet charges it to policers again !! */
 static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
+       int ret;
        struct htb_sched *q = qdisc_priv(sch);
-       int ret = NET_XMIT_SUCCESS;
        struct htb_class *cl = htb_classify(skb, sch, &ret);
        struct sk_buff *tskb;
 
-       if (cl == HTB_DIRECT || !cl) {
+       if (cl == HTB_DIRECT) {
                /* enqueue to helper queue */
-               if (q->direct_queue.qlen < q->direct_qlen && cl) {
+               if (q->direct_queue.qlen < q->direct_qlen) {
                        __skb_queue_head(&q->direct_queue, skb);
                } else {
                        __skb_queue_head(&q->direct_queue, skb);
@@ -663,6 +625,13 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
                        sch->qstats.drops++;
                        return NET_XMIT_CN;
                }
+#ifdef CONFIG_NET_CLS_ACT
+       } else if (!cl) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+#endif
        } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) !=
                   NET_XMIT_SUCCESS) {
                sch->qstats.drops++;
@@ -676,34 +645,6 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
        return NET_XMIT_SUCCESS;
 }
 
-#ifdef HTB_RATECM
-#define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
-static void htb_rate_timer(unsigned long arg)
-{
-       struct Qdisc *sch = (struct Qdisc *)arg;
-       struct htb_sched *q = qdisc_priv(sch);
-       struct hlist_node *p;
-       struct htb_class *cl;
-
-
-       /* lock queue so that we can muck with it */
-       spin_lock_bh(&sch->dev->queue_lock);
-
-       q->rttim.expires = jiffies + HZ;
-       add_timer(&q->rttim);
-
-       /* scan and recompute one bucket at time */
-       if (++q->recmp_bucket >= HTB_HSIZE)
-               q->recmp_bucket = 0;
-
-       hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) {
-               RT_GEN(cl->sum_bytes, cl->rate_bytes);
-               RT_GEN(cl->sum_packets, cl->rate_packets);
-       }
-       spin_unlock_bh(&sch->dev->queue_lock);
-}
-#endif
-
 /**
  * htb_charge_class - charges amount "bytes" to leaf and ancestors
  *
@@ -716,8 +657,9 @@ static void htb_rate_timer(unsigned long arg)
  * In such case we remove class from event queue first.
  */
 static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
-                            int level, int bytes)
+                            int level, struct sk_buff *skb)
 {
+       int bytes = skb->len;
        long toks, diff;
        enum htb_cmode old_mode;
 
@@ -728,7 +670,7 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
        cl->T = toks
 
        while (cl) {
-               diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
+               diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer);
                if (cl->level >= level) {
                        if (cl->level == level)
                                cl->xstats.lends++;
@@ -749,16 +691,12 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
                        if (cl->cmode != HTB_CAN_SEND)
                                htb_add_to_wait_tree(q, cl, diff);
                }
-#ifdef HTB_RATECM
-               /* update rate counters */
-               cl->sum_bytes += bytes;
-               cl->sum_packets++;
-#endif
 
                /* update byte stats except for leaves which are already updated */
                if (cl->level) {
                        cl->bstats.bytes += bytes;
-                       cl->bstats.packets++;
+                       cl->bstats.packets += skb_is_gso(skb)?
+                                       skb_shinfo(skb)->gso_segs:1;
                }
                cl = cl->parent;
        }
@@ -773,9 +711,11 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
  */
 static psched_time_t htb_do_events(struct htb_sched *q, int level)
 {
-       int i;
-
-       for (i = 0; i < 500; i++) {
+       /* don't run for longer than 2 jiffies; 2 is used instead of
+          1 to simplify things when jiffy is going to be incremented
+          too soon */
+       unsigned long stop_at = jiffies + 2;
+       while (time_before(jiffies, stop_at)) {
                struct htb_class *cl;
                long diff;
                struct rb_node *p = rb_first(&q->wait_pq[level]);
@@ -788,14 +728,13 @@ static psched_time_t htb_do_events(struct htb_sched *q, int level)
                        return cl->pq_key;
 
                htb_safe_rb_erase(p, q->wait_pq + level);
-               diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
+               diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer);
                htb_change_class_mode(q, cl, &diff);
                if (cl->cmode != HTB_CAN_SEND)
                        htb_add_to_wait_tree(q, cl, diff);
        }
-       if (net_ratelimit())
-               printk(KERN_WARNING "htb: too many events !\n");
-       return q->now + PSCHED_TICKS_PER_SEC / 10;
+       /* too much load - let's continue on next jiffie */
+       return q->now + PSCHED_TICKS_PER_SEC / HZ;
 }
 
 /* Returns class->node+prio from id-tree where classe's id is >= id. NULL
@@ -942,7 +881,7 @@ next:
                   gives us slightly better performance */
                if (!cl->un.leaf.q->q.qlen)
                        htb_deactivate(q, cl);
-               htb_charge_class(q, cl, level, skb->len);
+               htb_charge_class(q, cl, level, skb);
        }
        return skb;
 }
@@ -964,7 +903,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 
        if (!sch->q.qlen)
                goto fin;
-       PSCHED_GET_TIME(q->now);
+       q->now = psched_get_time();
 
        next_event = q->now + 5 * PSCHED_TICKS_PER_SEC;
        q->nwc_hit = 0;
@@ -975,8 +914,9 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 
                if (q->now >= q->near_ev_cache[level]) {
                        event = htb_do_events(q, level);
-                       q->near_ev_cache[level] = event ? event :
-                                                         PSCHED_TICKS_PER_SEC;
+                       if (!event)
+                               event = q->now + PSCHED_TICKS_PER_SEC;
+                       q->near_ev_cache[level] = event;
                } else
                        event = q->near_ev_cache[level];
 
@@ -1060,19 +1000,33 @@ static void htb_reset(struct Qdisc *sch)
                INIT_LIST_HEAD(q->drops + i);
 }
 
-static int htb_init(struct Qdisc *sch, struct rtattr *opt)
+static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = {
+       [TCA_HTB_PARMS] = { .len = sizeof(struct tc_htb_opt) },
+       [TCA_HTB_INIT]  = { .len = sizeof(struct tc_htb_glob) },
+       [TCA_HTB_CTAB]  = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+       [TCA_HTB_RTAB]  = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+};
+
+static int htb_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct htb_sched *q = qdisc_priv(sch);
-       struct rtattr *tb[TCA_HTB_INIT];
+       struct nlattr *tb[TCA_HTB_INIT + 1];
        struct tc_htb_glob *gopt;
+       int err;
        int i;
-       if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) ||
-           tb[TCA_HTB_INIT - 1] == NULL ||
-           RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) {
+
+       if (!opt)
+               return -EINVAL;
+
+       err = nla_parse_nested(tb, TCA_HTB_INIT, opt, htb_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_HTB_INIT] == NULL) {
                printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n");
                return -EINVAL;
        }
-       gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]);
+       gopt = nla_data(tb[TCA_HTB_INIT]);
        if (gopt->version != HTB_VER >> 16) {
                printk(KERN_ERR
                       "HTB: need tc/htb version %d (minor is %d), you have %d\n",
@@ -1093,13 +1047,6 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
        if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
                q->direct_qlen = 2;
 
-#ifdef HTB_RATECM
-       init_timer(&q->rttim);
-       q->rttim.function = htb_rate_timer;
-       q->rttim.data = (unsigned long)sch;
-       q->rttim.expires = jiffies + HZ;
-       add_timer(&q->rttim);
-#endif
        if ((q->rate2quantum = gopt->rate2quantum) < 1)
                q->rate2quantum = 1;
        q->defcls = gopt->defcls;
@@ -1110,25 +1057,29 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
 static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
        struct htb_sched *q = qdisc_priv(sch);
-       unsigned char *b = skb->tail;
-       struct rtattr *rta;
+       struct nlattr *nest;
        struct tc_htb_glob gopt;
+
        spin_lock_bh(&sch->dev->queue_lock);
-       gopt.direct_pkts = q->direct_pkts;
 
+       gopt.direct_pkts = q->direct_pkts;
        gopt.version = HTB_VER;
        gopt.rate2quantum = q->rate2quantum;
        gopt.defcls = q->defcls;
        gopt.debug = 0;
-       rta = (struct rtattr *)b;
-       RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
-       RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
-       rta->rta_len = skb->tail - b;
+
+       nest = nla_nest_start(skb, TCA_OPTIONS);
+       if (nest == NULL)
+               goto nla_put_failure;
+       NLA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
+       nla_nest_end(skb, nest);
+
        spin_unlock_bh(&sch->dev->queue_lock);
        return skb->len;
-rtattr_failure:
+
+nla_put_failure:
        spin_unlock_bh(&sch->dev->queue_lock);
-       skb_trim(skb, skb->tail - skb->data);
+       nla_nest_cancel(skb, nest);
        return -1;
 }
 
@@ -1136,8 +1087,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
                          struct sk_buff *skb, struct tcmsg *tcm)
 {
        struct htb_class *cl = (struct htb_class *)arg;
-       unsigned char *b = skb->tail;
-       struct rtattr *rta;
+       struct nlattr *nest;
        struct tc_htb_opt opt;
 
        spin_lock_bh(&sch->dev->queue_lock);
@@ -1146,8 +1096,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
        if (!cl->level && cl->un.leaf.q)
                tcm->tcm_info = cl->un.leaf.q->handle;
 
-       rta = (struct rtattr *)b;
-       RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+       nest = nla_nest_start(skb, TCA_OPTIONS);
+       if (nest == NULL)
+               goto nla_put_failure;
 
        memset(&opt, 0, sizeof(opt));
 
@@ -1158,13 +1109,15 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
        opt.quantum = cl->un.leaf.quantum;
        opt.prio = cl->un.leaf.prio;
        opt.level = cl->level;
-       RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
-       rta->rta_len = skb->tail - b;
+       NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt);
+
+       nla_nest_end(skb, nest);
        spin_unlock_bh(&sch->dev->queue_lock);
        return skb->len;
-rtattr_failure:
+
+nla_put_failure:
        spin_unlock_bh(&sch->dev->queue_lock);
-       skb_trim(skb, b - skb->data);
+       nla_nest_cancel(skb, nest);
        return -1;
 }
 
@@ -1173,11 +1126,6 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
 {
        struct htb_class *cl = (struct htb_class *)arg;
 
-#ifdef HTB_RATECM
-       cl->rate_est.bps = cl->rate_bytes / (HTB_EWMAC * HTB_HSIZE);
-       cl->rate_est.pps = cl->rate_packets / (HTB_EWMAC * HTB_HSIZE);
-#endif
-
        if (!cl->level && cl->un.leaf.q)
                cl->qstats.qlen = cl->un.leaf.q->q.qlen;
        cl->xstats.tokens = cl->tokens;
@@ -1235,16 +1183,6 @@ static unsigned long htb_get(struct Qdisc *sch, u32 classid)
        return (unsigned long)cl;
 }
 
-static void htb_destroy_filters(struct tcf_proto **fl)
-{
-       struct tcf_proto *tp;
-
-       while ((tp = *fl) != NULL) {
-               *fl = tp->next;
-               tcf_destroy(tp);
-       }
-}
-
 static inline int htb_parent_last_child(struct htb_class *cl)
 {
        if (!cl->parent)
@@ -1273,7 +1211,7 @@ static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q)
        parent->un.leaf.prio = parent->prio;
        parent->tokens = parent->buffer;
        parent->ctokens = parent->cbuffer;
-       PSCHED_GET_TIME(parent->t_c);
+       parent->t_c = psched_get_time();
        parent->cmode = HTB_CAN_SEND;
 }
 
@@ -1285,10 +1223,11 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
                BUG_TRAP(cl->un.leaf.q);
                qdisc_destroy(cl->un.leaf.q);
        }
+       gen_kill_estimator(&cl->bstats, &cl->rate_est);
        qdisc_put_rtab(cl->rate);
        qdisc_put_rtab(cl->ceil);
 
-       htb_destroy_filters(&cl->filter_list);
+       tcf_destroy_chain(cl->filter_list);
 
        while (!list_empty(&cl->children))
                htb_destroy_class(sch, list_entry(cl->children.next,
@@ -1313,14 +1252,11 @@ static void htb_destroy(struct Qdisc *sch)
        struct htb_sched *q = qdisc_priv(sch);
 
        qdisc_watchdog_cancel(&q->watchdog);
-#ifdef HTB_RATECM
-       del_timer_sync(&q->rttim);
-#endif
        /* This line used to be after htb_destroy_class call below
           and surprisingly it worked in 2.4. But it must precede it
           because filter need its target class alive to be able to call
           unbind_filter on it (without Oops). */
-       htb_destroy_filters(&q->filter_list);
+       tcf_destroy_chain(q->filter_list);
 
        while (!list_empty(&q->root))
                htb_destroy_class(sch, list_entry(q->root.next,
@@ -1382,35 +1318,55 @@ static void htb_put(struct Qdisc *sch, unsigned long arg)
 }
 
 static int htb_change_class(struct Qdisc *sch, u32 classid,
-                           u32 parentid, struct rtattr **tca,
+                           u32 parentid, struct nlattr **tca,
                            unsigned long *arg)
 {
        int err = -EINVAL;
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)*arg, *parent;
-       struct rtattr *opt = tca[TCA_OPTIONS - 1];
+       struct nlattr *opt = tca[TCA_OPTIONS];
        struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
-       struct rtattr *tb[TCA_HTB_RTAB];
+       struct nlattr *tb[TCA_HTB_RTAB + 1];
        struct tc_htb_opt *hopt;
 
        /* extract all subattrs from opt attr */
-       if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) ||
-           tb[TCA_HTB_PARMS - 1] == NULL ||
-           RTA_PAYLOAD(tb[TCA_HTB_PARMS - 1]) < sizeof(*hopt))
+       if (!opt)
+               goto failure;
+
+       err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, htb_policy);
+       if (err < 0)
+               goto failure;
+
+       err = -EINVAL;
+       if (tb[TCA_HTB_PARMS] == NULL)
                goto failure;
 
        parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch);
 
-       hopt = RTA_DATA(tb[TCA_HTB_PARMS - 1]);
+       hopt = nla_data(tb[TCA_HTB_PARMS]);
 
-       rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB - 1]);
-       ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB - 1]);
+       rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]);
+       ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]);
        if (!rtab || !ctab)
                goto failure;
 
        if (!cl) {              /* new class */
                struct Qdisc *new_q;
                int prio;
+               struct {
+                       struct nlattr           nla;
+                       struct gnet_estimator   opt;
+               } est = {
+                       .nla = {
+                               .nla_len        = nla_attr_size(sizeof(est.opt)),
+                               .nla_type       = TCA_RATE,
+                       },
+                       .opt = {
+                               /* 4s interval, 16s averaging constant */
+                               .interval       = 2,
+                               .ewma_log       = 2,
+                       },
+               };
 
                /* check for valid classid */
                if (!classid || TC_H_MAJ(classid ^ sch->handle)
@@ -1426,6 +1382,9 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
                        goto failure;
 
+               gen_new_estimator(&cl->bstats, &cl->rate_est,
+                                 &sch->dev->queue_lock,
+                                 tca[TCA_RATE] ? : &est.nla);
                cl->refcnt = 1;
                INIT_LIST_HEAD(&cl->sibling);
                INIT_HLIST_NODE(&cl->hlist);
@@ -1469,16 +1428,21 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                /* set class to be in HTB_CAN_SEND state */
                cl->tokens = hopt->buffer;
                cl->ctokens = hopt->cbuffer;
-               cl->mbuffer = PSCHED_JIFFIE2US(HZ * 60);        /* 1min */
-               PSCHED_GET_TIME(cl->t_c);
+               cl->mbuffer = 60 * PSCHED_TICKS_PER_SEC;        /* 1min */
+               cl->t_c = psched_get_time();
                cl->cmode = HTB_CAN_SEND;
 
                /* attach to the hash list and parent's family */
                hlist_add_head(&cl->hlist, q->hash + htb_hash(classid));
                list_add_tail(&cl->sibling,
                              parent ? &parent->children : &q->root);
-       } else
+       } else {
+               if (tca[TCA_RATE])
+                       gen_replace_estimator(&cl->bstats, &cl->rate_est,
+                                             &sch->dev->queue_lock,
+                                             tca[TCA_RATE]);
                sch_tree_lock(sch);
+       }
 
        /* it used to be a nasty bug here, we have to check that node
           is really leaf before changing cl->un.leaf ! */
@@ -1595,7 +1559,7 @@ static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg)
        }
 }
 
-static struct Qdisc_class_ops htb_class_ops = {
+static const struct Qdisc_class_ops htb_class_ops = {
        .graft          =       htb_graft,
        .leaf           =       htb_leaf,
        .qlen_notify    =       htb_qlen_notify,
@@ -1611,7 +1575,7 @@ static struct Qdisc_class_ops htb_class_ops = {
        .dump_stats     =       htb_dump_class_stats,
 };
 
-static struct Qdisc_ops htb_qdisc_ops = {
+static struct Qdisc_ops htb_qdisc_ops __read_mostly = {
        .next           =       NULL,
        .cl_ops         =       &htb_class_ops,
        .id             =       "htb",