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>
This commit is contained in:
committed by
John W. Linville
parent
37000b305b
commit
c10841ca72
@@ -100,14 +100,14 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
|
||||
rdev = container_of(wk, struct cfg80211_registered_device,
|
||||
sched_scan_results_wk);
|
||||
|
||||
cfg80211_lock_rdev(rdev);
|
||||
mutex_lock(&rdev->sched_scan_mtx);
|
||||
|
||||
/* we don't have sched_scan_req anymore if the scan is stopping */
|
||||
if (rdev->sched_scan_req)
|
||||
nl80211_send_sched_scan_results(rdev,
|
||||
rdev->sched_scan_req->dev);
|
||||
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
mutex_unlock(&rdev->sched_scan_mtx);
|
||||
}
|
||||
|
||||
void cfg80211_sched_scan_results(struct wiphy *wiphy)
|
||||
@@ -123,9 +123,9 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
cfg80211_lock_rdev(rdev);
|
||||
mutex_lock(&rdev->sched_scan_mtx);
|
||||
__cfg80211_stop_sched_scan(rdev, true);
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
mutex_unlock(&rdev->sched_scan_mtx);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
|
||||
|
||||
@@ -135,7 +135,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
int err;
|
||||
struct net_device *dev;
|
||||
|
||||
ASSERT_RDEV_LOCK(rdev);
|
||||
lockdep_assert_held(&rdev->sched_scan_mtx);
|
||||
|
||||
if (!rdev->sched_scan_req)
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user