Jesse Keating 2f82dda
From reinette.chatre@intel.com Thu May 13 17:49:59 2010
Jesse Keating 2f82dda
Return-path: <reinette.chatre@intel.com>
Jesse Keating 2f82dda
Envelope-to: linville@tuxdriver.com
Jesse Keating 2f82dda
Delivery-date: Thu, 13 May 2010 17:49:59 -0400
Jesse Keating 2f82dda
Received: from mga09.intel.com ([134.134.136.24])
Jesse Keating 2f82dda
	by smtp.tuxdriver.com with esmtp (Exim 4.63)
Jesse Keating 2f82dda
	(envelope-from <reinette.chatre@intel.com>)
Jesse Keating 2f82dda
	id 1OCgI1-0007H3-Eg
Jesse Keating 2f82dda
	for linville@tuxdriver.com; Thu, 13 May 2010 17:49:59 -0400
Jesse Keating 2f82dda
Received: from orsmga002.jf.intel.com ([10.7.209.21])
Jesse Keating 2f82dda
  by orsmga102.jf.intel.com with ESMTP; 13 May 2010 14:48:04 -0700
Jesse Keating 2f82dda
X-ExtLoop1: 1
Jesse Keating 2f82dda
X-IronPort-AV: E=Sophos;i="4.53,224,1272870000"; 
Jesse Keating 2f82dda
   d="scan'208";a="517743256"
Jesse Keating 2f82dda
Received: from rchatre-desk.amr.corp.intel.com.jf.intel.com (HELO localhost.localdomain) ([134.134.15.94])
Jesse Keating 2f82dda
  by orsmga002.jf.intel.com with ESMTP; 13 May 2010 14:49:12 -0700
Jesse Keating 2f82dda
From: Reinette Chatre <reinette.chatre@intel.com>
Jesse Keating 2f82dda
To: linville@tuxdriver.com
Jesse Keating 2f82dda
Cc: linux-wireless@vger.kernel.org, ipw3945-devel@lists.sourceforge.net, Reinette Chatre <reinette.chatre@intel.com>
Jesse Keating 2f82dda
Subject: [PATCH 1/2] iwlwifi: fix internal scan race
Jesse Keating 2f82dda
Date: Thu, 13 May 2010 14:49:44 -0700
Jesse Keating 2f82dda
Message-Id: <1273787385-9248-2-git-send-email-reinette.chatre@intel.com>
Jesse Keating 2f82dda
X-Mailer: git-send-email 1.6.3.3
Jesse Keating 2f82dda
In-Reply-To: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com>
Jesse Keating 2f82dda
References: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com>
Jesse Keating 2f82dda
X-Spam-Score: -4.2 (----)
Jesse Keating 2f82dda
X-Spam-Status: No
Jesse Keating 2f82dda
Status: RO
Jesse Keating 2f82dda
Content-Length: 3370
Jesse Keating 2f82dda
Lines: 91
Jesse Keating 2f82dda
Jesse Keating 2f82dda
From: Reinette Chatre <reinette.chatre@intel.com>
Jesse Keating 2f82dda
Jesse Keating 2f82dda
It is possible for internal scan to race against itself if the device is
Jesse Keating 2f82dda
not returning the scan results from first requests. What happens in this
Jesse Keating 2f82dda
case is the cleanup done during the abort of the first internal scan also
Jesse Keating 2f82dda
cleans up part of the new scan, causing it to access memory it shouldn't.
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Here are details:
Jesse Keating 2f82dda
* First internal scan is triggered and scan command sent to device.
Jesse Keating 2f82dda
* After seven seconds there is no scan results so the watchdog timer
Jesse Keating 2f82dda
  triggers a scan abort.
Jesse Keating 2f82dda
* The scan abort succeeds and a SCAN_COMPLETE_NOTIFICATION is received for
Jesse Keating 2f82dda
 failed scan.
Jesse Keating 2f82dda
* During processing of SCAN_COMPLETE_NOTIFICATION we clear STATUS_SCANNING
Jesse Keating 2f82dda
  and queue the "scan_completed" work.
Jesse Keating 2f82dda
** At this time, since the problem that caused the internal scan in first
Jesse Keating 2f82dda
   place is still present, a new internal scan is triggered.
Jesse Keating 2f82dda
The behavior at this point is a bit different between 2.6.34 and 2.6.35
Jesse Keating 2f82dda
since 2.6.35 has a lot of this synchronized. The rest of the race
Jesse Keating 2f82dda
description will thus be generalized.
Jesse Keating 2f82dda
** As part of preparing for the scan "is_internal_short_scan" is set to
Jesse Keating 2f82dda
true.
Jesse Keating 2f82dda
* At this point the completion work for fist scan is run. As part of this
Jesse Keating 2f82dda
  there is some locking missing around the "is_internal_short_scan"
Jesse Keating 2f82dda
  variable and it is set to "false".
Jesse Keating 2f82dda
** Now the second scan runs and it considers itself a real (not internal0
Jesse Keating 2f82dda
   scan and thus causes problems with wrong memory being accessed.
Jesse Keating 2f82dda
Jesse Keating 2f82dda
The fix is twofold.
Jesse Keating 2f82dda
* Since "is_internal_short_scan" should be protected by mutex, fix this in
Jesse Keating 2f82dda
  scan completion work so that changes to it can be serialized.
Jesse Keating 2f82dda
* Do not queue a new internal scan if one is in progress.
Jesse Keating 2f82dda
Jesse Keating 2f82dda
This fixes https://bugzilla.kernel.org/show_bug.cgi?id=15824
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Jesse Keating 2f82dda
---
Jesse Keating 2f82dda
 drivers/net/wireless/iwlwifi/iwl-scan.c |   21 ++++++++++++++++++---
Jesse Keating 2f82dda
 1 files changed, 18 insertions(+), 3 deletions(-)
Jesse Keating 2f82dda
Jesse Keating 2f82dda
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
Jesse Keating 2f82dda
index 2367286..a2c4855 100644
Jesse Keating 2f82dda
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
Jesse Keating 2f82dda
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
Jesse Keating 2f82dda
@@ -560,6 +560,11 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	mutex_lock(&priv->mutex);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+	if (priv->is_internal_short_scan == true) {
Jesse Keating 2f82dda
+		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
Jesse Keating 2f82dda
+		goto unlock;
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 	if (!iwl_is_ready_rf(priv)) {
Jesse Keating 2f82dda
 		IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
Jesse Keating 2f82dda
 		goto unlock;
Jesse Keating 2f82dda
@@ -957,17 +962,27 @@ void iwl_bg_scan_completed(struct work_struct *work)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	struct iwl_priv *priv =
Jesse Keating 2f82dda
 	    container_of(work, struct iwl_priv, scan_completed);
Jesse Keating 2f82dda
+	bool internal = false;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	cancel_delayed_work(&priv->scan_check);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
-	if (!priv->is_internal_short_scan)
Jesse Keating 2f82dda
-		ieee80211_scan_completed(priv->hw, false);
Jesse Keating 2f82dda
-	else {
Jesse Keating 2f82dda
+	mutex_lock(&priv->mutex);
Jesse Keating 2f82dda
+	if (priv->is_internal_short_scan) {
Jesse Keating 2f82dda
 		priv->is_internal_short_scan = false;
Jesse Keating 2f82dda
 		IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
Jesse Keating 2f82dda
+		internal = true;
Jesse Keating 2f82dda
 	}
Jesse Keating 2f82dda
+	mutex_unlock(&priv->mutex);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	/*
Jesse Keating 2f82dda
+	 * Do not hold mutex here since this will cause mac80211 to call
Jesse Keating 2f82dda
+	 * into driver again into functions that will attempt to take
Jesse Keating 2f82dda
+	 * mutex.
Jesse Keating 2f82dda
+	 */
Jesse Keating 2f82dda
+	if (!internal)
Jesse Keating 2f82dda
+		ieee80211_scan_completed(priv->hw, false);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
Jesse Keating 2f82dda
 		return;
Jesse Keating 2f82dda
-- 
Jesse Keating 2f82dda
1.6.3.3
Jesse Keating 2f82dda
Jesse Keating 2f82dda
Jesse Keating 2f82dda