diff options
-rw-r--r-- | package/mac80211/Makefile | 2 | ||||
-rw-r--r-- | package/mac80211/patches/100-cfg80211-fix-deadlock.patch | 108 |
2 files changed, 109 insertions, 1 deletions
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index 07811bd2b0..f9c1f7fce3 100644 --- a/package/mac80211/Makefile +++ b/package/mac80211/Makefile @@ -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 index 0000000000..6e2a2b1d1f --- /dev/null +++ b/package/mac80211/patches/100-cfg80211-fix-deadlock.patch @@ -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))) |