diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2010-10-01 08:05:27 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-05 13:35:24 -0400 |
commit | bc86863de63e6ae7ec6f9f524604631608c6cb02 (patch) | |
tree | ae4d1096ea66a03e23f515739d630dc85e61aa86 /net/mac80211 | |
parent | 8e0167a4bdce4adcea64d2197378673d332cda28 (diff) |
mac80211: perform scan cancel in hw reset work
Move ieee80211_scan_cancel() and all other related code to
ieee80211_restart_work() as ieee80211_restart_hw() is intended to be
callable from any context.
Fix a bug that RTNL lock is not taken during ieee80211_cancel_scan().
Take local->mtx before WARN(test_bit(SCAN_HW_SCANNING, &local->scanning)
to prevent the race condition with __ieee80211_start_scan() described
here: http://marc.info/?l=linux-wireless&m=128516716810537&w=2
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/main.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e24fa5be4264..494dba1b46a5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -295,7 +295,17 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
295 | struct ieee80211_local *local = | 295 | struct ieee80211_local *local = |
296 | container_of(work, struct ieee80211_local, restart_work); | 296 | container_of(work, struct ieee80211_local, restart_work); |
297 | 297 | ||
298 | /* wait for scan work complete */ | ||
299 | flush_workqueue(local->workqueue); | ||
300 | |||
301 | mutex_lock(&local->mtx); | ||
302 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | ||
303 | "%s called with hardware scan in progress\n", __func__); | ||
304 | mutex_unlock(&local->mtx); | ||
305 | |||
298 | rtnl_lock(); | 306 | rtnl_lock(); |
307 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) | ||
308 | ieee80211_scan_cancel(local); | ||
299 | ieee80211_reconfig(local); | 309 | ieee80211_reconfig(local); |
300 | rtnl_unlock(); | 310 | rtnl_unlock(); |
301 | } | 311 | } |
@@ -306,15 +316,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
306 | 316 | ||
307 | trace_api_restart_hw(local); | 317 | trace_api_restart_hw(local); |
308 | 318 | ||
309 | /* wait for scan work complete */ | ||
310 | flush_workqueue(local->workqueue); | ||
311 | |||
312 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), | ||
313 | "%s called with hardware scan in progress\n", __func__); | ||
314 | |||
315 | if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) | ||
316 | ieee80211_scan_cancel(local); | ||
317 | |||
318 | /* use this reason, ieee80211_reconfig will unblock it */ | 319 | /* use this reason, ieee80211_reconfig will unblock it */ |
319 | ieee80211_stop_queues_by_reason(hw, | 320 | ieee80211_stop_queues_by_reason(hw, |
320 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 321 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |