diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_api.c | 11 | ||||
-rw-r--r-- | net/sched/act_mirred.c | 12 | ||||
-rw-r--r-- | net/sched/act_nat.c | 31 | ||||
-rw-r--r-- | net/sched/act_pedit.c | 3 | ||||
-rw-r--r-- | net/sched/act_police.c | 12 | ||||
-rw-r--r-- | net/sched/act_simple.c | 4 | ||||
-rw-r--r-- | net/sched/sch_atm.c | 98 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 25 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 2 |
9 files changed, 102 insertions, 96 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 972378f47f3c..23b25f89e7e0 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -26,6 +26,11 @@ | |||
26 | #include <net/act_api.h> | 26 | #include <net/act_api.h> |
27 | #include <net/netlink.h> | 27 | #include <net/netlink.h> |
28 | 28 | ||
29 | static void tcf_common_free_rcu(struct rcu_head *head) | ||
30 | { | ||
31 | kfree(container_of(head, struct tcf_common, tcfc_rcu)); | ||
32 | } | ||
33 | |||
29 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) | 34 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) |
30 | { | 35 | { |
31 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | 36 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); |
@@ -38,7 +43,11 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) | |||
38 | write_unlock_bh(hinfo->lock); | 43 | write_unlock_bh(hinfo->lock); |
39 | gen_kill_estimator(&p->tcfc_bstats, | 44 | gen_kill_estimator(&p->tcfc_bstats, |
40 | &p->tcfc_rate_est); | 45 | &p->tcfc_rate_est); |
41 | kfree(p); | 46 | /* |
47 | * gen_estimator est_timer() might access p->tcfc_lock | ||
48 | * or bstats, wait a RCU grace period before freeing p | ||
49 | */ | ||
50 | call_rcu(&p->tcfc_rcu, tcf_common_free_rcu); | ||
42 | return; | 51 | return; |
43 | } | 52 | } |
44 | } | 53 | } |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 1980b71c283f..11f195af2da0 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -165,6 +165,8 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
165 | 165 | ||
166 | spin_lock(&m->tcf_lock); | 166 | spin_lock(&m->tcf_lock); |
167 | m->tcf_tm.lastuse = jiffies; | 167 | m->tcf_tm.lastuse = jiffies; |
168 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
169 | m->tcf_bstats.packets++; | ||
168 | 170 | ||
169 | dev = m->tcfm_dev; | 171 | dev = m->tcfm_dev; |
170 | if (!dev) { | 172 | if (!dev) { |
@@ -179,13 +181,11 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
179 | goto out; | 181 | goto out; |
180 | } | 182 | } |
181 | 183 | ||
182 | skb2 = skb_act_clone(skb, GFP_ATOMIC); | 184 | at = G_TC_AT(skb->tc_verd); |
185 | skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action); | ||
183 | if (skb2 == NULL) | 186 | if (skb2 == NULL) |
184 | goto out; | 187 | goto out; |
185 | 188 | ||
186 | m->tcf_bstats.bytes += qdisc_pkt_len(skb2); | ||
187 | m->tcf_bstats.packets++; | ||
188 | at = G_TC_AT(skb->tc_verd); | ||
189 | if (!(at & AT_EGRESS)) { | 189 | if (!(at & AT_EGRESS)) { |
190 | if (m->tcfm_ok_push) | 190 | if (m->tcfm_ok_push) |
191 | skb_push(skb2, skb2->dev->hard_header_len); | 191 | skb_push(skb2, skb2->dev->hard_header_len); |
@@ -195,16 +195,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
195 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) | 195 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) |
196 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); | 196 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); |
197 | 197 | ||
198 | skb2->dev = dev; | ||
199 | skb2->skb_iif = skb->dev->ifindex; | 198 | skb2->skb_iif = skb->dev->ifindex; |
199 | skb2->dev = dev; | ||
200 | dev_queue_xmit(skb2); | 200 | dev_queue_xmit(skb2); |
201 | err = 0; | 201 | err = 0; |
202 | 202 | ||
203 | out: | 203 | out: |
204 | if (err) { | 204 | if (err) { |
205 | m->tcf_qstats.overlimits++; | 205 | m->tcf_qstats.overlimits++; |
206 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
207 | m->tcf_bstats.packets++; | ||
208 | /* should we be asking for packet to be dropped? | 206 | /* should we be asking for packet to be dropped? |
209 | * may make sense for redirect case only | 207 | * may make sense for redirect case only |
210 | */ | 208 | */ |
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 724553e8ed7b..24e614c495f2 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c | |||
@@ -268,40 +268,29 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, | |||
268 | { | 268 | { |
269 | unsigned char *b = skb_tail_pointer(skb); | 269 | unsigned char *b = skb_tail_pointer(skb); |
270 | struct tcf_nat *p = a->priv; | 270 | struct tcf_nat *p = a->priv; |
271 | struct tc_nat *opt; | 271 | struct tc_nat opt; |
272 | struct tcf_t t; | 272 | struct tcf_t t; |
273 | int s; | ||
274 | 273 | ||
275 | s = sizeof(*opt); | 274 | opt.old_addr = p->old_addr; |
275 | opt.new_addr = p->new_addr; | ||
276 | opt.mask = p->mask; | ||
277 | opt.flags = p->flags; | ||
276 | 278 | ||
277 | /* netlink spinlocks held above us - must use ATOMIC */ | 279 | opt.index = p->tcf_index; |
278 | opt = kzalloc(s, GFP_ATOMIC); | 280 | opt.action = p->tcf_action; |
279 | if (unlikely(!opt)) | 281 | opt.refcnt = p->tcf_refcnt - ref; |
280 | return -ENOBUFS; | 282 | opt.bindcnt = p->tcf_bindcnt - bind; |
281 | 283 | ||
282 | opt->old_addr = p->old_addr; | 284 | NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt); |
283 | opt->new_addr = p->new_addr; | ||
284 | opt->mask = p->mask; | ||
285 | opt->flags = p->flags; | ||
286 | |||
287 | opt->index = p->tcf_index; | ||
288 | opt->action = p->tcf_action; | ||
289 | opt->refcnt = p->tcf_refcnt - ref; | ||
290 | opt->bindcnt = p->tcf_bindcnt - bind; | ||
291 | |||
292 | NLA_PUT(skb, TCA_NAT_PARMS, s, opt); | ||
293 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); | 285 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); |
294 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); | 286 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); |
295 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); | 287 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); |
296 | NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); | 288 | NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); |
297 | 289 | ||
298 | kfree(opt); | ||
299 | |||
300 | return skb->len; | 290 | return skb->len; |
301 | 291 | ||
302 | nla_put_failure: | 292 | nla_put_failure: |
303 | nlmsg_trim(skb, b); | 293 | nlmsg_trim(skb, b); |
304 | kfree(opt); | ||
305 | return -1; | 294 | return -1; |
306 | } | 295 | } |
307 | 296 | ||
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 50e3d945e1f4..a0593c9640db 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
@@ -127,8 +127,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, | |||
127 | int i, munged = 0; | 127 | int i, munged = 0; |
128 | unsigned int off; | 128 | unsigned int off; |
129 | 129 | ||
130 | if (!(skb->tc_verd & TC_OK2MUNGE)) { | 130 | if (skb_cloned(skb)) { |
131 | /* should we set skb->cloned? */ | ||
132 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { | 131 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { |
133 | return p->tcf_action; | 132 | return p->tcf_action; |
134 | } | 133 | } |
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 654f73dff7c1..537a48732e9e 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -97,6 +97,11 @@ nla_put_failure: | |||
97 | goto done; | 97 | goto done; |
98 | } | 98 | } |
99 | 99 | ||
100 | static void tcf_police_free_rcu(struct rcu_head *head) | ||
101 | { | ||
102 | kfree(container_of(head, struct tcf_police, tcf_rcu)); | ||
103 | } | ||
104 | |||
100 | static void tcf_police_destroy(struct tcf_police *p) | 105 | static void tcf_police_destroy(struct tcf_police *p) |
101 | { | 106 | { |
102 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); | 107 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); |
@@ -113,7 +118,11 @@ static void tcf_police_destroy(struct tcf_police *p) | |||
113 | qdisc_put_rtab(p->tcfp_R_tab); | 118 | qdisc_put_rtab(p->tcfp_R_tab); |
114 | if (p->tcfp_P_tab) | 119 | if (p->tcfp_P_tab) |
115 | qdisc_put_rtab(p->tcfp_P_tab); | 120 | qdisc_put_rtab(p->tcfp_P_tab); |
116 | kfree(p); | 121 | /* |
122 | * gen_estimator est_timer() might access p->tcf_lock | ||
123 | * or bstats, wait a RCU grace period before freeing p | ||
124 | */ | ||
125 | call_rcu(&p->tcf_rcu, tcf_police_free_rcu); | ||
117 | return; | 126 | return; |
118 | } | 127 | } |
119 | } | 128 | } |
@@ -397,6 +406,7 @@ static void __exit | |||
397 | police_cleanup_module(void) | 406 | police_cleanup_module(void) |
398 | { | 407 | { |
399 | tcf_unregister_action(&act_police_ops); | 408 | tcf_unregister_action(&act_police_ops); |
409 | rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */ | ||
400 | } | 410 | } |
401 | 411 | ||
402 | module_init(police_init_module); | 412 | module_init(police_init_module); |
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 1b4bc691d7d1..4a1d640b0cf1 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
@@ -73,10 +73,10 @@ static int tcf_simp_release(struct tcf_defact *d, int bind) | |||
73 | 73 | ||
74 | static int alloc_defdata(struct tcf_defact *d, char *defdata) | 74 | static int alloc_defdata(struct tcf_defact *d, char *defdata) |
75 | { | 75 | { |
76 | d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL); | 76 | d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); |
77 | if (unlikely(!d->tcfd_defdata)) | 77 | if (unlikely(!d->tcfd_defdata)) |
78 | return -ENOMEM; | 78 | return -ENOMEM; |
79 | 79 | strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); | |
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index fcbb86a486a2..e114f23d5eae 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c | |||
@@ -52,7 +52,7 @@ struct atm_flow_data { | |||
52 | int ref; /* reference count */ | 52 | int ref; /* reference count */ |
53 | struct gnet_stats_basic_packed bstats; | 53 | struct gnet_stats_basic_packed bstats; |
54 | struct gnet_stats_queue qstats; | 54 | struct gnet_stats_queue qstats; |
55 | struct atm_flow_data *next; | 55 | struct list_head list; |
56 | struct atm_flow_data *excess; /* flow for excess traffic; | 56 | struct atm_flow_data *excess; /* flow for excess traffic; |
57 | NULL to set CLP instead */ | 57 | NULL to set CLP instead */ |
58 | int hdr_len; | 58 | int hdr_len; |
@@ -61,34 +61,23 @@ struct atm_flow_data { | |||
61 | 61 | ||
62 | struct atm_qdisc_data { | 62 | struct atm_qdisc_data { |
63 | struct atm_flow_data link; /* unclassified skbs go here */ | 63 | struct atm_flow_data link; /* unclassified skbs go here */ |
64 | struct atm_flow_data *flows; /* NB: "link" is also on this | 64 | struct list_head flows; /* NB: "link" is also on this |
65 | list */ | 65 | list */ |
66 | struct tasklet_struct task; /* dequeue tasklet */ | 66 | struct tasklet_struct task; /* dequeue tasklet */ |
67 | }; | 67 | }; |
68 | 68 | ||
69 | /* ------------------------- Class/flow operations ------------------------- */ | 69 | /* ------------------------- Class/flow operations ------------------------- */ |
70 | 70 | ||
71 | static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow) | ||
72 | { | ||
73 | struct atm_flow_data *walk; | ||
74 | |||
75 | pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow); | ||
76 | for (walk = qdisc->flows; walk; walk = walk->next) | ||
77 | if (walk == flow) | ||
78 | return 1; | ||
79 | pr_debug("find_flow: not found\n"); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) | 71 | static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) |
84 | { | 72 | { |
85 | struct atm_qdisc_data *p = qdisc_priv(sch); | 73 | struct atm_qdisc_data *p = qdisc_priv(sch); |
86 | struct atm_flow_data *flow; | 74 | struct atm_flow_data *flow; |
87 | 75 | ||
88 | for (flow = p->flows; flow; flow = flow->next) | 76 | list_for_each_entry(flow, &p->flows, list) { |
89 | if (flow->classid == classid) | 77 | if (flow->classid == classid) |
90 | break; | 78 | return flow; |
91 | return flow; | 79 | } |
80 | return NULL; | ||
92 | } | 81 | } |
93 | 82 | ||
94 | static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, | 83 | static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, |
@@ -99,7 +88,7 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, | |||
99 | 88 | ||
100 | pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", | 89 | pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", |
101 | sch, p, flow, new, old); | 90 | sch, p, flow, new, old); |
102 | if (!find_flow(p, flow)) | 91 | if (list_empty(&flow->list)) |
103 | return -EINVAL; | 92 | return -EINVAL; |
104 | if (!new) | 93 | if (!new) |
105 | new = &noop_qdisc; | 94 | new = &noop_qdisc; |
@@ -146,20 +135,12 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl) | |||
146 | { | 135 | { |
147 | struct atm_qdisc_data *p = qdisc_priv(sch); | 136 | struct atm_qdisc_data *p = qdisc_priv(sch); |
148 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; | 137 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; |
149 | struct atm_flow_data **prev; | ||
150 | 138 | ||
151 | pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); | 139 | pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); |
152 | if (--flow->ref) | 140 | if (--flow->ref) |
153 | return; | 141 | return; |
154 | pr_debug("atm_tc_put: destroying\n"); | 142 | pr_debug("atm_tc_put: destroying\n"); |
155 | for (prev = &p->flows; *prev; prev = &(*prev)->next) | 143 | list_del_init(&flow->list); |
156 | if (*prev == flow) | ||
157 | break; | ||
158 | if (!*prev) { | ||
159 | printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow); | ||
160 | return; | ||
161 | } | ||
162 | *prev = flow->next; | ||
163 | pr_debug("atm_tc_put: qdisc %p\n", flow->q); | 144 | pr_debug("atm_tc_put: qdisc %p\n", flow->q); |
164 | qdisc_destroy(flow->q); | 145 | qdisc_destroy(flow->q); |
165 | tcf_destroy_chain(&flow->filter_list); | 146 | tcf_destroy_chain(&flow->filter_list); |
@@ -274,7 +255,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
274 | error = -EINVAL; | 255 | error = -EINVAL; |
275 | goto err_out; | 256 | goto err_out; |
276 | } | 257 | } |
277 | if (find_flow(p, flow)) { | 258 | if (!list_empty(&flow->list)) { |
278 | error = -EEXIST; | 259 | error = -EEXIST; |
279 | goto err_out; | 260 | goto err_out; |
280 | } | 261 | } |
@@ -313,8 +294,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
313 | flow->classid = classid; | 294 | flow->classid = classid; |
314 | flow->ref = 1; | 295 | flow->ref = 1; |
315 | flow->excess = excess; | 296 | flow->excess = excess; |
316 | flow->next = p->link.next; | 297 | list_add(&flow->list, &p->link.list); |
317 | p->link.next = flow; | ||
318 | flow->hdr_len = hdr_len; | 298 | flow->hdr_len = hdr_len; |
319 | if (hdr) | 299 | if (hdr) |
320 | memcpy(flow->hdr, hdr, hdr_len); | 300 | memcpy(flow->hdr, hdr, hdr_len); |
@@ -335,7 +315,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg) | |||
335 | struct atm_flow_data *flow = (struct atm_flow_data *)arg; | 315 | struct atm_flow_data *flow = (struct atm_flow_data *)arg; |
336 | 316 | ||
337 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); | 317 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); |
338 | if (!find_flow(qdisc_priv(sch), flow)) | 318 | if (list_empty(&flow->list)) |
339 | return -EINVAL; | 319 | return -EINVAL; |
340 | if (flow->filter_list || flow == &p->link) | 320 | if (flow->filter_list || flow == &p->link) |
341 | return -EBUSY; | 321 | return -EBUSY; |
@@ -361,12 +341,12 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) | |||
361 | pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); | 341 | pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); |
362 | if (walker->stop) | 342 | if (walker->stop) |
363 | return; | 343 | return; |
364 | for (flow = p->flows; flow; flow = flow->next) { | 344 | list_for_each_entry(flow, &p->flows, list) { |
365 | if (walker->count >= walker->skip) | 345 | if (walker->count >= walker->skip && |
366 | if (walker->fn(sch, (unsigned long)flow, walker) < 0) { | 346 | walker->fn(sch, (unsigned long)flow, walker) < 0) { |
367 | walker->stop = 1; | 347 | walker->stop = 1; |
368 | break; | 348 | break; |
369 | } | 349 | } |
370 | walker->count++; | 350 | walker->count++; |
371 | } | 351 | } |
372 | } | 352 | } |
@@ -385,16 +365,17 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl) | |||
385 | static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 365 | static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
386 | { | 366 | { |
387 | struct atm_qdisc_data *p = qdisc_priv(sch); | 367 | struct atm_qdisc_data *p = qdisc_priv(sch); |
388 | struct atm_flow_data *flow = NULL; /* @@@ */ | 368 | struct atm_flow_data *flow; |
389 | struct tcf_result res; | 369 | struct tcf_result res; |
390 | int result; | 370 | int result; |
391 | int ret = NET_XMIT_POLICED; | 371 | int ret = NET_XMIT_POLICED; |
392 | 372 | ||
393 | pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); | 373 | pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); |
394 | result = TC_POLICE_OK; /* be nice to gcc */ | 374 | result = TC_POLICE_OK; /* be nice to gcc */ |
375 | flow = NULL; | ||
395 | if (TC_H_MAJ(skb->priority) != sch->handle || | 376 | if (TC_H_MAJ(skb->priority) != sch->handle || |
396 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) | 377 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) { |
397 | for (flow = p->flows; flow; flow = flow->next) | 378 | list_for_each_entry(flow, &p->flows, list) { |
398 | if (flow->filter_list) { | 379 | if (flow->filter_list) { |
399 | result = tc_classify_compat(skb, | 380 | result = tc_classify_compat(skb, |
400 | flow->filter_list, | 381 | flow->filter_list, |
@@ -404,8 +385,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
404 | flow = (struct atm_flow_data *)res.class; | 385 | flow = (struct atm_flow_data *)res.class; |
405 | if (!flow) | 386 | if (!flow) |
406 | flow = lookup_flow(sch, res.classid); | 387 | flow = lookup_flow(sch, res.classid); |
407 | break; | 388 | goto done; |
408 | } | 389 | } |
390 | } | ||
391 | flow = NULL; | ||
392 | done: | ||
393 | ; | ||
394 | } | ||
409 | if (!flow) | 395 | if (!flow) |
410 | flow = &p->link; | 396 | flow = &p->link; |
411 | else { | 397 | else { |
@@ -477,7 +463,9 @@ static void sch_atm_dequeue(unsigned long data) | |||
477 | struct sk_buff *skb; | 463 | struct sk_buff *skb; |
478 | 464 | ||
479 | pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); | 465 | pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); |
480 | for (flow = p->link.next; flow; flow = flow->next) | 466 | list_for_each_entry(flow, &p->flows, list) { |
467 | if (flow == &p->link) | ||
468 | continue; | ||
481 | /* | 469 | /* |
482 | * If traffic is properly shaped, this won't generate nasty | 470 | * If traffic is properly shaped, this won't generate nasty |
483 | * little bursts. Otherwise, it may ... (but that's okay) | 471 | * little bursts. Otherwise, it may ... (but that's okay) |
@@ -512,6 +500,7 @@ static void sch_atm_dequeue(unsigned long data) | |||
512 | /* atm.atm_options are already set by atm_tc_enqueue */ | 500 | /* atm.atm_options are already set by atm_tc_enqueue */ |
513 | flow->vcc->send(flow->vcc, skb); | 501 | flow->vcc->send(flow->vcc, skb); |
514 | } | 502 | } |
503 | } | ||
515 | } | 504 | } |
516 | 505 | ||
517 | static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) | 506 | static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) |
@@ -543,9 +532,10 @@ static unsigned int atm_tc_drop(struct Qdisc *sch) | |||
543 | unsigned int len; | 532 | unsigned int len; |
544 | 533 | ||
545 | pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); | 534 | pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); |
546 | for (flow = p->flows; flow; flow = flow->next) | 535 | list_for_each_entry(flow, &p->flows, list) { |
547 | if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) | 536 | if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) |
548 | return len; | 537 | return len; |
538 | } | ||
549 | return 0; | 539 | return 0; |
550 | } | 540 | } |
551 | 541 | ||
@@ -554,7 +544,9 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
554 | struct atm_qdisc_data *p = qdisc_priv(sch); | 544 | struct atm_qdisc_data *p = qdisc_priv(sch); |
555 | 545 | ||
556 | pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); | 546 | pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); |
557 | p->flows = &p->link; | 547 | INIT_LIST_HEAD(&p->flows); |
548 | INIT_LIST_HEAD(&p->link.list); | ||
549 | list_add(&p->link.list, &p->flows); | ||
558 | p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 550 | p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, |
559 | &pfifo_qdisc_ops, sch->handle); | 551 | &pfifo_qdisc_ops, sch->handle); |
560 | if (!p->link.q) | 552 | if (!p->link.q) |
@@ -565,7 +557,6 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
565 | p->link.sock = NULL; | 557 | p->link.sock = NULL; |
566 | p->link.classid = sch->handle; | 558 | p->link.classid = sch->handle; |
567 | p->link.ref = 1; | 559 | p->link.ref = 1; |
568 | p->link.next = NULL; | ||
569 | tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); | 560 | tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); |
570 | return 0; | 561 | return 0; |
571 | } | 562 | } |
@@ -576,7 +567,7 @@ static void atm_tc_reset(struct Qdisc *sch) | |||
576 | struct atm_flow_data *flow; | 567 | struct atm_flow_data *flow; |
577 | 568 | ||
578 | pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); | 569 | pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); |
579 | for (flow = p->flows; flow; flow = flow->next) | 570 | list_for_each_entry(flow, &p->flows, list) |
580 | qdisc_reset(flow->q); | 571 | qdisc_reset(flow->q); |
581 | sch->q.qlen = 0; | 572 | sch->q.qlen = 0; |
582 | } | 573 | } |
@@ -584,24 +575,17 @@ static void atm_tc_reset(struct Qdisc *sch) | |||
584 | static void atm_tc_destroy(struct Qdisc *sch) | 575 | static void atm_tc_destroy(struct Qdisc *sch) |
585 | { | 576 | { |
586 | struct atm_qdisc_data *p = qdisc_priv(sch); | 577 | struct atm_qdisc_data *p = qdisc_priv(sch); |
587 | struct atm_flow_data *flow; | 578 | struct atm_flow_data *flow, *tmp; |
588 | 579 | ||
589 | pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); | 580 | pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); |
590 | for (flow = p->flows; flow; flow = flow->next) | 581 | list_for_each_entry(flow, &p->flows, list) |
591 | tcf_destroy_chain(&flow->filter_list); | 582 | tcf_destroy_chain(&flow->filter_list); |
592 | 583 | ||
593 | /* races ? */ | 584 | list_for_each_entry_safe(flow, tmp, &p->flows, list) { |
594 | while ((flow = p->flows)) { | ||
595 | if (flow->ref > 1) | 585 | if (flow->ref > 1) |
596 | printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow, | 586 | printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow, |
597 | flow->ref); | 587 | flow->ref); |
598 | atm_tc_put(sch, (unsigned long)flow); | 588 | atm_tc_put(sch, (unsigned long)flow); |
599 | if (p->flows == flow) { | ||
600 | printk(KERN_ERR "atm_destroy: putting flow %p didn't " | ||
601 | "kill it\n", flow); | ||
602 | p->flows = flow->next; /* brute force */ | ||
603 | break; | ||
604 | } | ||
605 | } | 589 | } |
606 | tasklet_kill(&p->task); | 590 | tasklet_kill(&p->task); |
607 | } | 591 | } |
@@ -615,7 +599,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, | |||
615 | 599 | ||
616 | pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", | 600 | pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", |
617 | sch, p, flow, skb, tcm); | 601 | sch, p, flow, skb, tcm); |
618 | if (!find_flow(p, flow)) | 602 | if (list_empty(&flow->list)) |
619 | return -EINVAL; | 603 | return -EINVAL; |
620 | tcm->tcm_handle = flow->classid; | 604 | tcm->tcm_handle = flow->classid; |
621 | tcm->tcm_info = flow->q->handle; | 605 | tcm->tcm_info = flow->q->handle; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index a63029ef3edd..2aeb3a4386a1 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -96,7 +96,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, | |||
96 | * Another cpu is holding lock, requeue & delay xmits for | 96 | * Another cpu is holding lock, requeue & delay xmits for |
97 | * some time. | 97 | * some time. |
98 | */ | 98 | */ |
99 | __get_cpu_var(softnet_data).cpu_collision++; | 99 | __this_cpu_inc(softnet_data.cpu_collision); |
100 | ret = dev_requeue_skb(skb, q); | 100 | ret = dev_requeue_skb(skb, q); |
101 | } | 101 | } |
102 | 102 | ||
@@ -205,7 +205,7 @@ void __qdisc_run(struct Qdisc *q) | |||
205 | } | 205 | } |
206 | } | 206 | } |
207 | 207 | ||
208 | clear_bit(__QDISC_STATE_RUNNING, &q->state); | 208 | qdisc_run_end(q); |
209 | } | 209 | } |
210 | 210 | ||
211 | unsigned long dev_trans_start(struct net_device *dev) | 211 | unsigned long dev_trans_start(struct net_device *dev) |
@@ -327,6 +327,24 @@ void netif_carrier_off(struct net_device *dev) | |||
327 | } | 327 | } |
328 | EXPORT_SYMBOL(netif_carrier_off); | 328 | EXPORT_SYMBOL(netif_carrier_off); |
329 | 329 | ||
330 | /** | ||
331 | * netif_notify_peers - notify network peers about existence of @dev | ||
332 | * @dev: network device | ||
333 | * | ||
334 | * Generate traffic such that interested network peers are aware of | ||
335 | * @dev, such as by generating a gratuitous ARP. This may be used when | ||
336 | * a device wants to inform the rest of the network about some sort of | ||
337 | * reconfiguration such as a failover event or virtual machine | ||
338 | * migration. | ||
339 | */ | ||
340 | void netif_notify_peers(struct net_device *dev) | ||
341 | { | ||
342 | rtnl_lock(); | ||
343 | call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev); | ||
344 | rtnl_unlock(); | ||
345 | } | ||
346 | EXPORT_SYMBOL(netif_notify_peers); | ||
347 | |||
330 | /* "NOOP" scheduler: the best scheduler, recommended for all interfaces | 348 | /* "NOOP" scheduler: the best scheduler, recommended for all interfaces |
331 | under all circumstances. It is difficult to invent anything faster or | 349 | under all circumstances. It is difficult to invent anything faster or |
332 | cheaper. | 350 | cheaper. |
@@ -543,6 +561,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, | |||
543 | 561 | ||
544 | INIT_LIST_HEAD(&sch->list); | 562 | INIT_LIST_HEAD(&sch->list); |
545 | skb_queue_head_init(&sch->q); | 563 | skb_queue_head_init(&sch->q); |
564 | spin_lock_init(&sch->busylock); | ||
546 | sch->ops = ops; | 565 | sch->ops = ops; |
547 | sch->enqueue = ops->enqueue; | 566 | sch->enqueue = ops->enqueue; |
548 | sch->dequeue = ops->dequeue; | 567 | sch->dequeue = ops->dequeue; |
@@ -779,7 +798,7 @@ static bool some_qdisc_is_busy(struct net_device *dev) | |||
779 | 798 | ||
780 | spin_lock_bh(root_lock); | 799 | spin_lock_bh(root_lock); |
781 | 800 | ||
782 | val = (test_bit(__QDISC_STATE_RUNNING, &q->state) || | 801 | val = (qdisc_is_running(q) || |
783 | test_bit(__QDISC_STATE_SCHED, &q->state)); | 802 | test_bit(__QDISC_STATE_SCHED, &q->state)); |
784 | 803 | ||
785 | spin_unlock_bh(root_lock); | 804 | spin_unlock_bh(root_lock); |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 0b52b8de562c..4be8d04b262d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1550,7 +1550,6 @@ static const struct Qdisc_class_ops htb_class_ops = { | |||
1550 | }; | 1550 | }; |
1551 | 1551 | ||
1552 | static struct Qdisc_ops htb_qdisc_ops __read_mostly = { | 1552 | static struct Qdisc_ops htb_qdisc_ops __read_mostly = { |
1553 | .next = NULL, | ||
1554 | .cl_ops = &htb_class_ops, | 1553 | .cl_ops = &htb_class_ops, |
1555 | .id = "htb", | 1554 | .id = "htb", |
1556 | .priv_size = sizeof(struct htb_sched), | 1555 | .priv_size = sizeof(struct htb_sched), |
@@ -1561,7 +1560,6 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = { | |||
1561 | .init = htb_init, | 1560 | .init = htb_init, |
1562 | .reset = htb_reset, | 1561 | .reset = htb_reset, |
1563 | .destroy = htb_destroy, | 1562 | .destroy = htb_destroy, |
1564 | .change = NULL /* htb_change */, | ||
1565 | .dump = htb_dump, | 1563 | .dump = htb_dump, |
1566 | .owner = THIS_MODULE, | 1564 | .owner = THIS_MODULE, |
1567 | }; | 1565 | }; |