mac80211: add deadlock fix patch
authorGabor Juhos <juhosg@openwrt.org>
Sun, 16 Aug 2009 19:55:10 +0000 (19:55 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Sun, 16 Aug 2009 19:55:10 +0000 (19:55 +0000)
SVN-Revision: 17290

package/mac80211/Makefile
package/mac80211/patches/100-cfg80211-fix-deadlock.patch [new file with mode: 0644]

index 07811bd2b0e0066cc59646bb3d770b17077fba5d..f9c1f7fce3f3b0e43a822289d8fb39ff6abc0300 100644 (file)
@@ -18,7 +18,7 @@ ifneq ($(CONFIG_LINUX_2_6_21)$(CONFIG_LINUX_2_6_25),)
   PATCH_DIR:=./patches-old
 else
   PKG_VERSION:=2009-08-15
-  PKG_RELEASE:=2
+  PKG_RELEASE:=3
   PKG_SOURCE_URL:= \
        http://www.orbit-lab.org/kernel/compat-wireless-2.6/2009/08 \
        http://wireless.kernel.org/download/compat-wireless-2.6
diff --git a/package/mac80211/patches/100-cfg80211-fix-deadlock.patch b/package/mac80211/patches/100-cfg80211-fix-deadlock.patch
new file mode 100644 (file)
index 0000000..6e2a2b1
--- /dev/null
@@ -0,0 +1,108 @@
+Subject: [PATCH] cfg80211: fix deadlock
+From:  Johannes Berg <johannes@sipsolutions.net>
+To:    John Linville <linville@tuxdriver.com>
+Cc:    linux-wireless <linux-wireless@vger.kernel.org>,
+       Christian Lamparter <chunkeey@web.de>
+Content-Type: text/plain
+Date:  Sun, 16 Aug 2009 13:32:38 +0200
+Message-Id: <1250422358.17522.0.camel@johannes.local>
+Mime-Version: 1.0
+X-Mailer: Evolution 2.27.90 
+Content-Transfer-Encoding: 7bit
+Sender:        linux-wireless-owner@vger.kernel.org
+Precedence: bulk
+List-ID: <linux-wireless.vger.kernel.org>
+X-Mailing-List:        linux-wireless@vger.kernel.org
+
+When removing an interface with nl80211, cfg80211 will
+deadlock in the netdev notifier because we're already
+holding rdev->mtx and try to acquire it again to verify
+the scan has been done.
+
+This bug was introduced by my patch
+"cfg80211: check for and abort dangling scan requests".
+
+To fix this, move the dangling scan request check into
+wiphy_unregister(). This will not be able to catch all
+cases right away, but if the scan problem happens with
+a manual ifdown or so it will be possible to remedy it
+by removing the module/device.
+
+Additionally, add comments about the deadlock scenario.
+
+Reported-by: Christian Lamparter <chunkeey@web.de>
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+---
+ net/wireless/core.c |   32 +++++++++++++++++++-------------
+ 1 file changed, 19 insertions(+), 13 deletions(-)
+
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -586,9 +586,15 @@ void wiphy_unregister(struct wiphy *wiph
+        * get to lock contention here if userspace issues a command
+        * that identified the hardware by wiphy index.
+        */
+-      mutex_lock(&rdev->mtx);
+-      /* unlock again before freeing */
+-      mutex_unlock(&rdev->mtx);
++      cfg80211_lock_rdev(rdev);
++
++      if (WARN_ON(rdev->scan_req)) {
++              rdev->scan_req->aborted = true;
++              ___cfg80211_scan_done(rdev);
++      }
++
++      cfg80211_unlock_rdev(rdev);
++      flush_work(&rdev->scan_done_wk);
+       cfg80211_debugfs_rdev_del(rdev);
+@@ -603,9 +609,7 @@ void wiphy_unregister(struct wiphy *wiph
+       mutex_unlock(&cfg80211_mutex);
+-      flush_work(&rdev->scan_done_wk);
+       cancel_work_sync(&rdev->conn_work);
+-      kfree(rdev->scan_req);
+       flush_work(&rdev->event_work);
+ }
+ EXPORT_SYMBOL(wiphy_unregister);
+@@ -653,6 +657,11 @@ static int cfg80211_netdev_notifier_call
+       switch (state) {
+       case NETDEV_REGISTER:
++              /*
++               * NB: cannot take rdev->mtx here because this may be
++               * called within code protected by it when interfaces
++               * are added with nl80211.
++               */
+               mutex_init(&wdev->mtx);
+               INIT_LIST_HEAD(&wdev->event_list);
+               spin_lock_init(&wdev->event_lock);
+@@ -730,13 +739,11 @@ static int cfg80211_netdev_notifier_call
+ #endif
+               break;
+       case NETDEV_UNREGISTER:
+-              cfg80211_lock_rdev(rdev);
+-
+-              if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) {
+-                      rdev->scan_req->aborted = true;
+-                      ___cfg80211_scan_done(rdev);
+-              }
+-
++              /*
++               * NB: cannot take rdev->mtx here because this may be
++               * called within code protected by it when interfaces
++               * are removed with nl80211.
++               */
+               mutex_lock(&rdev->devlist_mtx);
+               /*
+                * It is possible to get NETDEV_UNREGISTER
+@@ -755,7 +762,6 @@ static int cfg80211_netdev_notifier_call
+ #endif
+               }
+               mutex_unlock(&rdev->devlist_mtx);
+-              cfg80211_unlock_rdev(rdev);
+               break;
+       case NETDEV_PRE_UP:
+               if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))