Skip to content

Commit a85d0d7

Browse files
mcgroflinvjw
authored andcommitted
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>
1 parent 78c04c0 commit a85d0d7

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

net/wireless/reg.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ static void reg_regdb_search(struct work_struct *work)
350350
struct reg_regdb_search_request *request;
351351
const struct ieee80211_regdomain *curdom, *regdom;
352352
int i, r;
353+
bool set_reg = false;
354+
355+
mutex_lock(&cfg80211_mutex);
353356

354357
mutex_lock(&reg_regdb_search_mutex);
355358
while (!list_empty(&reg_regdb_search_list)) {
@@ -365,16 +368,19 @@ static void reg_regdb_search(struct work_struct *work)
365368
r = reg_copy_regd(&regdom, curdom);
366369
if (r)
367370
break;
368-
mutex_lock(&cfg80211_mutex);
369-
set_regdom(regdom);
370-
mutex_unlock(&cfg80211_mutex);
371+
set_reg = true;
371372
break;
372373
}
373374
}
374375

375376
kfree(request);
376377
}
377378
mutex_unlock(&reg_regdb_search_mutex);
379+
380+
if (set_reg)
381+
set_regdom(regdom);
382+
383+
mutex_unlock(&cfg80211_mutex);
378384
}
379385

380386
static DECLARE_WORK(reg_regdb_work, reg_regdb_search);

0 commit comments

Comments
 (0)