aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-18 13:51:57 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:36:05 -0400
commitad002395fd230528281083f4be71855ed7e35b04 (patch)
treec2bccce17ad69dcfb454fe3a38ba68f0f210b5b5
parent21f8a73f829797eb7ebc12202b4c68e10e751ddb (diff)
cfg80211: fix dangling scan request checking
My patch "cfg80211: fix deadlock" broke the code it was supposed to fix, the scan request checking. But it's not trivial to put it back the way it was, since the original patch had a deadlock. Now do it in a completely new way: queue the check off to a work struct, where we can freely lock. But that has some more complications, like needing to wait for it to be done before the wiphy/rdev can be destroyed, so some code is required to handle that. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/cfg80211.h2
-rw-r--r--net/wireless/core.c76
-rw-r--r--net/wireless/core.h2
3 files changed, 67 insertions, 13 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0b146bb2dd14..3d874c620219 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1325,6 +1325,8 @@ struct wireless_dev {
1325 1325
1326 struct mutex mtx; 1326 struct mutex mtx;
1327 1327
1328 struct work_struct cleanup_work;
1329
1328 /* currently used for IBSS and SME - might be rearranged later */ 1330 /* currently used for IBSS and SME - might be rearranged later */
1329 u8 ssid[IEEE80211_MAX_SSID_LEN]; 1331 u8 ssid[IEEE80211_MAX_SSID_LEN];
1330 u8 ssid_len; 1332 u8 ssid_len;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 69a185ba9ff1..c150071b6f29 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -430,6 +430,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
430 INIT_WORK(&rdev->conn_work, cfg80211_conn_work); 430 INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
431 INIT_WORK(&rdev->event_work, cfg80211_event_work); 431 INIT_WORK(&rdev->event_work, cfg80211_event_work);
432 432
433 init_waitqueue_head(&rdev->dev_wait);
434
433 /* 435 /*
434 * Initialize wiphy parameters to IEEE 802.11 MIB default values. 436 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
435 * Fragmentation and RTS threshold are disabled by default with the 437 * Fragmentation and RTS threshold are disabled by default with the
@@ -574,7 +576,23 @@ void wiphy_unregister(struct wiphy *wiphy)
574 /* protect the device list */ 576 /* protect the device list */
575 mutex_lock(&cfg80211_mutex); 577 mutex_lock(&cfg80211_mutex);
576 578
579 wait_event(rdev->dev_wait, ({
580 int __count;
581 mutex_lock(&rdev->devlist_mtx);
582 __count = rdev->opencount;
583 mutex_unlock(&rdev->devlist_mtx);
584 __count == 0;}));
585
586 mutex_lock(&rdev->devlist_mtx);
577 BUG_ON(!list_empty(&rdev->netdev_list)); 587 BUG_ON(!list_empty(&rdev->netdev_list));
588 mutex_unlock(&rdev->devlist_mtx);
589
590 /*
591 * First remove the hardware from everywhere, this makes
592 * it impossible to find from userspace.
593 */
594 cfg80211_debugfs_rdev_del(rdev);
595 list_del(&rdev->list);
578 596
579 /* 597 /*
580 * Try to grab rdev->mtx. If a command is still in progress, 598 * Try to grab rdev->mtx. If a command is still in progress,
@@ -582,26 +600,18 @@ void wiphy_unregister(struct wiphy *wiphy)
582 * down the device already. We wait for this command to complete 600 * down the device already. We wait for this command to complete
583 * before unlinking the item from the list. 601 * before unlinking the item from the list.
584 * Note: as codified by the BUG_ON above we cannot get here if 602 * Note: as codified by the BUG_ON above we cannot get here if
585 * a virtual interface is still associated. Hence, we can only 603 * a virtual interface is still present. Hence, we can only get
586 * get to lock contention here if userspace issues a command 604 * to lock contention here if userspace issues a command that
587 * that identified the hardware by wiphy index. 605 * identified the hardware by wiphy index.
588 */ 606 */
589 cfg80211_lock_rdev(rdev); 607 cfg80211_lock_rdev(rdev);
590 608 /* nothing */
591 if (WARN_ON(rdev->scan_req)) {
592 rdev->scan_req->aborted = true;
593 ___cfg80211_scan_done(rdev);
594 }
595
596 cfg80211_unlock_rdev(rdev); 609 cfg80211_unlock_rdev(rdev);
597 610
598 cfg80211_debugfs_rdev_del(rdev);
599
600 /* If this device got a regulatory hint tell core its 611 /* If this device got a regulatory hint tell core its
601 * free to listen now to a new shiny device regulatory hint */ 612 * free to listen now to a new shiny device regulatory hint */
602 reg_device_remove(wiphy); 613 reg_device_remove(wiphy);
603 614
604 list_del(&rdev->list);
605 cfg80211_rdev_list_generation++; 615 cfg80211_rdev_list_generation++;
606 device_del(&rdev->wiphy.dev); 616 device_del(&rdev->wiphy.dev);
607 debugfs_remove(rdev->wiphy.debugfsdir); 617 debugfs_remove(rdev->wiphy.debugfsdir);
@@ -640,6 +650,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
640} 650}
641EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); 651EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
642 652
653static void wdev_cleanup_work(struct work_struct *work)
654{
655 struct wireless_dev *wdev;
656 struct cfg80211_registered_device *rdev;
657
658 wdev = container_of(work, struct wireless_dev, cleanup_work);
659 rdev = wiphy_to_dev(wdev->wiphy);
660
661 cfg80211_lock_rdev(rdev);
662
663 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
664 rdev->scan_req->aborted = true;
665 ___cfg80211_scan_done(rdev);
666 }
667
668 cfg80211_unlock_rdev(rdev);
669
670 mutex_lock(&rdev->devlist_mtx);
671 rdev->opencount--;
672 mutex_unlock(&rdev->devlist_mtx);
673 wake_up(&rdev->dev_wait);
674
675 dev_put(wdev->netdev);
676}
677
643static int cfg80211_netdev_notifier_call(struct notifier_block * nb, 678static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
644 unsigned long state, 679 unsigned long state,
645 void *ndev) 680 void *ndev)
@@ -663,6 +698,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
663 * are added with nl80211. 698 * are added with nl80211.
664 */ 699 */
665 mutex_init(&wdev->mtx); 700 mutex_init(&wdev->mtx);
701 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
666 INIT_LIST_HEAD(&wdev->event_list); 702 INIT_LIST_HEAD(&wdev->event_list);
667 spin_lock_init(&wdev->event_lock); 703 spin_lock_init(&wdev->event_lock);
668 mutex_lock(&rdev->devlist_mtx); 704 mutex_lock(&rdev->devlist_mtx);
@@ -717,8 +753,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
717 default: 753 default:
718 break; 754 break;
719 } 755 }
756 dev_hold(dev);
757 schedule_work(&wdev->cleanup_work);
720 break; 758 break;
721 case NETDEV_UP: 759 case NETDEV_UP:
760 /*
761 * If we have a really quick DOWN/UP succession we may
762 * have this work still pending ... cancel it and see
763 * if it was pending, in which case we need to account
764 * for some of the work it would have done.
765 */
766 if (cancel_work_sync(&wdev->cleanup_work)) {
767 mutex_lock(&rdev->devlist_mtx);
768 rdev->opencount--;
769 mutex_unlock(&rdev->devlist_mtx);
770 dev_put(dev);
771 }
722#ifdef CONFIG_WIRELESS_EXT 772#ifdef CONFIG_WIRELESS_EXT
723 cfg80211_lock_rdev(rdev); 773 cfg80211_lock_rdev(rdev);
724 mutex_lock(&rdev->devlist_mtx); 774 mutex_lock(&rdev->devlist_mtx);
@@ -734,6 +784,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
734 break; 784 break;
735 } 785 }
736 wdev_unlock(wdev); 786 wdev_unlock(wdev);
787 rdev->opencount++;
737 mutex_unlock(&rdev->devlist_mtx); 788 mutex_unlock(&rdev->devlist_mtx);
738 cfg80211_unlock_rdev(rdev); 789 cfg80211_unlock_rdev(rdev);
739#endif 790#endif
@@ -756,7 +807,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
756 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 807 sysfs_remove_link(&dev->dev.kobj, "phy80211");
757 list_del_init(&wdev->list); 808 list_del_init(&wdev->list);
758 rdev->devlist_generation++; 809 rdev->devlist_generation++;
759 mutex_destroy(&wdev->mtx);
760#ifdef CONFIG_WIRELESS_EXT 810#ifdef CONFIG_WIRELESS_EXT
761 kfree(wdev->wext.keys); 811 kfree(wdev->wext.keys);
762#endif 812#endif
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c603f5286326..f565432ae22f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -50,6 +50,8 @@ struct cfg80211_registered_device {
50 struct mutex devlist_mtx; 50 struct mutex devlist_mtx;
51 struct list_head netdev_list; 51 struct list_head netdev_list;
52 int devlist_generation; 52 int devlist_generation;
53 int opencount; /* also protected by devlist_mtx */
54 wait_queue_head_t dev_wait;
53 55
54 /* BSSes/scanning */ 56 /* BSSes/scanning */
55 spinlock_t bss_lock; 57 spinlock_t bss_lock;