aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorLuciano Coelho <coelho@ti.com>2011-06-30 01:32:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-05 14:42:36 -0400
commitc10841ca722a0bc960dc541c51582773f9a24f98 (patch)
treef1e5901db0a530cfd4008f718a908a86bddcb333 /net/wireless/core.c
parent37000b305bff81bb1ee2f7f37b1319b670a08f76 (diff)
cfg80211: fix deadlock with rfkill/sched_scan by adding new mutex
There was a deadlock when rfkill-blocking a wireless interface, because we were locking the rdev mutex on NETDEV_GOING_DOWN to stop sched_scans that were eventually running. The rfkill block code was already holding a mutex under rdev: kernel: ======================================================= kernel: [ INFO: possible circular locking dependency detected ] kernel: 3.0.0-rc1-00049-g1fa7b6a #57 kernel: ------------------------------------------------------- kernel: kworker/0:1/4525 is trying to acquire lock: kernel: (&rdev->mtx){+.+.+.}, at: [<ffffffff8164c831>] cfg80211_netdev_notifier_call+0x131/0x5b0 kernel: kernel: but task is already holding lock: kernel: (&rdev->devlist_mtx){+.+.+.}, at: [<ffffffff8164dcef>] cfg80211_rfkill_set_block+0x4f/0xa0 kernel: kernel: which lock already depends on the new lock. To fix this, add a new mutex specifically for sched_scan, to protect the sched_scan_req element in the rdev struct, instead of using the global rdev mutex. Reported-by: Duane Griffin <duaneg@dghda.com> Signed-off-by: Luciano Coelho <coelho@ti.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c22ef3492ee6..880dbe2e6f94 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -366,6 +366,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
366 366
367 mutex_init(&rdev->mtx); 367 mutex_init(&rdev->mtx);
368 mutex_init(&rdev->devlist_mtx); 368 mutex_init(&rdev->devlist_mtx);
369 mutex_init(&rdev->sched_scan_mtx);
369 INIT_LIST_HEAD(&rdev->netdev_list); 370 INIT_LIST_HEAD(&rdev->netdev_list);
370 spin_lock_init(&rdev->bss_lock); 371 spin_lock_init(&rdev->bss_lock);
371 INIT_LIST_HEAD(&rdev->bss_list); 372 INIT_LIST_HEAD(&rdev->bss_list);
@@ -701,6 +702,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
701 rfkill_destroy(rdev->rfkill); 702 rfkill_destroy(rdev->rfkill);
702 mutex_destroy(&rdev->mtx); 703 mutex_destroy(&rdev->mtx);
703 mutex_destroy(&rdev->devlist_mtx); 704 mutex_destroy(&rdev->devlist_mtx);
705 mutex_destroy(&rdev->sched_scan_mtx);
704 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) 706 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
705 cfg80211_put_bss(&scan->pub); 707 cfg80211_put_bss(&scan->pub);
706 cfg80211_rdev_free_wowlan(rdev); 708 cfg80211_rdev_free_wowlan(rdev);
@@ -737,12 +739,16 @@ static void wdev_cleanup_work(struct work_struct *work)
737 ___cfg80211_scan_done(rdev, true); 739 ___cfg80211_scan_done(rdev, true);
738 } 740 }
739 741
742 cfg80211_unlock_rdev(rdev);
743
744 mutex_lock(&rdev->sched_scan_mtx);
745
740 if (WARN_ON(rdev->sched_scan_req && 746 if (WARN_ON(rdev->sched_scan_req &&
741 rdev->sched_scan_req->dev == wdev->netdev)) { 747 rdev->sched_scan_req->dev == wdev->netdev)) {
742 __cfg80211_stop_sched_scan(rdev, false); 748 __cfg80211_stop_sched_scan(rdev, false);
743 } 749 }
744 750
745 cfg80211_unlock_rdev(rdev); 751 mutex_unlock(&rdev->sched_scan_mtx);
746 752
747 mutex_lock(&rdev->devlist_mtx); 753 mutex_lock(&rdev->devlist_mtx);
748 rdev->opencount--; 754 rdev->opencount--;
@@ -830,9 +836,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
830 break; 836 break;
831 case NL80211_IFTYPE_P2P_CLIENT: 837 case NL80211_IFTYPE_P2P_CLIENT:
832 case NL80211_IFTYPE_STATION: 838 case NL80211_IFTYPE_STATION:
833 cfg80211_lock_rdev(rdev); 839 mutex_lock(&rdev->sched_scan_mtx);
834 __cfg80211_stop_sched_scan(rdev, false); 840 __cfg80211_stop_sched_scan(rdev, false);
835 cfg80211_unlock_rdev(rdev); 841 mutex_unlock(&rdev->sched_scan_mtx);
836 842
837 wdev_lock(wdev); 843 wdev_lock(wdev);
838#ifdef CONFIG_CFG80211_WEXT 844#ifdef CONFIG_CFG80211_WEXT