From 758c57d16adcbec3c03e85f0c9a5b4ca31f6c507 Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <stephen@networkplumber.org>
Date: Mon, 17 Jun 2013 14:16:09 -0700
Subject: [PATCH] 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>
---
 drivers/net/vxlan.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

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);
-- 
2.34.1