fix multiple ipkg builds of the same arch but with different targets in the same...
[openwrt/openwrt.git] / package / mac80211 / patches / 100-cfg80211-fix-deadlock.patch
1 Subject: [PATCH] cfg80211: fix deadlock
2 From: Johannes Berg <johannes@sipsolutions.net>
3 To: John Linville <linville@tuxdriver.com>
4 Cc: linux-wireless <linux-wireless@vger.kernel.org>,
5 Christian Lamparter <chunkeey@web.de>
6 Content-Type: text/plain
7 Date: Sun, 16 Aug 2009 13:32:38 +0200
8 Message-Id: <1250422358.17522.0.camel@johannes.local>
9 Mime-Version: 1.0
10 X-Mailer: Evolution 2.27.90
11 Content-Transfer-Encoding: 7bit
12 Sender: linux-wireless-owner@vger.kernel.org
13 Precedence: bulk
14 List-ID: <linux-wireless.vger.kernel.org>
15 X-Mailing-List: linux-wireless@vger.kernel.org
16
17 When removing an interface with nl80211, cfg80211 will
18 deadlock in the netdev notifier because we're already
19 holding rdev->mtx and try to acquire it again to verify
20 the scan has been done.
21
22 This bug was introduced by my patch
23 "cfg80211: check for and abort dangling scan requests".
24
25 To fix this, move the dangling scan request check into
26 wiphy_unregister(). This will not be able to catch all
27 cases right away, but if the scan problem happens with
28 a manual ifdown or so it will be possible to remedy it
29 by removing the module/device.
30
31 Additionally, add comments about the deadlock scenario.
32
33 Reported-by: Christian Lamparter <chunkeey@web.de>
34 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
35 ---
36 net/wireless/core.c | 32 +++++++++++++++++++-------------
37 1 file changed, 19 insertions(+), 13 deletions(-)
38
39 --- a/net/wireless/core.c
40 +++ b/net/wireless/core.c
41 @@ -586,9 +586,15 @@ void wiphy_unregister(struct wiphy *wiph
42 * get to lock contention here if userspace issues a command
43 * that identified the hardware by wiphy index.
44 */
45 - mutex_lock(&rdev->mtx);
46 - /* unlock again before freeing */
47 - mutex_unlock(&rdev->mtx);
48 + cfg80211_lock_rdev(rdev);
49 +
50 + if (WARN_ON(rdev->scan_req)) {
51 + rdev->scan_req->aborted = true;
52 + ___cfg80211_scan_done(rdev);
53 + }
54 +
55 + cfg80211_unlock_rdev(rdev);
56 + flush_work(&rdev->scan_done_wk);
57
58 cfg80211_debugfs_rdev_del(rdev);
59
60 @@ -603,9 +609,7 @@ void wiphy_unregister(struct wiphy *wiph
61
62 mutex_unlock(&cfg80211_mutex);
63
64 - flush_work(&rdev->scan_done_wk);
65 cancel_work_sync(&rdev->conn_work);
66 - kfree(rdev->scan_req);
67 flush_work(&rdev->event_work);
68 }
69 EXPORT_SYMBOL(wiphy_unregister);
70 @@ -653,6 +657,11 @@ static int cfg80211_netdev_notifier_call
71
72 switch (state) {
73 case NETDEV_REGISTER:
74 + /*
75 + * NB: cannot take rdev->mtx here because this may be
76 + * called within code protected by it when interfaces
77 + * are added with nl80211.
78 + */
79 mutex_init(&wdev->mtx);
80 INIT_LIST_HEAD(&wdev->event_list);
81 spin_lock_init(&wdev->event_lock);
82 @@ -730,13 +739,11 @@ static int cfg80211_netdev_notifier_call
83 #endif
84 break;
85 case NETDEV_UNREGISTER:
86 - cfg80211_lock_rdev(rdev);
87 -
88 - if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) {
89 - rdev->scan_req->aborted = true;
90 - ___cfg80211_scan_done(rdev);
91 - }
92 -
93 + /*
94 + * NB: cannot take rdev->mtx here because this may be
95 + * called within code protected by it when interfaces
96 + * are removed with nl80211.
97 + */
98 mutex_lock(&rdev->devlist_mtx);
99 /*
100 * It is possible to get NETDEV_UNREGISTER
101 @@ -755,7 +762,6 @@ static int cfg80211_netdev_notifier_call
102 #endif
103 }
104 mutex_unlock(&rdev->devlist_mtx);
105 - cfg80211_unlock_rdev(rdev);
106 break;
107 case NETDEV_PRE_UP:
108 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))