diff options
author | David S. Miller <davem@davemloft.net> | 2010-07-28 00:01:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-28 00:01:35 -0400 |
commit | bb7e95c8fd859922c6cf3ebbb3a8546007df1748 (patch) | |
tree | 58b54c6306ba168b76f25cc6dc9a2d1d2eb830a7 /net/sched | |
parent | b8bc0421ab7f83712a0a8ef7eb05fa73ec53c027 (diff) | |
parent | 5447080cfa3c77154498dfbf225367ac85b4c2b5 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
drivers/net/bnx2x_main.c
Merge bnx2x bug fixes in by hand... :-/
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_mirred.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index a16b0175f890..11f195af2da0 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -33,6 +33,7 @@ | |||
33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; | 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; |
34 | static u32 mirred_idx_gen; | 34 | static u32 mirred_idx_gen; |
35 | static DEFINE_RWLOCK(mirred_lock); | 35 | static DEFINE_RWLOCK(mirred_lock); |
36 | static LIST_HEAD(mirred_list); | ||
36 | 37 | ||
37 | static struct tcf_hashinfo mirred_hash_info = { | 38 | static struct tcf_hashinfo mirred_hash_info = { |
38 | .htab = tcf_mirred_ht, | 39 | .htab = tcf_mirred_ht, |
@@ -47,7 +48,9 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) | |||
47 | m->tcf_bindcnt--; | 48 | m->tcf_bindcnt--; |
48 | m->tcf_refcnt--; | 49 | m->tcf_refcnt--; |
49 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { | 50 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { |
50 | dev_put(m->tcfm_dev); | 51 | list_del(&m->tcfm_list); |
52 | if (m->tcfm_dev) | ||
53 | dev_put(m->tcfm_dev); | ||
51 | tcf_hash_destroy(&m->common, &mirred_hash_info); | 54 | tcf_hash_destroy(&m->common, &mirred_hash_info); |
52 | return 1; | 55 | return 1; |
53 | } | 56 | } |
@@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, | |||
134 | m->tcfm_ok_push = ok_push; | 137 | m->tcfm_ok_push = ok_push; |
135 | } | 138 | } |
136 | spin_unlock_bh(&m->tcf_lock); | 139 | spin_unlock_bh(&m->tcf_lock); |
137 | if (ret == ACT_P_CREATED) | 140 | if (ret == ACT_P_CREATED) { |
141 | list_add(&m->tcfm_list, &mirred_list); | ||
138 | tcf_hash_insert(pc, &mirred_hash_info); | 142 | tcf_hash_insert(pc, &mirred_hash_info); |
143 | } | ||
139 | 144 | ||
140 | return ret; | 145 | return ret; |
141 | } | 146 | } |
@@ -164,9 +169,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
164 | m->tcf_bstats.packets++; | 169 | m->tcf_bstats.packets++; |
165 | 170 | ||
166 | dev = m->tcfm_dev; | 171 | dev = m->tcfm_dev; |
172 | if (!dev) { | ||
173 | printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
167 | if (!(dev->flags & IFF_UP)) { | 177 | if (!(dev->flags & IFF_UP)) { |
168 | if (net_ratelimit()) | 178 | if (net_ratelimit()) |
169 | pr_notice("tc mirred to Houston: device %s is gone!\n", | 179 | pr_notice("tc mirred to Houston: device %s is down\n", |
170 | dev->name); | 180 | dev->name); |
171 | goto out; | 181 | goto out; |
172 | } | 182 | } |
@@ -230,6 +240,28 @@ nla_put_failure: | |||
230 | return -1; | 240 | return -1; |
231 | } | 241 | } |
232 | 242 | ||
243 | static int mirred_device_event(struct notifier_block *unused, | ||
244 | unsigned long event, void *ptr) | ||
245 | { | ||
246 | struct net_device *dev = ptr; | ||
247 | struct tcf_mirred *m; | ||
248 | |||
249 | if (event == NETDEV_UNREGISTER) | ||
250 | list_for_each_entry(m, &mirred_list, tcfm_list) { | ||
251 | if (m->tcfm_dev == dev) { | ||
252 | dev_put(dev); | ||
253 | m->tcfm_dev = NULL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | return NOTIFY_DONE; | ||
258 | } | ||
259 | |||
260 | static struct notifier_block mirred_device_notifier = { | ||
261 | .notifier_call = mirred_device_event, | ||
262 | }; | ||
263 | |||
264 | |||
233 | static struct tc_action_ops act_mirred_ops = { | 265 | static struct tc_action_ops act_mirred_ops = { |
234 | .kind = "mirred", | 266 | .kind = "mirred", |
235 | .hinfo = &mirred_hash_info, | 267 | .hinfo = &mirred_hash_info, |
@@ -250,12 +282,17 @@ MODULE_LICENSE("GPL"); | |||
250 | 282 | ||
251 | static int __init mirred_init_module(void) | 283 | static int __init mirred_init_module(void) |
252 | { | 284 | { |
285 | int err = register_netdevice_notifier(&mirred_device_notifier); | ||
286 | if (err) | ||
287 | return err; | ||
288 | |||
253 | pr_info("Mirror/redirect action on\n"); | 289 | pr_info("Mirror/redirect action on\n"); |
254 | return tcf_register_action(&act_mirred_ops); | 290 | return tcf_register_action(&act_mirred_ops); |
255 | } | 291 | } |
256 | 292 | ||
257 | static void __exit mirred_cleanup_module(void) | 293 | static void __exit mirred_cleanup_module(void) |
258 | { | 294 | { |
295 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
259 | tcf_unregister_action(&act_mirred_ops); | 296 | tcf_unregister_action(&act_mirred_ops); |
260 | } | 297 | } |
261 | 298 | ||