diff options
author | Stephen Hemminger <stephen@networkplumber.org> | 2013-06-18 01:16:09 +0400 |
---|---|---|
committer | Stephen Hemminger <stephen@networkplumber.org> | 2013-06-24 19:40:32 +0400 |
commit | 758c57d16adcbec3c03e85f0c9a5b4ca31f6c507 (patch) | |
tree | bb9ede28bfdcef71cc152dbebb3329ded1e4bfff /drivers/net/vxlan.c | |
parent | b7153984074e51a50dad905871b705e0d67aa147 (diff) | |
download | linux-758c57d16adcbec3c03e85f0c9a5b4ca31f6c507.tar.xz |
vxlan: fix crash from work pending on module removal
Switch to using a per module work queue so that all the socket
deletion callbacks are done when module is removed.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r-- | drivers/net/vxlan.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d3005d3a768d..eb94bf5812cb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -148,6 +148,7 @@ struct vxlan_dev { /* salt for hash table */ static u32 vxlan_salt __read_mostly; +static struct workqueue_struct *vxlan_wq; /* Virtual Network hash table head */ static inline struct hlist_head *vni_head(struct vxlan_sock *vs, u32 id) @@ -1631,7 +1632,7 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) if (--vs->refcnt == 0) { hlist_del_rcu(&vs->hlist); - schedule_work(&vs->del_work); + queue_work(vxlan_wq, &vs->del_work); } } @@ -1750,6 +1751,10 @@ static int __init vxlan_init_module(void) { int rc; + vxlan_wq = alloc_workqueue("vxlan", 0, 0); + if (!vxlan_wq) + return -ENOMEM; + get_random_bytes(&vxlan_salt, sizeof(vxlan_salt)); rc = register_pernet_device(&vxlan_net_ops); @@ -1765,6 +1770,7 @@ static int __init vxlan_init_module(void) out2: unregister_pernet_device(&vxlan_net_ops); out1: + destroy_workqueue(vxlan_wq); return rc; } late_initcall(vxlan_init_module); @@ -1773,6 +1779,7 @@ static void __exit vxlan_cleanup_module(void) { unregister_pernet_device(&vxlan_net_ops); rtnl_link_unregister(&vxlan_link_ops); + destroy_workqueue(vxlan_wq); rcu_barrier(); } module_exit(vxlan_cleanup_module); |