From 30de3242a9e2ce447f9d6a55dad49e284894c8b4 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 28 Apr 2011 18:05:58 -0700 Subject: [PATCH] cfg80211: fix lockdep complaint on regulatory timeout The regulatory user timeout work introduced a secondary regression which can cause a lockup when a user regulatory hint times out longer than the time it takes to process the hint. If the timeout hits while processing regulatory data the _synch forces us to wait on an already held lock. Fix this by scheduling out the cancelation, avoiding contention on both threads. cfg80211: Timeout while waiting for CRDA to reply, restoring regulatory settings cfg80211: 5150000 KHz - 5350000 KHz @ KHz), (N/A mBi, 2000 mBm) ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.39-rc4-wl-00414-gbb467115-dirty #68 ------------------------------------------------------- kworker/1:2/50 is trying to acquire lock: (cfg80211_mutex){+.+.+.}, at: [] restore_regulatory_settings+0x31/0x330 [cfg80211] but task is already holding lock: ((reg_timeout).work ){+.+...} , at: [] process_one_work+0x13f/0x540 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 ((reg_timeout).work ){+.+...} : [] validate_chain+0x70a/0x810 [] __lock_acquire+0x2fa/0x4f0 [] lock_acquire+0xa0/0x170 [] wait_on_work+0x4f/0x140 [] __cancel_work_timer+0x49/0x140 [] cancel_delayed_work_sync+0x12/0x20 [] reg_set_request_processed+0x74/0x80 [cfg80211] [] set_regdom+0xaf/0x140 [cfg80211] [] nl80211_set_reg+0x101/0x2d0 [cfg80211] [] genl_rcv_msg+0x20d/0x270 [] netlink_rcv_skb+0xa9/0xd0 [] genl_rcv+0x25/0x40 [] netlink_unicast+0x2f2/0x310 [] netlink_sendmsg+0x22a/0x340 [] sock_sendmsg+0xe9/0x120 [] sys_sendmsg+0x243/0x3a0 [] system_call_fastpath+0x16/0x1b -> #1 (reg_mutex){+.+.+.}: [] validate_chain+0x70a/0x810 [] __lock_acquire+0x2fa/0x4f0 [] lock_acquire+0xa0/0x170 [] __mutex_lock_common+0x62/0x4f0 [] mutex_lock_nested+0x43/0x50 [] reg_process_pending_hints+0x2a/0xd0 [cfg80211] [] reg_todo+0xe/0x20 [cfg80211] [] process_one_work+0x1b0/0x540 [] worker_thread+0x174/0x400 [] kthread+0xb6/0xc0 [] kernel_thread_helper+0x4/0x10 -> #0 (cfg80211_mutex){+.+.+.}: [] check_prev_add+0x537/0x560 [] validate_chain+0x70a/0x810 [] __lock_acquire+0x2fa/0x4f0 [] lock_acquire+0xa0/0x170 [] __mutex_lock_common+0x62/0x4f0 [] mutex_lock_nested+0x43/0x50 [] restore_regulatory_settings+0x31/0x330 [cfg80211] [] reg_timeout_work+0x21/0x30 [cfg80211] [] process_one_work+0x1b0/0x540 [] worker_thread+0x174/0x400 [] kthread+0xb6/0xc0 [] kernel_thread_helper+0x4/0x10 other info that might help us debug this: 2 locks held by kworker/1:2/50: #0: (events){.+.+.+}, at: [] process_one_work+0x13f/0x540 #1: ((reg_timeout).work){+.+...}, at: [] process_one_work+0x13f/0x540 stack backtrace: Pid: 50, comm: kworker/1:2 Not tainted 2.6.39-rc4-wl-00414-gbb467115-dirty #68 Call Trace: [] print_circular_bug+0xf1/0x100 [] check_prev_add+0x537/0x560 [] validate_chain+0x70a/0x810 [] __lock_acquire+0x2fa/0x4f0 [] ? _raw_spin_unlock+0x35/0x60 [] lock_acquire+0xa0/0x170 [] ? restore_regulatory_settings+0x31/0x330 [cfg80211] [] ? do_raw_spin_unlock+0x5e/0xb0 [] __mutex_lock_common+0x62/0x4f0 [] ? restore_regulatory_settings+0x31/0x330 [cfg80211] [] ? vprintk+0x37c/0x520 [] ? restore_regulatory_settings+0x31/0x330 [cfg80211] [] mutex_lock_nested+0x43/0x50 [] restore_regulatory_settings+0x31/0x330 [cfg80211] [] reg_timeout_work+0x21/0x30 [cfg80211] [] process_one_work+0x1b0/0x540 [] ? process_one_work+0x13f/0x540 [] ? restore_regulatory_settings+0x330/0x330 [cfg80211] [] worker_thread+0x174/0x400 [] ? manage_workers+0x120/0x120 [] kthread+0xb6/0xc0 [] ? trace_hardirqs_on_caller+0x13d/0x180 [] kernel_thread_helper+0x4/0x10 [] ? finish_task_switch+0x7d/0x110 [] ? retint_restore_args+0x13/0x13 [] ? __init_kthread_worker+0x70/0x70 [] ? gs_change+0x13/0x13 Reported-by: Johannes Berg Signed-off-by: Luis R. Rodriguez --- net/wireless/reg.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1613080..624929f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -106,6 +106,9 @@ struct reg_beacon { static void reg_todo(struct work_struct *work); static DECLARE_WORK(reg_work, reg_todo); +static void reg_cancel_timeout(struct work_struct *work); +static DECLARE_WORK(reg_cancel, reg_cancel_timeout); + static void reg_timeout_work(struct work_struct *work); static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); @@ -1334,7 +1337,7 @@ static void reg_set_request_processed(void) spin_unlock(®_requests_lock); if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) - cancel_delayed_work_sync(®_timeout); + schedule_work(®_cancel); if (need_more_processing) schedule_work(®_work); @@ -1544,6 +1547,11 @@ static void reg_todo(struct work_struct *work) reg_process_pending_beacon_hints(); } +static void reg_cancel_timeout(struct work_struct *work) +{ + cancel_delayed_work_sync(®_timeout); +} + static void queue_regulatory_request(struct regulatory_request *request) { if (isalpha(request->alpha2[0])) @@ -2245,6 +2253,7 @@ void /* __init_or_exit */ regulatory_exit(void) struct reg_beacon *reg_beacon, *btmp; cancel_work_sync(®_work); + cancel_work_sync(®_cancel); cancel_delayed_work_sync(®_timeout); mutex_lock(&cfg80211_mutex); -- 1.7.4.15.g7811d