aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-17 06:25:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:35:56 -0400
commit0ff6ce7b36199f67f709c750e9a2a66659a4babe (patch)
tree3b023b960e010b7ce84d35d8e9b516f5cb285f77 /net/wireless
parent96909e97716de1d86e6e24d6aabce09980372771 (diff)
cfg80211: fix deadlock
When removing an interface with nl80211, cfg80211 will deadlock in the netdev notifier because we're already holding rdev->mtx and try to acquire it again to verify the scan has been done. This bug was introduced by my patch "cfg80211: check for and abort dangling scan requests". To fix this, move the dangling scan request check into wiphy_unregister(). This will not be able to catch all cases right away, but if the scan problem happens with a manual ifdown or so it will be possible to remedy it by removing the module/device. Additionally, add comments about the deadlock scenario. Reported-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Tested-by: Christian Lamparter <chunkeey@web.de> Tested-by: Kalle Valo <kalle.valo@iki.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index bc99e4ec7463..69a185ba9ff1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -586,9 +586,14 @@ void wiphy_unregister(struct wiphy *wiphy)
586 * get to lock contention here if userspace issues a command 586 * get to lock contention here if userspace issues a command
587 * that identified the hardware by wiphy index. 587 * that identified the hardware by wiphy index.
588 */ 588 */
589 mutex_lock(&rdev->mtx); 589 cfg80211_lock_rdev(rdev);
590 /* unlock again before freeing */ 590
591 mutex_unlock(&rdev->mtx); 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);
592 597
593 cfg80211_debugfs_rdev_del(rdev); 598 cfg80211_debugfs_rdev_del(rdev);
594 599
@@ -605,7 +610,6 @@ void wiphy_unregister(struct wiphy *wiphy)
605 610
606 flush_work(&rdev->scan_done_wk); 611 flush_work(&rdev->scan_done_wk);
607 cancel_work_sync(&rdev->conn_work); 612 cancel_work_sync(&rdev->conn_work);
608 kfree(rdev->scan_req);
609 flush_work(&rdev->event_work); 613 flush_work(&rdev->event_work);
610} 614}
611EXPORT_SYMBOL(wiphy_unregister); 615EXPORT_SYMBOL(wiphy_unregister);
@@ -653,6 +657,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
653 657
654 switch (state) { 658 switch (state) {
655 case NETDEV_REGISTER: 659 case NETDEV_REGISTER:
660 /*
661 * NB: cannot take rdev->mtx here because this may be
662 * called within code protected by it when interfaces
663 * are added with nl80211.
664 */
656 mutex_init(&wdev->mtx); 665 mutex_init(&wdev->mtx);
657 INIT_LIST_HEAD(&wdev->event_list); 666 INIT_LIST_HEAD(&wdev->event_list);
658 spin_lock_init(&wdev->event_lock); 667 spin_lock_init(&wdev->event_lock);
@@ -730,13 +739,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
730#endif 739#endif
731 break; 740 break;
732 case NETDEV_UNREGISTER: 741 case NETDEV_UNREGISTER:
733 cfg80211_lock_rdev(rdev); 742 /*
734 743 * NB: cannot take rdev->mtx here because this may be
735 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { 744 * called within code protected by it when interfaces
736 rdev->scan_req->aborted = true; 745 * are removed with nl80211.
737 ___cfg80211_scan_done(rdev); 746 */
738 }
739
740 mutex_lock(&rdev->devlist_mtx); 747 mutex_lock(&rdev->devlist_mtx);
741 /* 748 /*
742 * It is possible to get NETDEV_UNREGISTER 749 * It is possible to get NETDEV_UNREGISTER
@@ -755,7 +762,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
755#endif 762#endif
756 } 763 }
757 mutex_unlock(&rdev->devlist_mtx); 764 mutex_unlock(&rdev->devlist_mtx);
758 cfg80211_unlock_rdev(rdev);
759 break; 765 break;
760 case NETDEV_PRE_UP: 766 case NETDEV_PRE_UP:
761 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) 767 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))