linux/net/wireless
Luis R. Rodriguez a85d0d7f34 cfg80211: fix possible circular lock on reg_regdb_search()
When call_crda() is called we kick off a witch hunt search
for the same regulatory domain on our internal regulatory
database and that work gets kicked off on a workqueue, this
is done while the cfg80211_mutex is held. If that workqueue
kicks off it will first lock reg_regdb_search_mutex and
later cfg80211_mutex but to ensure two CPUs will not contend
against cfg80211_mutex the right thing to do is to have the
reg_regdb_search() wait until the cfg80211_mutex is let go.

The lockdep report is pasted below.

cfg80211: Calling CRDA to update world regulatory domain

======================================================
[ INFO: possible circular locking dependency detected ]
3.3.8 #3 Tainted: G           O
-------------------------------------------------------
kworker/0:1/235 is trying to acquire lock:
 (cfg80211_mutex){+.+...}, at: [<816468a4>] set_regdom+0x78c/0x808 [cfg80211]

but task is already holding lock:
 (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211]

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #2 (reg_regdb_search_mutex){+.+...}:
       [<800a8384>] lock_acquire+0x60/0x88
       [<802950a8>] mutex_lock_nested+0x54/0x31c
       [<81645778>] is_world_regdom+0x9f8/0xc74 [cfg80211]

-> #1 (reg_mutex#2){+.+...}:
       [<800a8384>] lock_acquire+0x60/0x88
       [<802950a8>] mutex_lock_nested+0x54/0x31c
       [<8164539c>] is_world_regdom+0x61c/0xc74 [cfg80211]

-> #0 (cfg80211_mutex){+.+...}:
       [<800a77b8>] __lock_acquire+0x10d4/0x17bc
       [<800a8384>] lock_acquire+0x60/0x88
       [<802950a8>] mutex_lock_nested+0x54/0x31c
       [<816468a4>] set_regdom+0x78c/0x808 [cfg80211]

other info that might help us debug this:

Chain exists of:
  cfg80211_mutex --> reg_mutex#2 --> reg_regdb_search_mutex

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  lock(reg_regdb_search_mutex);
                               lock(reg_mutex#2);
                               lock(reg_regdb_search_mutex);
  lock(cfg80211_mutex);

 *** DEADLOCK ***

3 locks held by kworker/0:1/235:
 #0:  (events){.+.+..}, at: [<80089a00>] process_one_work+0x230/0x460
 #1:  (reg_regdb_work){+.+...}, at: [<80089a00>] process_one_work+0x230/0x460
 #2:  (reg_regdb_search_mutex){+.+...}, at: [<81646828>] set_regdom+0x710/0x808 [cfg80211]

stack backtrace:
Call Trace:
[<80290fd4>] dump_stack+0x8/0x34
[<80291bc4>] print_circular_bug+0x2ac/0x2d8
[<800a77b8>] __lock_acquire+0x10d4/0x17bc
[<800a8384>] lock_acquire+0x60/0x88
[<802950a8>] mutex_lock_nested+0x54/0x31c
[<816468a4>] set_regdom+0x78c/0x808 [cfg80211]

Reported-by: Felix Fietkau <nbd@openwrt.org>
Tested-by: Felix Fietkau <nbd@openwrt.org>
Cc: stable@vger.kernel.org
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2012-09-18 20:43:23 -04:00
..
.gitignore wireless: support internal statically compiled regulatory database 2009-12-21 18:56:10 -05:00
Kconfig cfg80211: add CONFIG_CFG80211_CERTIFICATION_ONUS 2012-07-17 12:13:51 +02:00
Makefile cfg80211: introduce cfg80211_stop_ap 2012-06-29 13:39:14 +02:00
ap.c cfg80211: add channel tracking for AP and mesh 2012-06-29 13:39:15 +02:00
chan.c cfg80211: reduce monitor interface tracking 2012-07-13 16:16:11 +02:00
core.c cfg80211: process pending events when unregistering net device 2012-08-06 14:29:58 -04:00
core.h cfg80211: process pending events when unregistering net device 2012-08-06 14:29:58 -04:00
db.txt wireless: support internal statically compiled regulatory database 2009-12-21 18:56:10 -05:00
debugfs.c simple_open: automatically convert to simple_open() 2012-04-05 15:25:50 -07:00
debugfs.h
ethtool.c cfg80211: Add framework to support ethtool stats. 2012-05-08 21:53:49 -04:00
ethtool.h
genregdb.awk cfg80211: relicense reg.c reg.h and genregdb.awk to ISC 2012-01-04 14:30:41 -05:00
ibss.c cfg80211: respect iface combinations when starting operation 2012-06-29 13:39:19 +02:00
lib80211.c lib80211: remove exports for functions not called by other modules 2011-08-09 15:42:36 -04:00
lib80211_crypt_ccmp.c net: Convert net_ratelimit uses to net_<level>_ratelimited 2012-05-15 13:45:03 -04:00
lib80211_crypt_tkip.c net: Convert net_ratelimit uses to net_<level>_ratelimited 2012-05-15 13:45:03 -04:00
lib80211_crypt_wep.c wireless: Remove unnecessary OOM logging messages 2011-09-13 15:45:02 -04:00
mesh.c cfg80211: respect iface combinations when starting operation 2012-06-29 13:39:19 +02:00
mlme.c cfg80211: support TX error rate CQM 2012-07-17 11:57:23 +02:00
nl80211.c nl80211: fix possible memory leak nl80211_connect() 2012-09-04 18:06:00 +02:00
nl80211.h cfg80211: support TX error rate CQM 2012-07-17 11:57:23 +02:00
radiotap.c net: Add export.h for EXPORT_SYMBOL/THIS_MODULE to non-modules 2011-10-31 19:30:30 -04:00
reg.c cfg80211: fix possible circular lock on reg_regdb_search() 2012-09-18 20:43:23 -04:00
reg.h cfg80211: make regulatory_update() static 2012-07-17 12:16:40 +02:00
regdb.h cfg80211: relicense reg.c reg.h and genregdb.awk to ISC 2012-01-04 14:30:41 -05:00
scan.c nl80211: move scan API to wdev 2012-07-12 12:10:41 +02:00
sme.c nl80211: move scan API to wdev 2012-07-12 12:10:41 +02:00
sysfs.c mac80211: fix suspend/resume races with unregister hw 2011-08-22 14:21:40 -04:00
sysfs.h
util.c cfg80211: process pending events when unregistering net device 2012-08-06 14:29:58 -04:00
wext-compat.c cfg80211/mac80211: re-add get_channel operation 2012-07-13 16:16:11 +02:00
wext-compat.h cfg80211: remove unused wext handler exports 2011-08-08 14:26:29 -04:00
wext-core.c net: cleanup unsigned to unsigned int 2012-04-15 12:44:40 -04:00
wext-priv.c wext: fix potential private ioctl memory content leak 2010-09-20 13:41:40 -04:00
wext-proc.c net: spread __net_init, __net_exit 2010-01-17 19:16:02 -08:00
wext-sme.c cfg80211: clarify set_channel APIs 2012-06-06 15:18:17 -04:00
wext-spy.c wireless: Convert compare_ether_addr to ether_addr_equal 2012-05-09 20:49:19 -04:00