aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.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/nl80211.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/nl80211.c')
-rw-r--r--net/wireless/nl80211.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f07602d7bf6..cea338150d0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3461,9 +3461,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3461 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3461 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3462 return -EINVAL; 3462 return -EINVAL;
3463 3463
3464 if (rdev->sched_scan_req)
3465 return -EINPROGRESS;
3466
3467 if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) 3464 if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
3468 return -EINVAL; 3465 return -EINVAL;
3469 3466
@@ -3502,12 +3499,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3502 if (ie_len > wiphy->max_scan_ie_len) 3499 if (ie_len > wiphy->max_scan_ie_len)
3503 return -EINVAL; 3500 return -EINVAL;
3504 3501
3502 mutex_lock(&rdev->sched_scan_mtx);
3503
3504 if (rdev->sched_scan_req) {
3505 err = -EINPROGRESS;
3506 goto out;
3507 }
3508
3505 request = kzalloc(sizeof(*request) 3509 request = kzalloc(sizeof(*request)
3506 + sizeof(*request->ssids) * n_ssids 3510 + sizeof(*request->ssids) * n_ssids
3507 + sizeof(*request->channels) * n_channels 3511 + sizeof(*request->channels) * n_channels
3508 + ie_len, GFP_KERNEL); 3512 + ie_len, GFP_KERNEL);
3509 if (!request) 3513 if (!request) {
3510 return -ENOMEM; 3514 err = -ENOMEM;
3515 goto out;
3516 }
3511 3517
3512 if (n_ssids) 3518 if (n_ssids)
3513 request->ssids = (void *)&request->channels[n_channels]; 3519 request->ssids = (void *)&request->channels[n_channels];
@@ -3605,6 +3611,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
3605out_free: 3611out_free:
3606 kfree(request); 3612 kfree(request);
3607out: 3613out:
3614 mutex_unlock(&rdev->sched_scan_mtx);
3608 return err; 3615 return err;
3609} 3616}
3610 3617
@@ -3612,12 +3619,17 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb,
3612 struct genl_info *info) 3619 struct genl_info *info)
3613{ 3620{
3614 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 3621 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3622 int err;
3615 3623
3616 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 3624 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
3617 !rdev->ops->sched_scan_stop) 3625 !rdev->ops->sched_scan_stop)
3618 return -EOPNOTSUPP; 3626 return -EOPNOTSUPP;
3619 3627
3620 return __cfg80211_stop_sched_scan(rdev, false); 3628 mutex_lock(&rdev->sched_scan_mtx);
3629 err = __cfg80211_stop_sched_scan(rdev, false);
3630 mutex_unlock(&rdev->sched_scan_mtx);
3631
3632 return err;
3621} 3633}
3622 3634
3623static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, 3635static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,