mac80211_hwsim: add workqueue to wait for deferred radio deletion on mod unload
authorBenjamin Beichler <benjamin.beichler@uni-rostock.de>
Wed, 10 Jan 2018 16:42:51 +0000 (17:42 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 15 Jan 2018 08:18:27 +0000 (09:18 +0100)
When closing multiple wmediumd instances with many radios and try to
unload the  mac80211_hwsim module, it may happen that the work items live
longer than the module. To wait especially for this deletion work items,
add a work queue, otherwise flush_scheduled_work would be necessary.

Signed-off-by: Benjamin Beichler <benjamin.beichler@uni-rostock.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/mac80211_hwsim.c

index e8189c07b41f6b450f135ef703ec4e01568e311d..ccd573e53c92a18ab077c462f0fdcd309a788bde 100644 (file)
@@ -489,6 +489,7 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
 
 static spinlock_t hwsim_radio_lock;
 static LIST_HEAD(hwsim_radios);
+static struct workqueue_struct *hwsim_wq;
 static int hwsim_radio_idx;
 
 static struct platform_driver mac80211_hwsim_driver = {
@@ -3342,7 +3343,7 @@ static void remove_user_radios(u32 portid)
                if (entry->destroy_on_close && entry->portid == portid) {
                        list_del(&entry->list);
                        INIT_WORK(&entry->destroy_work, destroy_radio);
-                       schedule_work(&entry->destroy_work);
+                       queue_work(hwsim_wq, &entry->destroy_work);
                }
        }
        spin_unlock_bh(&hwsim_radio_lock);
@@ -3417,7 +3418,7 @@ static void __net_exit hwsim_exit_net(struct net *net)
 
                list_del(&data->list);
                INIT_WORK(&data->destroy_work, destroy_radio);
-               schedule_work(&data->destroy_work);
+               queue_work(hwsim_wq, &data->destroy_work);
        }
        spin_unlock_bh(&hwsim_radio_lock);
 }
@@ -3449,6 +3450,10 @@ static int __init init_mac80211_hwsim(void)
 
        spin_lock_init(&hwsim_radio_lock);
 
+       hwsim_wq = alloc_workqueue("hwsim_wq",WQ_MEM_RECLAIM,0);
+       if (!hwsim_wq)
+               return -ENOMEM;
+
        err = register_pernet_device(&hwsim_net_ops);
        if (err)
                return err;
@@ -3587,8 +3592,11 @@ static void __exit exit_mac80211_hwsim(void)
        hwsim_exit_netlink();
 
        mac80211_hwsim_free();
+       flush_workqueue(hwsim_wq);
+
        unregister_netdev(hwsim_mon);
        platform_driver_unregister(&mac80211_hwsim_driver);
        unregister_pernet_device(&hwsim_net_ops);
+       destroy_workqueue(hwsim_wq);
 }
 module_exit(exit_mac80211_hwsim);