aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-08-26 07:30:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-27 13:27:06 -0400
commit8789d459bc5e837bf37d261453df96ef54018d7b (patch)
tree5dbcabe5807de84f9119ab3654b998fd65ac0a40 /net/mac80211
parent5f33c92d188add2a22ec524c03e0ab097e303d52 (diff)
mac80211: allow scan to complete from any context
The ieee80211_scan_completed() function was a frequent source of potential deadlocks, since it is called by drivers but may call back into drivers, so drivers had to make sure to call it without any locks held, which frequently lead to more complex code in drivers. Avoid that problem by allowing the function to be called in any context, and queueing the actual work it does. Also update the documentation for it to indicate this. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/scan.c34
2 files changed, 32 insertions, 8 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9e225f01497b..31713320258c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -596,11 +596,17 @@ enum queue_stop_reason {
596 * determine if we are on the operating channel or not 596 * determine if we are on the operating channel or not
597 * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, 597 * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
598 * gets only set in conjunction with SCAN_SW_SCANNING 598 * gets only set in conjunction with SCAN_SW_SCANNING
599 * @SCAN_COMPLETED: Set for our scan work function when the driver reported
600 * that the scan completed.
601 * @SCAN_ABORTED: Set for our scan work function when the driver reported
602 * a scan complete for an aborted scan.
599 */ 603 */
600enum { 604enum {
601 SCAN_SW_SCANNING, 605 SCAN_SW_SCANNING,
602 SCAN_HW_SCANNING, 606 SCAN_HW_SCANNING,
603 SCAN_OFF_CHANNEL, 607 SCAN_OFF_CHANNEL,
608 SCAN_COMPLETED,
609 SCAN_ABORTED,
604}; 610};
605 611
606/** 612/**
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 31f233f7f51a..d60389ba9b95 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -248,13 +248,11 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
248 return true; 248 return true;
249} 249}
250 250
251void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 251static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
252{ 252{
253 struct ieee80211_local *local = hw_to_local(hw); 253 struct ieee80211_local *local = hw_to_local(hw);
254 bool was_hw_scan; 254 bool was_hw_scan;
255 255
256 trace_api_scan_completed(local, aborted);
257
258 mutex_lock(&local->mtx); 256 mutex_lock(&local->mtx);
259 257
260 /* 258 /*
@@ -312,6 +310,18 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
312 ieee80211_mesh_notify_scan_completed(local); 310 ieee80211_mesh_notify_scan_completed(local);
313 ieee80211_queue_work(&local->hw, &local->work_work); 311 ieee80211_queue_work(&local->hw, &local->work_work);
314} 312}
313
314void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
315{
316 struct ieee80211_local *local = hw_to_local(hw);
317
318 trace_api_scan_completed(local, aborted);
319
320 set_bit(SCAN_COMPLETED, &local->scanning);
321 if (aborted)
322 set_bit(SCAN_ABORTED, &local->scanning);
323 ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
324}
315EXPORT_SYMBOL(ieee80211_scan_completed); 325EXPORT_SYMBOL(ieee80211_scan_completed);
316 326
317static int ieee80211_start_sw_scan(struct ieee80211_local *local) 327static int ieee80211_start_sw_scan(struct ieee80211_local *local)
@@ -449,7 +459,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
449 459
450 /* if no more bands/channels left, complete scan and advance to the idle state */ 460 /* if no more bands/channels left, complete scan and advance to the idle state */
451 if (local->scan_channel_idx >= local->scan_req->n_channels) { 461 if (local->scan_channel_idx >= local->scan_req->n_channels) {
452 ieee80211_scan_completed(&local->hw, false); 462 __ieee80211_scan_completed(&local->hw, false);
453 return 1; 463 return 1;
454 } 464 }
455 465
@@ -641,6 +651,14 @@ void ieee80211_scan_work(struct work_struct *work)
641 struct ieee80211_sub_if_data *sdata = local->scan_sdata; 651 struct ieee80211_sub_if_data *sdata = local->scan_sdata;
642 unsigned long next_delay = 0; 652 unsigned long next_delay = 0;
643 653
654 if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
655 bool aborted;
656
657 aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
658 __ieee80211_scan_completed(&local->hw, aborted);
659 return;
660 }
661
644 mutex_lock(&local->mtx); 662 mutex_lock(&local->mtx);
645 if (!sdata || !local->scan_req) { 663 if (!sdata || !local->scan_req) {
646 mutex_unlock(&local->mtx); 664 mutex_unlock(&local->mtx);
@@ -651,7 +669,7 @@ void ieee80211_scan_work(struct work_struct *work)
651 int rc = drv_hw_scan(local, sdata, local->hw_scan_req); 669 int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
652 mutex_unlock(&local->mtx); 670 mutex_unlock(&local->mtx);
653 if (rc) 671 if (rc)
654 ieee80211_scan_completed(&local->hw, true); 672 __ieee80211_scan_completed(&local->hw, true);
655 return; 673 return;
656 } 674 }
657 675
@@ -666,7 +684,7 @@ void ieee80211_scan_work(struct work_struct *work)
666 mutex_unlock(&local->mtx); 684 mutex_unlock(&local->mtx);
667 685
668 if (rc) 686 if (rc)
669 ieee80211_scan_completed(&local->hw, true); 687 __ieee80211_scan_completed(&local->hw, true);
670 return; 688 return;
671 } 689 }
672 690
@@ -676,7 +694,7 @@ void ieee80211_scan_work(struct work_struct *work)
676 * Avoid re-scheduling when the sdata is going away. 694 * Avoid re-scheduling when the sdata is going away.
677 */ 695 */
678 if (!ieee80211_sdata_running(sdata)) { 696 if (!ieee80211_sdata_running(sdata)) {
679 ieee80211_scan_completed(&local->hw, true); 697 __ieee80211_scan_completed(&local->hw, true);
680 return; 698 return;
681 } 699 }
682 700
@@ -783,5 +801,5 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
783 mutex_unlock(&local->mtx); 801 mutex_unlock(&local->mtx);
784 802
785 if (abortscan) 803 if (abortscan)
786 ieee80211_scan_completed(&local->hw, true); 804 __ieee80211_scan_completed(&local->hw, true);
787} 805}