diff options
author | Luis R. Rodriguez <lrodriguez@atheros.com> | 2009-07-30 20:38:08 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-04 16:44:18 -0400 |
commit | abc7381bcca6ce9dc101f112a13e14957bfbda7e (patch) | |
tree | b56d22241fbba51614e773617ef65f2b20661795 /net/wireless | |
parent | 4b44c8bc4d077f1a7a9e5e946a1400c3cbcadee7 (diff) |
cfg80211: decouple regulatory variables from cfg80211_mutex
We change regulatory code to be protected by its own regulatory
mutex and alleviate cfg80211_mutex to only be used to protect
cfg80211_rdev_list, the registered device list.
By doing this we will be able to work on regulatory core components
without having to have hog up the cfg80211_mutex. An example here is
we no longer need to use the cfg80211_mutex during driver specific
wiphy_apply_custom_regulatory(). We also no longer need it for the
the country IE regulatory hint; by doing so we end up curing this
new lockdep warning:
=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.31-rc4-wl #12
-------------------------------------------------------
phy1/1709 is trying to acquire lock:
(cfg80211_mutex){+.+.+.}, at: [<ffffffffa00af852>] regulatory_hint_11d+0x32/0x3f0 [cfg80211]
but task is already holding lock:
(&ifmgd->mtx){+.+.+.}, at: [<ffffffffa0144228>] ieee80211_sta_work+0x108/0x10f0 [mac80211]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #3 (&ifmgd->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa0141bb8>] ieee80211_mgd_auth+0x108/0x1f0 [mac80211]
[<ffffffffa0148563>] ieee80211_auth+0x13/0x20 [mac80211]
[<ffffffffa00bc3a1>] __cfg80211_mlme_auth+0x1b1/0x2a0 [cfg80211]
[<ffffffffa00bc516>] cfg80211_mlme_auth+0x86/0xc0 [cfg80211]
[<ffffffffa00b368d>] nl80211_authenticate+0x21d/0x230 [cfg80211]
[<ffffffff81416ba6>] genl_rcv_msg+0x1b6/0x1f0
[<ffffffff81415c39>] netlink_rcv_skb+0x89/0xb0
[<ffffffff814169d9>] genl_rcv+0x29/0x40
[<ffffffff8141591d>] netlink_unicast+0x29d/0x2b0
[<ffffffff81416514>] netlink_sendmsg+0x214/0x300
[<ffffffff813e4407>] sock_sendmsg+0x107/0x130
[<ffffffff813e45b9>] sys_sendmsg+0x189/0x320
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
-> #2 (&wdev->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa00ab304>] cfg80211_netdev_notifier_call+0x1a4/0x390 [cfg80211]
[<ffffffff814f3dff>] notifier_call_chain+0x3f/0x80
[<ffffffff81075a91>] raw_notifier_call_chain+0x11/0x20
[<ffffffff813f665a>] dev_open+0x10a/0x120
[<ffffffff813f59bd>] dev_change_flags+0x9d/0x1e0
[<ffffffff8144eb6e>] devinet_ioctl+0x6fe/0x760
[<ffffffff81450204>] inet_ioctl+0x94/0xc0
[<ffffffff813e25fa>] sock_ioctl+0x6a/0x290
[<ffffffff8111e911>] vfs_ioctl+0x31/0xa0
[<ffffffff8111ea9a>] do_vfs_ioctl+0x8a/0x5c0
[<ffffffff8111f069>] sys_ioctl+0x99/0xa0
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
-> #1 (&rdev->mtx){+.+.+.}:
[<ffffffff810857b6>] __lock_acquire+0xd76/0x12b0
[<ffffffff81085dd3>] lock_acquire+0xe3/0x120
[<ffffffff814eeae4>] mutex_lock_nested+0x44/0x350
[<ffffffffa00ac4d0>] cfg80211_get_dev_from_ifindex+0x60/0x90 [cfg80211]
[<ffffffffa00b21ff>] get_rdev_dev_by_info_ifindex+0x6f/0xa0 [cfg80211]
[<ffffffffa00b51eb>] nl80211_set_interface+0x3b/0x260 [cfg80211]
[<ffffffff81416ba6>] genl_rcv_msg+0x1b6/0x1f0
[<ffffffff81415c39>] netlink_rcv_skb+0x89/0xb0
[<ffffffff814169d9>] genl_rcv+0x29/0x40
[<ffffffff8141591d>] netlink_unicast+0x29d/0x2b0
[<ffffffff81416514>] netlink_sendmsg+0x214/0x300
[<ffffffff813e4407>] sock_sendmsg+0x107/0x130
[<ffffffff813e45b9>] sys_sendmsg+0x189/0x320
[<ffffffff81011f82>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
other info that might help us debug this:
3 locks held by phy1/1709:
#0: ((wiphy_name(local->hw.wiphy))){+.+.+.}, at: [<ffffffff8106b45d>] worker_thread+0x19d/0x340
#1: (&ifmgd->work){+.+.+.}, at: [<ffffffff8106b45d>] worker_thread+0x19d/0x340
#2: (&ifmgd->mtx){+.+.+.}, at: [<ffffffffa0144228>] ieee80211_sta_work+0x108/0x10f0 [mac80211]
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 4 | ||||
-rw-r--r-- | net/wireless/reg.c | 46 |
2 files changed, 38 insertions, 12 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 1493285b6a4d..cd7dff9c75f4 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -34,9 +34,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain, | 37 | * This is used to protect the cfg80211_rdev_list |
38 | * country_ie_regdomain, the reg_beacon_list and the the last regulatory | ||
39 | * request receipt (last_request). | ||
40 | */ | 38 | */ |
41 | DEFINE_MUTEX(cfg80211_mutex); | 39 | DEFINE_MUTEX(cfg80211_mutex); |
42 | 40 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f386981734a0..6ab56f098de1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
62 | */ | 62 | */ |
63 | static const struct ieee80211_regdomain *country_ie_regdomain; | 63 | static const struct ieee80211_regdomain *country_ie_regdomain; |
64 | 64 | ||
65 | /* | ||
66 | * Protects static reg.c components: | ||
67 | * - cfg80211_world_regdom | ||
68 | * - cfg80211_regdom | ||
69 | * - country_ie_regdomain | ||
70 | * - last_request | ||
71 | */ | ||
72 | DEFINE_MUTEX(reg_mutex); | ||
73 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | ||
74 | |||
65 | /* Used to queue up regulatory hints */ | 75 | /* Used to queue up regulatory hints */ |
66 | static LIST_HEAD(reg_requests_list); | 76 | static LIST_HEAD(reg_requests_list); |
67 | static spinlock_t reg_requests_lock; | 77 | static spinlock_t reg_requests_lock; |
@@ -1293,7 +1303,7 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1293 | struct ieee80211_supported_band *sband; | 1303 | struct ieee80211_supported_band *sband; |
1294 | struct ieee80211_channel *chan; | 1304 | struct ieee80211_channel *chan; |
1295 | 1305 | ||
1296 | assert_cfg80211_lock(); | 1306 | assert_reg_lock(); |
1297 | 1307 | ||
1298 | sband = wiphy->bands[band]; | 1308 | sband = wiphy->bands[band]; |
1299 | BUG_ON(chan_idx >= sband->n_channels); | 1309 | BUG_ON(chan_idx >= sband->n_channels); |
@@ -1342,14 +1352,14 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1342 | enum ieee80211_band band; | 1352 | enum ieee80211_band band; |
1343 | unsigned int bands_set = 0; | 1353 | unsigned int bands_set = 0; |
1344 | 1354 | ||
1345 | mutex_lock(&cfg80211_mutex); | 1355 | mutex_lock(®_mutex); |
1346 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1356 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1347 | if (!wiphy->bands[band]) | 1357 | if (!wiphy->bands[band]) |
1348 | continue; | 1358 | continue; |
1349 | handle_band_custom(wiphy, band, regd); | 1359 | handle_band_custom(wiphy, band, regd); |
1350 | bands_set++; | 1360 | bands_set++; |
1351 | } | 1361 | } |
1352 | mutex_unlock(&cfg80211_mutex); | 1362 | mutex_unlock(®_mutex); |
1353 | 1363 | ||
1354 | /* | 1364 | /* |
1355 | * no point in calling this if it won't have any effect | 1365 | * no point in calling this if it won't have any effect |
@@ -1495,7 +1505,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1495 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | 1505 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had |
1496 | * already been set or other standard error codes. | 1506 | * already been set or other standard error codes. |
1497 | * | 1507 | * |
1498 | * Caller must hold &cfg80211_mutex | 1508 | * Caller must hold &cfg80211_mutex and ®_mutex |
1499 | */ | 1509 | */ |
1500 | static int __regulatory_hint(struct wiphy *wiphy, | 1510 | static int __regulatory_hint(struct wiphy *wiphy, |
1501 | struct regulatory_request *pending_request) | 1511 | struct regulatory_request *pending_request) |
@@ -1570,6 +1580,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1570 | BUG_ON(!reg_request->alpha2); | 1580 | BUG_ON(!reg_request->alpha2); |
1571 | 1581 | ||
1572 | mutex_lock(&cfg80211_mutex); | 1582 | mutex_lock(&cfg80211_mutex); |
1583 | mutex_lock(®_mutex); | ||
1573 | 1584 | ||
1574 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | 1585 | if (wiphy_idx_valid(reg_request->wiphy_idx)) |
1575 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1586 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
@@ -1585,6 +1596,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1585 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) | 1596 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) |
1586 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1597 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1587 | out: | 1598 | out: |
1599 | mutex_unlock(®_mutex); | ||
1588 | mutex_unlock(&cfg80211_mutex); | 1600 | mutex_unlock(&cfg80211_mutex); |
1589 | } | 1601 | } |
1590 | 1602 | ||
@@ -1613,6 +1625,10 @@ static void reg_process_pending_beacon_hints(void) | |||
1613 | struct cfg80211_registered_device *rdev; | 1625 | struct cfg80211_registered_device *rdev; |
1614 | struct reg_beacon *pending_beacon, *tmp; | 1626 | struct reg_beacon *pending_beacon, *tmp; |
1615 | 1627 | ||
1628 | /* | ||
1629 | * No need to hold the reg_mutex here as we just touch wiphys | ||
1630 | * and do not read or access regulatory variables. | ||
1631 | */ | ||
1616 | mutex_lock(&cfg80211_mutex); | 1632 | mutex_lock(&cfg80211_mutex); |
1617 | 1633 | ||
1618 | /* This goes through the _pending_ beacon list */ | 1634 | /* This goes through the _pending_ beacon list */ |
@@ -1734,12 +1750,13 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
1734 | } | 1750 | } |
1735 | EXPORT_SYMBOL(regulatory_hint); | 1751 | EXPORT_SYMBOL(regulatory_hint); |
1736 | 1752 | ||
1753 | /* Caller must hold reg_mutex */ | ||
1737 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1754 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
1738 | u32 country_ie_checksum) | 1755 | u32 country_ie_checksum) |
1739 | { | 1756 | { |
1740 | struct wiphy *request_wiphy; | 1757 | struct wiphy *request_wiphy; |
1741 | 1758 | ||
1742 | assert_cfg80211_lock(); | 1759 | assert_reg_lock(); |
1743 | 1760 | ||
1744 | if (unlikely(last_request->initiator != | 1761 | if (unlikely(last_request->initiator != |
1745 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | 1762 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) |
@@ -1776,7 +1793,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1776 | enum environment_cap env = ENVIRON_ANY; | 1793 | enum environment_cap env = ENVIRON_ANY; |
1777 | struct regulatory_request *request; | 1794 | struct regulatory_request *request; |
1778 | 1795 | ||
1779 | mutex_lock(&cfg80211_mutex); | 1796 | mutex_lock(®_mutex); |
1780 | 1797 | ||
1781 | if (unlikely(!last_request)) | 1798 | if (unlikely(!last_request)) |
1782 | goto out; | 1799 | goto out; |
@@ -1850,7 +1867,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1850 | request->country_ie_checksum = checksum; | 1867 | request->country_ie_checksum = checksum; |
1851 | request->country_ie_env = env; | 1868 | request->country_ie_env = env; |
1852 | 1869 | ||
1853 | mutex_unlock(&cfg80211_mutex); | 1870 | mutex_unlock(®_mutex); |
1854 | 1871 | ||
1855 | queue_regulatory_request(request); | 1872 | queue_regulatory_request(request); |
1856 | 1873 | ||
@@ -1859,7 +1876,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1859 | free_rd_out: | 1876 | free_rd_out: |
1860 | kfree(rd); | 1877 | kfree(rd); |
1861 | out: | 1878 | out: |
1862 | mutex_unlock(&cfg80211_mutex); | 1879 | mutex_unlock(®_mutex); |
1863 | } | 1880 | } |
1864 | EXPORT_SYMBOL(regulatory_hint_11d); | 1881 | EXPORT_SYMBOL(regulatory_hint_11d); |
1865 | 1882 | ||
@@ -2192,10 +2209,13 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2192 | 2209 | ||
2193 | assert_cfg80211_lock(); | 2210 | assert_cfg80211_lock(); |
2194 | 2211 | ||
2212 | mutex_lock(®_mutex); | ||
2213 | |||
2195 | /* Note that this doesn't update the wiphys, this is done below */ | 2214 | /* Note that this doesn't update the wiphys, this is done below */ |
2196 | r = __set_regdom(rd); | 2215 | r = __set_regdom(rd); |
2197 | if (r) { | 2216 | if (r) { |
2198 | kfree(rd); | 2217 | kfree(rd); |
2218 | mutex_unlock(®_mutex); | ||
2199 | return r; | 2219 | return r; |
2200 | } | 2220 | } |
2201 | 2221 | ||
@@ -2210,6 +2230,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2210 | 2230 | ||
2211 | nl80211_send_reg_change_event(last_request); | 2231 | nl80211_send_reg_change_event(last_request); |
2212 | 2232 | ||
2233 | mutex_unlock(®_mutex); | ||
2234 | |||
2213 | return r; | 2235 | return r; |
2214 | } | 2236 | } |
2215 | 2237 | ||
@@ -2220,16 +2242,20 @@ void reg_device_remove(struct wiphy *wiphy) | |||
2220 | 2242 | ||
2221 | assert_cfg80211_lock(); | 2243 | assert_cfg80211_lock(); |
2222 | 2244 | ||
2245 | mutex_lock(®_mutex); | ||
2246 | |||
2223 | kfree(wiphy->regd); | 2247 | kfree(wiphy->regd); |
2224 | 2248 | ||
2225 | if (last_request) | 2249 | if (last_request) |
2226 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2250 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
2227 | 2251 | ||
2228 | if (!request_wiphy || request_wiphy != wiphy) | 2252 | if (!request_wiphy || request_wiphy != wiphy) |
2229 | return; | 2253 | goto out; |
2230 | 2254 | ||
2231 | last_request->wiphy_idx = WIPHY_IDX_STALE; | 2255 | last_request->wiphy_idx = WIPHY_IDX_STALE; |
2232 | last_request->country_ie_env = ENVIRON_ANY; | 2256 | last_request->country_ie_env = ENVIRON_ANY; |
2257 | out: | ||
2258 | mutex_unlock(®_mutex); | ||
2233 | } | 2259 | } |
2234 | 2260 | ||
2235 | int regulatory_init(void) | 2261 | int regulatory_init(void) |
@@ -2290,6 +2316,7 @@ void regulatory_exit(void) | |||
2290 | cancel_work_sync(®_work); | 2316 | cancel_work_sync(®_work); |
2291 | 2317 | ||
2292 | mutex_lock(&cfg80211_mutex); | 2318 | mutex_lock(&cfg80211_mutex); |
2319 | mutex_lock(®_mutex); | ||
2293 | 2320 | ||
2294 | reset_regdomains(); | 2321 | reset_regdomains(); |
2295 | 2322 | ||
@@ -2328,5 +2355,6 @@ void regulatory_exit(void) | |||
2328 | } | 2355 | } |
2329 | spin_unlock(®_requests_lock); | 2356 | spin_unlock(®_requests_lock); |
2330 | 2357 | ||
2358 | mutex_unlock(®_mutex); | ||
2331 | mutex_unlock(&cfg80211_mutex); | 2359 | mutex_unlock(&cfg80211_mutex); |
2332 | } | 2360 | } |