aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
commit1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch)
treef5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /net/sched
parentac58c9059da8886b5e8cde012a80266b18ca146e (diff)
parent674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff)
Merge branch 'linus'
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/Kconfig1
-rw-r--r--net/sched/act_ipt.c10
-rw-r--r--net/sched/cls_u32.c6
-rw-r--r--net/sched/sch_atm.c1
-rw-r--r--net/sched/sch_dsmark.c1
-rw-r--r--net/sched/sch_generic.c2
-rw-r--r--net/sched/sch_netem.c4
-rw-r--r--net/sched/sch_prio.c2
-rw-r--r--net/sched/sch_red.c179
-rw-r--r--net/sched/sch_sfq.c5
-rw-r--r--net/sched/sch_tbf.c9
11 files changed, 187 insertions, 33 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 778b1e5a4b50..13eeee582886 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -434,7 +434,6 @@ config NET_EMATCH_TEXT
434 434
435config NET_CLS_ACT 435config NET_CLS_ACT
436 bool "Actions" 436 bool "Actions"
437 depends on EXPERIMENTAL
438 select NET_ESTIMATOR 437 select NET_ESTIMATOR
439 ---help--- 438 ---help---
440 Say Y here if you want to use traffic control actions. Actions 439 Say Y here if you want to use traffic control actions. Actions
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 39a22a3ffe78..6056d20ef429 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -70,7 +70,8 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
70 t->u.kernel.target = target; 70 t->u.kernel.target = target;
71 71
72 if (t->u.kernel.target->checkentry 72 if (t->u.kernel.target->checkentry
73 && !t->u.kernel.target->checkentry(table, NULL, t->data, 73 && !t->u.kernel.target->checkentry(table, NULL,
74 t->u.kernel.target, t->data,
74 t->u.target_size - sizeof(*t), 75 t->u.target_size - sizeof(*t),
75 hook)) { 76 hook)) {
76 DPRINTK("ipt_init_target: check failed for `%s'.\n", 77 DPRINTK("ipt_init_target: check failed for `%s'.\n",
@@ -86,7 +87,7 @@ static void
86ipt_destroy_target(struct ipt_entry_target *t) 87ipt_destroy_target(struct ipt_entry_target *t)
87{ 88{
88 if (t->u.kernel.target->destroy) 89 if (t->u.kernel.target->destroy)
89 t->u.kernel.target->destroy(t->data, 90 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
90 t->u.target_size - sizeof(*t)); 91 t->u.target_size - sizeof(*t));
91 module_put(t->u.kernel.target->me); 92 module_put(t->u.kernel.target->me);
92} 93}
@@ -224,8 +225,9 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
224 /* iptables targets take a double skb pointer in case the skb 225 /* iptables targets take a double skb pointer in case the skb
225 * needs to be replaced. We don't own the skb, so this must not 226 * needs to be replaced. We don't own the skb, so this must not
226 * happen. The pskb_expand_head above should make sure of this */ 227 * happen. The pskb_expand_head above should make sure of this */
227 ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, 228 ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook,
228 p->hook, p->t->data, NULL); 229 p->t->u.kernel.target, p->t->data,
230 NULL);
229 switch (ret) { 231 switch (ret) {
230 case NF_ACCEPT: 232 case NF_ACCEPT:
231 result = TC_ACT_OK; 233 result = TC_ACT_OK;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 2b670479dde1..78e052591fa9 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -347,8 +347,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n)
347 if (n->ht_down) 347 if (n->ht_down)
348 n->ht_down->refcnt--; 348 n->ht_down->refcnt--;
349#ifdef CONFIG_CLS_U32_PERF 349#ifdef CONFIG_CLS_U32_PERF
350 if (n) 350 kfree(n->pf);
351 kfree(n->pf);
352#endif 351#endif
353 kfree(n); 352 kfree(n);
354 return 0; 353 return 0;
@@ -680,8 +679,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle,
680 return 0; 679 return 0;
681 } 680 }
682#ifdef CONFIG_CLS_U32_PERF 681#ifdef CONFIG_CLS_U32_PERF
683 if (n) 682 kfree(n->pf);
684 kfree(n->pf);
685#endif 683#endif
686 kfree(n); 684 kfree(n);
687 return err; 685 return err;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 93ebce40acac..ac7cb60d1e25 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -638,6 +638,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
638 sch,p,flow,skb,tcm); 638 sch,p,flow,skb,tcm);
639 if (!find_flow(p,flow)) return -EINVAL; 639 if (!find_flow(p,flow)) return -EINVAL;
640 tcm->tcm_handle = flow->classid; 640 tcm->tcm_handle = flow->classid;
641 tcm->tcm_info = flow->q->handle;
641 rta = (struct rtattr *) b; 642 rta = (struct rtattr *) b;
642 RTA_PUT(skb,TCA_OPTIONS,0,NULL); 643 RTA_PUT(skb,TCA_OPTIONS,0,NULL);
643 RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr); 644 RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 13e0e7b3856b..f6320ca70493 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -438,6 +438,7 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
438 return -EINVAL; 438 return -EINVAL;
439 439
440 tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1); 440 tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1);
441 tcm->tcm_info = p->q->handle;
441 442
442 opts = RTA_NEST(skb, TCA_OPTIONS); 443 opts = RTA_NEST(skb, TCA_OPTIONS);
443 RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]); 444 RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 99ceb91f0150..31eb83717c26 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -234,7 +234,7 @@ static void dev_watchdog_down(struct net_device *dev)
234{ 234{
235 spin_lock_bh(&dev->xmit_lock); 235 spin_lock_bh(&dev->xmit_lock);
236 if (del_timer(&dev->watchdog_timer)) 236 if (del_timer(&dev->watchdog_timer))
237 __dev_put(dev); 237 dev_put(dev);
238 spin_unlock_bh(&dev->xmit_lock); 238 spin_unlock_bh(&dev->xmit_lock);
239} 239}
240 240
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index ba5283204837..7228d30512c7 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -252,9 +252,9 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
252static unsigned int netem_drop(struct Qdisc* sch) 252static unsigned int netem_drop(struct Qdisc* sch)
253{ 253{
254 struct netem_sched_data *q = qdisc_priv(sch); 254 struct netem_sched_data *q = qdisc_priv(sch);
255 unsigned int len; 255 unsigned int len = 0;
256 256
257 if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { 257 if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
258 sch->q.qlen--; 258 sch->q.qlen--;
259 sch->qstats.drops++; 259 sch->qstats.drops++;
260 } 260 }
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 1641db33a994..3395ca7bcadf 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -165,7 +165,7 @@ static unsigned int prio_drop(struct Qdisc* sch)
165 165
166 for (prio = q->bands-1; prio >= 0; prio--) { 166 for (prio = q->bands-1; prio >= 0; prio--) {
167 qdisc = q->queues[prio]; 167 qdisc = q->queues[prio];
168 if ((len = qdisc->ops->drop(qdisc)) != 0) { 168 if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) {
169 sch->q.qlen--; 169 sch->q.qlen--;
170 return len; 170 return len;
171 } 171 }
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index dccfa44c2d71..2be563cba72b 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -44,6 +44,7 @@ struct red_sched_data
44 unsigned char flags; 44 unsigned char flags;
45 struct red_parms parms; 45 struct red_parms parms;
46 struct red_stats stats; 46 struct red_stats stats;
47 struct Qdisc *qdisc;
47}; 48};
48 49
49static inline int red_use_ecn(struct red_sched_data *q) 50static inline int red_use_ecn(struct red_sched_data *q)
@@ -59,8 +60,10 @@ static inline int red_use_harddrop(struct red_sched_data *q)
59static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) 60static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
60{ 61{
61 struct red_sched_data *q = qdisc_priv(sch); 62 struct red_sched_data *q = qdisc_priv(sch);
63 struct Qdisc *child = q->qdisc;
64 int ret;
62 65
63 q->parms.qavg = red_calc_qavg(&q->parms, sch->qstats.backlog); 66 q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog);
64 67
65 if (red_is_idling(&q->parms)) 68 if (red_is_idling(&q->parms))
66 red_end_of_idle_period(&q->parms); 69 red_end_of_idle_period(&q->parms);
@@ -91,11 +94,16 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
91 break; 94 break;
92 } 95 }
93 96
94 if (sch->qstats.backlog + skb->len <= q->limit) 97 ret = child->enqueue(skb, child);
95 return qdisc_enqueue_tail(skb, sch); 98 if (likely(ret == NET_XMIT_SUCCESS)) {
96 99 sch->bstats.bytes += skb->len;
97 q->stats.pdrop++; 100 sch->bstats.packets++;
98 return qdisc_drop(skb, sch); 101 sch->q.qlen++;
102 } else {
103 q->stats.pdrop++;
104 sch->qstats.drops++;
105 }
106 return ret;
99 107
100congestion_drop: 108congestion_drop:
101 qdisc_drop(skb, sch); 109 qdisc_drop(skb, sch);
@@ -105,21 +113,30 @@ congestion_drop:
105static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) 113static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
106{ 114{
107 struct red_sched_data *q = qdisc_priv(sch); 115 struct red_sched_data *q = qdisc_priv(sch);
116 struct Qdisc *child = q->qdisc;
117 int ret;
108 118
109 if (red_is_idling(&q->parms)) 119 if (red_is_idling(&q->parms))
110 red_end_of_idle_period(&q->parms); 120 red_end_of_idle_period(&q->parms);
111 121
112 return qdisc_requeue(skb, sch); 122 ret = child->ops->requeue(skb, child);
123 if (likely(ret == NET_XMIT_SUCCESS)) {
124 sch->qstats.requeues++;
125 sch->q.qlen++;
126 }
127 return ret;
113} 128}
114 129
115static struct sk_buff * red_dequeue(struct Qdisc* sch) 130static struct sk_buff * red_dequeue(struct Qdisc* sch)
116{ 131{
117 struct sk_buff *skb; 132 struct sk_buff *skb;
118 struct red_sched_data *q = qdisc_priv(sch); 133 struct red_sched_data *q = qdisc_priv(sch);
134 struct Qdisc *child = q->qdisc;
119 135
120 skb = qdisc_dequeue_head(sch); 136 skb = child->dequeue(child);
121 137 if (skb)
122 if (skb == NULL && !red_is_idling(&q->parms)) 138 sch->q.qlen--;
139 else if (!red_is_idling(&q->parms))
123 red_start_of_idle_period(&q->parms); 140 red_start_of_idle_period(&q->parms);
124 141
125 return skb; 142 return skb;
@@ -127,14 +144,14 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
127 144
128static unsigned int red_drop(struct Qdisc* sch) 145static unsigned int red_drop(struct Qdisc* sch)
129{ 146{
130 struct sk_buff *skb;
131 struct red_sched_data *q = qdisc_priv(sch); 147 struct red_sched_data *q = qdisc_priv(sch);
148 struct Qdisc *child = q->qdisc;
149 unsigned int len;
132 150
133 skb = qdisc_dequeue_tail(sch); 151 if (child->ops->drop && (len = child->ops->drop(child)) > 0) {
134 if (skb) {
135 unsigned int len = skb->len;
136 q->stats.other++; 152 q->stats.other++;
137 qdisc_drop(skb, sch); 153 sch->qstats.drops++;
154 sch->q.qlen--;
138 return len; 155 return len;
139 } 156 }
140 157
@@ -148,15 +165,48 @@ static void red_reset(struct Qdisc* sch)
148{ 165{
149 struct red_sched_data *q = qdisc_priv(sch); 166 struct red_sched_data *q = qdisc_priv(sch);
150 167
151 qdisc_reset_queue(sch); 168 qdisc_reset(q->qdisc);
169 sch->q.qlen = 0;
152 red_restart(&q->parms); 170 red_restart(&q->parms);
153} 171}
154 172
173static void red_destroy(struct Qdisc *sch)
174{
175 struct red_sched_data *q = qdisc_priv(sch);
176 qdisc_destroy(q->qdisc);
177}
178
179static struct Qdisc *red_create_dflt(struct net_device *dev, u32 limit)
180{
181 struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops);
182 struct rtattr *rta;
183 int ret;
184
185 if (q) {
186 rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)),
187 GFP_KERNEL);
188 if (rta) {
189 rta->rta_type = RTM_NEWQDISC;
190 rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
191 ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
192
193 ret = q->ops->change(q, rta);
194 kfree(rta);
195
196 if (ret == 0)
197 return q;
198 }
199 qdisc_destroy(q);
200 }
201 return NULL;
202}
203
155static int red_change(struct Qdisc *sch, struct rtattr *opt) 204static int red_change(struct Qdisc *sch, struct rtattr *opt)
156{ 205{
157 struct red_sched_data *q = qdisc_priv(sch); 206 struct red_sched_data *q = qdisc_priv(sch);
158 struct rtattr *tb[TCA_RED_MAX]; 207 struct rtattr *tb[TCA_RED_MAX];
159 struct tc_red_qopt *ctl; 208 struct tc_red_qopt *ctl;
209 struct Qdisc *child = NULL;
160 210
161 if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt)) 211 if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt))
162 return -EINVAL; 212 return -EINVAL;
@@ -169,9 +219,17 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
169 219
170 ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); 220 ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
171 221
222 if (ctl->limit > 0) {
223 child = red_create_dflt(sch->dev, ctl->limit);
224 if (child == NULL)
225 return -ENOMEM;
226 }
227
172 sch_tree_lock(sch); 228 sch_tree_lock(sch);
173 q->flags = ctl->flags; 229 q->flags = ctl->flags;
174 q->limit = ctl->limit; 230 q->limit = ctl->limit;
231 if (child)
232 qdisc_destroy(xchg(&q->qdisc, child));
175 233
176 red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, 234 red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
177 ctl->Plog, ctl->Scell_log, 235 ctl->Plog, ctl->Scell_log,
@@ -186,6 +244,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
186 244
187static int red_init(struct Qdisc* sch, struct rtattr *opt) 245static int red_init(struct Qdisc* sch, struct rtattr *opt)
188{ 246{
247 struct red_sched_data *q = qdisc_priv(sch);
248
249 q->qdisc = &noop_qdisc;
189 return red_change(sch, opt); 250 return red_change(sch, opt);
190} 251}
191 252
@@ -224,15 +285,101 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
224 return gnet_stats_copy_app(d, &st, sizeof(st)); 285 return gnet_stats_copy_app(d, &st, sizeof(st));
225} 286}
226 287
288static int red_dump_class(struct Qdisc *sch, unsigned long cl,
289 struct sk_buff *skb, struct tcmsg *tcm)
290{
291 struct red_sched_data *q = qdisc_priv(sch);
292
293 if (cl != 1)
294 return -ENOENT;
295 tcm->tcm_handle |= TC_H_MIN(1);
296 tcm->tcm_info = q->qdisc->handle;
297 return 0;
298}
299
300static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
301 struct Qdisc **old)
302{
303 struct red_sched_data *q = qdisc_priv(sch);
304
305 if (new == NULL)
306 new = &noop_qdisc;
307
308 sch_tree_lock(sch);
309 *old = xchg(&q->qdisc, new);
310 qdisc_reset(*old);
311 sch->q.qlen = 0;
312 sch_tree_unlock(sch);
313 return 0;
314}
315
316static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
317{
318 struct red_sched_data *q = qdisc_priv(sch);
319 return q->qdisc;
320}
321
322static unsigned long red_get(struct Qdisc *sch, u32 classid)
323{
324 return 1;
325}
326
327static void red_put(struct Qdisc *sch, unsigned long arg)
328{
329 return;
330}
331
332static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
333 struct rtattr **tca, unsigned long *arg)
334{
335 return -ENOSYS;
336}
337
338static int red_delete(struct Qdisc *sch, unsigned long cl)
339{
340 return -ENOSYS;
341}
342
343static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
344{
345 if (!walker->stop) {
346 if (walker->count >= walker->skip)
347 if (walker->fn(sch, 1, walker) < 0) {
348 walker->stop = 1;
349 return;
350 }
351 walker->count++;
352 }
353}
354
355static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
356{
357 return NULL;
358}
359
360static struct Qdisc_class_ops red_class_ops = {
361 .graft = red_graft,
362 .leaf = red_leaf,
363 .get = red_get,
364 .put = red_put,
365 .change = red_change_class,
366 .delete = red_delete,
367 .walk = red_walk,
368 .tcf_chain = red_find_tcf,
369 .dump = red_dump_class,
370};
371
227static struct Qdisc_ops red_qdisc_ops = { 372static struct Qdisc_ops red_qdisc_ops = {
228 .id = "red", 373 .id = "red",
229 .priv_size = sizeof(struct red_sched_data), 374 .priv_size = sizeof(struct red_sched_data),
375 .cl_ops = &red_class_ops,
230 .enqueue = red_enqueue, 376 .enqueue = red_enqueue,
231 .dequeue = red_dequeue, 377 .dequeue = red_dequeue,
232 .requeue = red_requeue, 378 .requeue = red_requeue,
233 .drop = red_drop, 379 .drop = red_drop,
234 .init = red_init, 380 .init = red_init,
235 .reset = red_reset, 381 .reset = red_reset,
382 .destroy = red_destroy,
236 .change = red_change, 383 .change = red_change,
237 .dump = red_dump, 384 .dump = red_dump,
238 .dump_stats = red_dump_stats, 385 .dump_stats = red_dump_stats,
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 86d8da0cbd02..e057768f68b4 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -232,6 +232,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
232 sfq_dec(q, x); 232 sfq_dec(q, x);
233 sch->q.qlen--; 233 sch->q.qlen--;
234 sch->qstats.drops++; 234 sch->qstats.drops++;
235 sch->qstats.backlog -= len;
235 return len; 236 return len;
236 } 237 }
237 238
@@ -248,6 +249,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
248 sch->q.qlen--; 249 sch->q.qlen--;
249 q->ht[q->hash[d]] = SFQ_DEPTH; 250 q->ht[q->hash[d]] = SFQ_DEPTH;
250 sch->qstats.drops++; 251 sch->qstats.drops++;
252 sch->qstats.backlog -= len;
251 return len; 253 return len;
252 } 254 }
253 255
@@ -266,6 +268,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
266 q->ht[hash] = x = q->dep[SFQ_DEPTH].next; 268 q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
267 q->hash[x] = hash; 269 q->hash[x] = hash;
268 } 270 }
271 sch->qstats.backlog += skb->len;
269 __skb_queue_tail(&q->qs[x], skb); 272 __skb_queue_tail(&q->qs[x], skb);
270 sfq_inc(q, x); 273 sfq_inc(q, x);
271 if (q->qs[x].qlen == 1) { /* The flow is new */ 274 if (q->qs[x].qlen == 1) { /* The flow is new */
@@ -301,6 +304,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
301 q->ht[hash] = x = q->dep[SFQ_DEPTH].next; 304 q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
302 q->hash[x] = hash; 305 q->hash[x] = hash;
303 } 306 }
307 sch->qstats.backlog += skb->len;
304 __skb_queue_head(&q->qs[x], skb); 308 __skb_queue_head(&q->qs[x], skb);
305 sfq_inc(q, x); 309 sfq_inc(q, x);
306 if (q->qs[x].qlen == 1) { /* The flow is new */ 310 if (q->qs[x].qlen == 1) { /* The flow is new */
@@ -344,6 +348,7 @@ sfq_dequeue(struct Qdisc* sch)
344 skb = __skb_dequeue(&q->qs[a]); 348 skb = __skb_dequeue(&q->qs[a]);
345 sfq_dec(q, a); 349 sfq_dec(q, a);
346 sch->q.qlen--; 350 sch->q.qlen--;
351 sch->qstats.backlog -= skb->len;
347 352
348 /* Is the slot empty? */ 353 /* Is the slot empty? */
349 if (q->qs[a].qlen == 0) { 354 if (q->qs[a].qlen == 0) {
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index cb9711ea8c6c..d8e03c74ca76 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -177,9 +177,9 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
177static unsigned int tbf_drop(struct Qdisc* sch) 177static unsigned int tbf_drop(struct Qdisc* sch)
178{ 178{
179 struct tbf_sched_data *q = qdisc_priv(sch); 179 struct tbf_sched_data *q = qdisc_priv(sch);
180 unsigned int len; 180 unsigned int len = 0;
181 181
182 if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { 182 if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
183 sch->q.qlen--; 183 sch->q.qlen--;
184 sch->qstats.drops++; 184 sch->qstats.drops++;
185 } 185 }
@@ -341,13 +341,14 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
341 if (max_size < 0) 341 if (max_size < 0)
342 goto done; 342 goto done;
343 343
344 if (q->qdisc == &noop_qdisc) { 344 if (qopt->limit > 0) {
345 if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) 345 if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL)
346 goto done; 346 goto done;
347 } 347 }
348 348
349 sch_tree_lock(sch); 349 sch_tree_lock(sch);
350 if (child) q->qdisc = child; 350 if (child)
351 qdisc_destroy(xchg(&q->qdisc, child));
351 q->limit = qopt->limit; 352 q->limit = qopt->limit;
352 q->mtu = qopt->mtu; 353 q->mtu = qopt->mtu;
353 q->max_size = max_size; 354 q->max_size = max_size;