* 2.6.25rc7 lockdep trace
@ 2008-03-28 0:00 Dave Jones
2008-03-28 1:55 ` Dave Jones
2008-03-29 0:34 ` David Miller
0 siblings, 2 replies; 28+ messages in thread
From: Dave Jones @ 2008-03-28 0:00 UTC (permalink / raw)
To: netdev
I see this every time I shut down.
Dave
=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.25-0.161.rc7.fc9.i686 #1
-------------------------------------------------------
NetworkManager/2308 is trying to acquire lock:
(events){--..}, at: [flush_workqueue+0/133] flush_workqueue+0x0/0x85
but task is already holding lock:
(rtnl_mutex){--..}, at: [rtnetlink_rcv+18/38] rtnetlink_rcv+0x12/0x26
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (rtnl_mutex){--..}:
[__lock_acquire+2713/3089] __lock_acquire+0xa99/0xc11
[lock_acquire+106/144] lock_acquire+0x6a/0x90
[mutex_lock_nested+219/625] mutex_lock_nested+0xdb/0x271
[rtnl_lock+15/17] rtnl_lock+0xf/0x11
[linkwatch_event+8/34] linkwatch_event+0x8/0x22
[run_workqueue+211/417] run_workqueue+0xd3/0x1a1
[worker_thread+182/194] worker_thread+0xb6/0xc2
[kthread+59/97] kthread+0x3b/0x61
[kernel_thread_helper+7/16] kernel_thread_helper+0x7/0x10
[<ffffffff>] 0xffffffff
-> #1 ((linkwatch_work).work){--..}:
[__lock_acquire+2713/3089] __lock_acquire+0xa99/0xc11
[lock_acquire+106/144] lock_acquire+0x6a/0x90
[run_workqueue+205/417] run_workqueue+0xcd/0x1a1
[worker_thread+182/194] worker_thread+0xb6/0xc2
[kthread+59/97] kthread+0x3b/0x61
[kernel_thread_helper+7/16] kernel_thread_helper+0x7/0x10
[<ffffffff>] 0xffffffff
-> #0 (events){--..}:
[__lock_acquire+2488/3089] __lock_acquire+0x9b8/0xc11
[lock_acquire+106/144] lock_acquire+0x6a/0x90
[flush_workqueue+68/133] flush_workqueue+0x44/0x85
[flush_scheduled_work+13/15] flush_scheduled_work+0xd/0xf
[<d096d80a>] tulip_down+0x20/0x1a3 [tulip]
[<d096e2b5>] tulip_close+0x24/0xd6 [tulip]
[dev_close+82/111] dev_close+0x52/0x6f
[dev_change_flags+159/338] dev_change_flags+0x9f/0x152
[do_setlink+586/764] do_setlink+0x24a/0x2fc
[rtnl_setlink+226/230] rtnl_setlink+0xe2/0xe6
[rtnetlink_rcv_msg+418/444] rtnetlink_rcv_msg+0x1a2/0x1bc
[netlink_rcv_skb+48/134] netlink_rcv_skb+0x30/0x86
[rtnetlink_rcv+30/38] rtnetlink_rcv+0x1e/0x26
[netlink_unicast+439/533] netlink_unicast+0x1b7/0x215
[netlink_sendmsg+600/613] netlink_sendmsg+0x258/0x265
[sock_sendmsg+222/249] sock_sendmsg+0xde/0xf9
[sys_sendmsg+319/402] sys_sendmsg+0x13f/0x192
[sys_socketcall+363/390] sys_socketcall+0x16b/0x186
[syscall_call+7/11] syscall_call+0x7/0xb
[<ffffffff>] 0xffffffff
other info that might help us debug this:
1 lock held by NetworkManager/2308:
#0: (rtnl_mutex){--..}, at: [rtnetlink_rcv+18/38] rtnetlink_rcv+0x12/0x26
stack backtrace:
Pid: 2308, comm: NetworkManager Not tainted 2.6.25-0.161.rc7.fc9.i686 #1
[print_circular_bug_tail+91/102] print_circular_bug_tail+0x5b/0x66
[print_circular_bug_entry+57/67] ? print_circular_bug_entry+0x39/0x43
[__lock_acquire+2488/3089] __lock_acquire+0x9b8/0xc11
[_spin_unlock_irq+34/47] ? _spin_unlock_irq+0x22/0x2f
[lock_acquire+106/144] lock_acquire+0x6a/0x90
[flush_workqueue+0/133] ? flush_workqueue+0x0/0x85
[flush_workqueue+68/133] flush_workqueue+0x44/0x85
[flush_workqueue+0/133] ? flush_workqueue+0x0/0x85
[flush_scheduled_work+13/15] flush_scheduled_work+0xd/0xf
[<d096d80a>] tulip_down+0x20/0x1a3 [tulip]
[trace_hardirqs_on+233/266] ? trace_hardirqs_on+0xe9/0x10a
[dev_deactivate+177/222] ? dev_deactivate+0xb1/0xde
[<d096e2b5>] tulip_close+0x24/0xd6 [tulip]
[dev_close+82/111] dev_close+0x52/0x6f
[dev_change_flags+159/338] dev_change_flags+0x9f/0x152
[do_setlink+586/764] do_setlink+0x24a/0x2fc
[_read_unlock+29/32] ? _read_unlock+0x1d/0x20
[rtnl_setlink+226/230] rtnl_setlink+0xe2/0xe6
[rtnl_setlink+0/230] ? rtnl_setlink+0x0/0xe6
[rtnetlink_rcv_msg+418/444] rtnetlink_rcv_msg+0x1a2/0x1bc
[rtnetlink_rcv_msg+0/444] ? rtnetlink_rcv_msg+0x0/0x1bc
[netlink_rcv_skb+48/134] netlink_rcv_skb+0x30/0x86
[rtnetlink_rcv+30/38] rtnetlink_rcv+0x1e/0x26
[netlink_unicast+439/533] netlink_unicast+0x1b7/0x215
[netlink_sendmsg+600/613] netlink_sendmsg+0x258/0x265
[sock_sendmsg+222/249] sock_sendmsg+0xde/0xf9
[autoremove_wake_function+0/51] ? autoremove_wake_function+0x0/0x33
[native_sched_clock+181/209] ? native_sched_clock+0xb5/0xd1
[sched_clock+8/11] ? sched_clock+0x8/0xb
[lock_release_holdtime+26/277] ? lock_release_holdtime+0x1a/0x115
[fget_light+142/185] ? fget_light+0x8e/0xb9
[copy_from_user+57/289] ? copy_from_user+0x39/0x121
[verify_iovec+64/111] ? verify_iovec+0x40/0x6f
[sys_sendmsg+319/402] sys_sendmsg+0x13f/0x192
[sys_recvmsg+366/379] ? sys_recvmsg+0x16e/0x17b
[check_object+304/388] ? check_object+0x130/0x184
[check_object+304/388] ? check_object+0x130/0x184
[kmem_cache_free+186/207] ? kmem_cache_free+0xba/0xcf
[trace_hardirqs_on+233/266] ? trace_hardirqs_on+0xe9/0x10a
[d_free+59/77] ? d_free+0x3b/0x4d
[d_free+59/77] ? d_free+0x3b/0x4d
[sys_socketcall+363/390] sys_socketcall+0x16b/0x186
[syscall_call+7/11] syscall_call+0x7/0xb
=======================
--
http://www.codemonkey.org.uk
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: 2.6.25rc7 lockdep trace 2008-03-28 0:00 2.6.25rc7 lockdep trace Dave Jones @ 2008-03-28 1:55 ` Dave Jones 2008-03-29 0:34 ` David Miller 1 sibling, 0 replies; 28+ messages in thread From: Dave Jones @ 2008-03-28 1:55 UTC (permalink / raw) To: netdev On Thu, Mar 27, 2008 at 08:00:13PM -0400, Dave Jones wrote: > I see this every time I shut down. Something that may be relevant.. There are two NICs in this machine. An onboard e100, which is in use, and there's a PCI tulip card in there which doesn't even have a cable plugged into it. The not-in-use card seems to be the trigger. Dave -- http://www.codemonkey.org.uk ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-28 0:00 2.6.25rc7 lockdep trace Dave Jones 2008-03-28 1:55 ` Dave Jones @ 2008-03-29 0:34 ` David Miller 2008-03-29 0:54 ` Johannes Berg 1 sibling, 1 reply; 28+ messages in thread From: David Miller @ 2008-03-29 0:34 UTC (permalink / raw) To: davej; +Cc: netdev From: Dave Jones <davej@codemonkey.org.uk> Date: Thu, 27 Mar 2008 20:00:13 -0400 > stack backtrace: > Pid: 2308, comm: NetworkManager Not tainted 2.6.25-0.161.rc7.fc9.i686 #1 > [print_circular_bug_tail+91/102] print_circular_bug_tail+0x5b/0x66 > [print_circular_bug_entry+57/67] ? print_circular_bug_entry+0x39/0x43 > [__lock_acquire+2488/3089] __lock_acquire+0x9b8/0xc11 > [_spin_unlock_irq+34/47] ? _spin_unlock_irq+0x22/0x2f > [lock_acquire+106/144] lock_acquire+0x6a/0x90 > [flush_workqueue+0/133] ? flush_workqueue+0x0/0x85 > [flush_workqueue+68/133] flush_workqueue+0x44/0x85 > [flush_workqueue+0/133] ? flush_workqueue+0x0/0x85 > [flush_scheduled_work+13/15] flush_scheduled_work+0xd/0xf > [<d096d80a>] tulip_down+0x20/0x1a3 [tulip] > [trace_hardirqs_on+233/266] ? trace_hardirqs_on+0xe9/0x10a > [dev_deactivate+177/222] ? dev_deactivate+0xb1/0xde Yes, see for example: http://www.mail-archive.com/netdev@vger.kernel.org/msg31718.html You can't flush a workqueue in the device close handler exactly because of this locking conflict. Nobody has come up with a suitable way to fix this yet. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 0:34 ` David Miller @ 2008-03-29 0:54 ` Johannes Berg 2008-03-29 1:01 ` Johannes Berg 2008-03-29 1:06 ` David Miller 0 siblings, 2 replies; 28+ messages in thread From: Johannes Berg @ 2008-03-29 0:54 UTC (permalink / raw) To: David Miller; +Cc: davej, netdev [-- Attachment #1: Type: text/plain, Size: 1554 bytes --] > > stack backtrace: > > Pid: 2308, comm: NetworkManager Not tainted 2.6.25-0.161.rc7.fc9.i686 #1 > > [print_circular_bug_tail+91/102] print_circular_bug_tail+0x5b/0x66 > > [print_circular_bug_entry+57/67] ? print_circular_bug_entry+0x39/0x43 > > [__lock_acquire+2488/3089] __lock_acquire+0x9b8/0xc11 > > [_spin_unlock_irq+34/47] ? _spin_unlock_irq+0x22/0x2f > > [lock_acquire+106/144] lock_acquire+0x6a/0x90 > > [flush_workqueue+0/133] ? flush_workqueue+0x0/0x85 > > [flush_workqueue+68/133] flush_workqueue+0x44/0x85 > > [flush_workqueue+0/133] ? flush_workqueue+0x0/0x85 > > [flush_scheduled_work+13/15] flush_scheduled_work+0xd/0xf > > [<d096d80a>] tulip_down+0x20/0x1a3 [tulip] > > [trace_hardirqs_on+233/266] ? trace_hardirqs_on+0xe9/0x10a > > [dev_deactivate+177/222] ? dev_deactivate+0xb1/0xde > > Yes, see for example: > > http://www.mail-archive.com/netdev@vger.kernel.org/msg31718.html > > You can't flush a workqueue in the device close handler > exactly because of this locking conflict. > > Nobody has come up with a suitable way to fix this yet. Maybe we should check which schedule_work users actually lock the rtnl within the work function and move them to a uses-rtnl-in-work workqueue so that everybody else can have rtnl around flush. Depending on how many users there are that might not be feasible, but I have so far only seen linkwatch_event() lock the rtnl within the work function and everybody else seems to want to use the rtnl around the flushing. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 0:54 ` Johannes Berg @ 2008-03-29 1:01 ` Johannes Berg 2008-03-29 1:09 ` David Miller 2008-03-29 1:06 ` David Miller 1 sibling, 1 reply; 28+ messages in thread From: Johannes Berg @ 2008-03-29 1:01 UTC (permalink / raw) To: David Miller; +Cc: davej, netdev [-- Attachment #1: Type: text/plain, Size: 790 bytes --] > > You can't flush a workqueue in the device close handler > > exactly because of this locking conflict. > > > > Nobody has come up with a suitable way to fix this yet. > > Maybe we should check which schedule_work users actually lock the rtnl > within the work function and move them to a uses-rtnl-in-work workqueue > so that everybody else can have rtnl around flush. On the other hand, most drivers don't actually care that their work has run, they just care that it won't run in the future after they give up resources or similar, hence they can and should use cancel_work_sync() which doesn't suffer from the deadlock. But that needs actual inspection because it does change behaviour from "run and wait for it if scheduled" to "cancel if scheduled". johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 1:01 ` Johannes Berg @ 2008-03-29 1:09 ` David Miller 2008-04-02 8:51 ` Oleg Nesterov 0 siblings, 1 reply; 28+ messages in thread From: David Miller @ 2008-03-29 1:09 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: Johannes Berg <johannes@sipsolutions.net> Date: Sat, 29 Mar 2008 02:01:25 +0100 > > > > You can't flush a workqueue in the device close handler > > > exactly because of this locking conflict. > > > > > > Nobody has come up with a suitable way to fix this yet. > > > > Maybe we should check which schedule_work users actually lock the rtnl > > within the work function and move them to a uses-rtnl-in-work workqueue > > so that everybody else can have rtnl around flush. > > On the other hand, most drivers don't actually care that their work has > run, they just care that it won't run in the future after they give up > resources or similar, hence they can and should use cancel_work_sync() > which doesn't suffer from the deadlock. But that needs actual inspection > because it does change behaviour from "run and wait for it if scheduled" > to "cancel if scheduled". I don't see how you can not race with the transition from scheduled to "executing" without taking the runqueue lock for the testing. And it is crucial that the workqueue function doesn't execute "accidently" due to such a race before the module and thus the workqueue code is about to get potentially unloaded. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 1:09 ` David Miller @ 2008-04-02 8:51 ` Oleg Nesterov 0 siblings, 0 replies; 28+ messages in thread From: Oleg Nesterov @ 2008-04-02 8:51 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 03/28, David Miller wrote: > > From: Johannes Berg <johannes@sipsolutions.net> > Date: Sat, 29 Mar 2008 02:01:25 +0100 > > > > > > > You can't flush a workqueue in the device close handler > > > > exactly because of this locking conflict. > > > > > > > > Nobody has come up with a suitable way to fix this yet. > > > > > > Maybe we should check which schedule_work users actually lock the rtnl > > > within the work function and move them to a uses-rtnl-in-work workqueue > > > so that everybody else can have rtnl around flush. > > > > On the other hand, most drivers don't actually care that their work has > > run, they just care that it won't run in the future after they give up > > resources or similar, hence they can and should use cancel_work_sync() > > which doesn't suffer from the deadlock. But that needs actual inspection > > because it does change behaviour from "run and wait for it if scheduled" > > to "cancel if scheduled". > > I don't see how you can not race with the transition from > scheduled to "executing" without taking the runqueue lock > for the testing. Yes, cancel_work_sync() takes cwq->lock but this is fine (unless it is buggy ;) Please note that run_workqueue() drops this lock before calling work->func(). If the caller of cancel_work_sync(work) doesn't share locks with work->func() we can't deadlock, even if there are other pending/running work_structs which need the same locks as the caller (say, RTNL). But, perhaps, you mean wq->lockdep_map? As Johannes pointed out this lock is fake, but I think this doesn't matter, from the correctness POV it is "real" lock. What does matter is that cancel_work_sync() doesn't use this lock at all. (again, Johannes has already explained this all). > And it is crucial that the workqueue function doesn't > execute "accidently" due to such a race before the module > and thus the workqueue code is about to get potentially > unloaded. Which race? Unless explicitly queued afterwards, work->func() can't execute after return from cancel_work_sync(work). David, I think you misunderstood Johannes, or perhaps I missed something. Oleg. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 0:54 ` Johannes Berg 2008-03-29 1:01 ` Johannes Berg @ 2008-03-29 1:06 ` David Miller 2008-03-29 10:02 ` Johannes Berg 1 sibling, 1 reply; 28+ messages in thread From: David Miller @ 2008-03-29 1:06 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: Johannes Berg <johannes@sipsolutions.net> Date: Sat, 29 Mar 2008 01:54:09 +0100 > Maybe we should check which schedule_work users actually lock the rtnl > within the work function and move them to a uses-rtnl-in-work workqueue > so that everybody else can have rtnl around flush. The issue is that linkwatch goes: workqueue lock --> RTNL And thus taking workqueue lock within RTNL is deadlock prone no matter where you do it. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 1:06 ` David Miller @ 2008-03-29 10:02 ` Johannes Berg 2008-03-29 12:52 ` Jarek Poplawski 2008-04-03 20:48 ` David Miller 0 siblings, 2 replies; 28+ messages in thread From: Johannes Berg @ 2008-03-29 10:02 UTC (permalink / raw) To: David Miller; +Cc: davej, netdev [-- Attachment #1: Type: text/plain, Size: 2956 bytes --] [merging your two mails] > The issue is that linkwatch goes: workqueue lock --> RTNL > > And thus taking workqueue lock within RTNL is deadlock > prone no matter where you do it. Which lock are you referring to here? There is no real runqueue lock other than a spin-lock for the list. I think you may be misunderstanding the lockdep output in a way I didn't anticipated when adding lockdep debugging for workqueue stuff. The actual work function is _not_ running with any locks held! The fact that you see lockdep output there is because we tell lockdep we're holding two locks, namely the "work" and the "workqueue". These are fake, they aren't actually locks. More importantly, those "locks" are locked and unlocked for every _run_ of the struct work function, not around the whole runqueue manipulation, that part is done atomically without global locks. So what you have is essentially list_for_each_work lock(workqueue) lock(struct work) work->f(); unlock(struct work) unlock(workqueue) where both those locks are really only telling lockdep there are locks to get it to warn about the deadlock scenario. Unfortunately Andrew mangled the two patches into one when committing, so I can't point to the changelog, but here are two links to the two patches adding this: http://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.23-rc1/2.6.23-rc1-mm2/broken-out/workqueue-debug-flushing-deadlocks-with-lockdep.patch http://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.23-rc1/2.6.23-rc1-mm2/broken-out/workqueue-debug-work-related-deadlocks-with-lockdep.patch I think the "runqueue lock" you're referring to is the fake "lock(workqueue)" which isn't around the whole runqueue manipulation but only a lockdep helper to debug exactly the deadlock problem we're talking about. I'm open to renaming it, but I don't think lockdep supports formatting its output differently. > I don't see how you can not race with the transition from > scheduled to "executing" without taking the runqueue lock > for the testing. When you call cancel_work_sync(), the work struct will be grabbed by the code (really __cancel_work_timer) and removed from the queue. That just operates on bits and a spinlock, not locks held across the struct work function execution, and ensures it is race-free without needing any such locks. > And it is crucial that the workqueue function doesn't > execute "accidently" due to such a race before the module > and thus the workqueue code is about to get potentially > unloaded. That is exactly what cancel_work_sync() guarantees, but not more. On contrary, flush_workqueue() also guarantees that the work is run one last time if it was scheduled at the time of the flush_workqueue() call. However, as I just tried to explain, cancel_work_sync() _is_ safe to run while holding the RTNL because it doesn't need any runqueue lock. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 10:02 ` Johannes Berg @ 2008-03-29 12:52 ` Jarek Poplawski 2008-03-29 12:50 ` Johannes Berg 2008-04-03 20:48 ` David Miller 1 sibling, 1 reply; 28+ messages in thread From: Jarek Poplawski @ 2008-03-29 12:52 UTC (permalink / raw) To: Johannes Berg; +Cc: David Miller, davej, netdev Johannes Berg wrote, On 03/29/2008 11:02 AM: ... > When you call cancel_work_sync(), the work struct will be grabbed by the > code (really __cancel_work_timer) and removed from the queue. That just > operates on bits and a spinlock, not locks held across the struct work > function execution, and ensures it is race-free without needing any such > locks ... > However, as I just tried to explain, cancel_work_sync() _is_ safe to run > while holding the RTNL because it doesn't need any runqueue lock. These issues are so seldom now that I forget these details each time "after use", so maybe I miss something again, but shouldn't this rather read something like this?: cancel_work_sync() _is_ safe to run while holding the RTNL against works which don't take RTNL. Regards, Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 12:52 ` Jarek Poplawski @ 2008-03-29 12:50 ` Johannes Berg 0 siblings, 0 replies; 28+ messages in thread From: Johannes Berg @ 2008-03-29 12:50 UTC (permalink / raw) To: Jarek Poplawski; +Cc: David Miller, davej, netdev [-- Attachment #1: Type: text/plain, Size: 830 bytes --] > > When you call cancel_work_sync(), the work struct will be grabbed by the > > code (really __cancel_work_timer) and removed from the queue. That just > > operates on bits and a spinlock, not locks held across the struct work > > function execution, and ensures it is race-free without needing any such > > locks > > ... > > > However, as I just tried to explain, cancel_work_sync() _is_ safe to run > > while holding the RTNL because it doesn't need any runqueue lock. > > These issues are so seldom now that I forget these details each time > > "after use", so maybe I miss something again, but shouldn't this rather > read something like this?: > > cancel_work_sync() _is_ safe to run while holding the RTNL against > works which don't take RTNL. Yes, indeed, I should have said that. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-03-29 10:02 ` Johannes Berg 2008-03-29 12:52 ` Jarek Poplawski @ 2008-04-03 20:48 ` David Miller 2008-04-04 14:48 ` Johannes Berg 1 sibling, 1 reply; 28+ messages in thread From: David Miller @ 2008-04-03 20:48 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: Johannes Berg <johannes@sipsolutions.net> Date: Sat, 29 Mar 2008 11:02:28 +0100 > However, as I just tried to explain, cancel_work_sync() _is_ safe to run > while holding the RTNL because it doesn't need any runqueue lock. So in theory we should be able to safely transform flush_scheduled_work() calls in network driver close methods into cancel_work_sync()? Could someone prepare that patch? Thanks. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-04-03 20:48 ` David Miller @ 2008-04-04 14:48 ` Johannes Berg 2008-06-11 5:40 ` David Miller 0 siblings, 1 reply; 28+ messages in thread From: Johannes Berg @ 2008-04-04 14:48 UTC (permalink / raw) To: David Miller; +Cc: davej, netdev [-- Attachment #1: Type: text/plain, Size: 623 bytes --] On Thu, 2008-04-03 at 13:48 -0700, David Miller wrote: > From: Johannes Berg <johannes@sipsolutions.net> > Date: Sat, 29 Mar 2008 11:02:28 +0100 > > > However, as I just tried to explain, cancel_work_sync() _is_ safe to run > > while holding the RTNL because it doesn't need any runqueue lock. > > So in theory we should be able to safely transform > flush_scheduled_work() calls in network driver close > methods into cancel_work_sync()? Yes, more precisely cancel_work_sync() for each work struct the driver uses, unless the driver actually requires that the work runs before it goes down. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-04-04 14:48 ` Johannes Berg @ 2008-06-11 5:40 ` David Miller 2008-06-11 7:08 ` Jarek Poplawski ` (5 more replies) 0 siblings, 6 replies; 28+ messages in thread From: David Miller @ 2008-06-11 5:40 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: Johannes Berg <johannes@sipsolutions.net> Date: Fri, 04 Apr 2008 16:48:12 +0200 I'm attempting to bring solving this problem back from the dead. Please help! > On Thu, 2008-04-03 at 13:48 -0700, David Miller wrote: > > From: Johannes Berg <johannes@sipsolutions.net> > > Date: Sat, 29 Mar 2008 11:02:28 +0100 > > > > > However, as I just tried to explain, cancel_work_sync() _is_ safe to run > > > while holding the RTNL because it doesn't need any runqueue lock. > > > > So in theory we should be able to safely transform > > flush_scheduled_work() calls in network driver close > > methods into cancel_work_sync()? > > Yes, more precisely cancel_work_sync() for each work struct the driver > uses, unless the driver actually requires that the work runs before it > goes down. Ok, I did an audit of all the drivers under drivers/net that invoke flush_scheduled_work(). Here is my audit analysis and the patch I came up with. The only deadlock'y case I couldn't fix right now is the cassini driver, see below for details and the patch: 8139too: Calls flush_scheduled_work() in device remove method, OK. libertas: Calls flush_scheduled_work() in device probe and remove methods, OK. bnx2: Uses special polling mdelay() sequence instead of calling flush_scheduled_work() in close method, converted to cancel_work_sync(). cassini: Does flush_scheduled_work() from ->change_mtu() method, which also holds RTNL semaphore. Seems tricky to fix as it's trying to schedule work and then immediately wait for it to complete synchronously before returning from the ->change_mtu method. Maybe calling cas_reset_task() directly would work, but this could conflict with reset tasks scheduled in other contexts. NOT FIXED e1000e: Does flush_scheduled_work() from device remove method, OK. ehea_main: Does flush_scheduled_work() in ->stop method, converted to cancel_work_sync(). baycom_epp: Does flush_scheduled_work() from ->stop method, converted to cancel_delayed_work()/cancel_work_sync() sequence. ibm_newemac: Calls flush_scheduled_work() from device remove method, OK. igb: Calls flush_scheduled_work() from device remove method, OK. irda/mcs7780: Calls flush_scheduled_work() from USB disconnect, OK. iseries_veth: Calls flush_scheduled_work() from device disconnect and module exit, OK. ixgbe: Calls flush_scheduled_work() from device remove method, OK. mv643xx_eth: Calls flush_scheduled_work() from device remove method, OK. myri10ge: Calls flush_scheduled_work() from device remove method, OK. netxen: Has it's own hand-grown scheme to work around the flush_scheduled_work() deadlock. Using a workqueue and flush_workqueue(). niu: Calls flush_scheduled_work() only from suspend handler, OK. phy/phy.c: Avoids flush_scheduled_work() calls to avoid deadlock, uses cancel_work_sync() instead. r8169: Calls flush_scheduled_work() from device remove method, OK. s2io: Calls flush_scheduled_work() from device remove method, OK. sis190: Calls flush_scheduled_work() from device remove method, OK. skge.c: Calls flush_scheduled_work() from device remove method, OK. smc911x: Uses a similar polling loop like bnx2 did, converted to cancel_work_sync(). smc91x: Same as smc911x sungem: Calls flush_scheduled_work() only from suspend and device remove method, OK. tg3: Calls flush_scheduled_work() only from suspend and device remove method, OK. tulip_core: Calls flush_scheduled_work() from tulip_down(), converted to cancel_work_sync(). kaweth: Calls flush_scheduled_work() from kaweth_kill_urbs() which can run from the ->stop() handler, converted to cancel_delayed_work/cancel_work_sync sequence. usbnet: Only calls flush_scheduled_work() from disconnect handler, OK. hostap: Calls flush_scheduled_work() from ->stop, converted to cancel_work_sync() Signed-off-by: David S. Miller <davem@davemloft.net> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4b46e68..48ed410 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5907,12 +5907,7 @@ bnx2_close(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 reset_code; - /* Calling flush_scheduled_work() may deadlock because - * linkwatch_event() may be on the workqueue and it will try to get - * the rtnl_lock which we are holding. - */ - while (bp->in_reset_task) - msleep(1); + cancel_work_sync(&bp->reset_task); bnx2_disable_int_sync(bp); bnx2_napi_disable(bp); diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index faae01d..075fd54 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2605,7 +2605,8 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_scheduled_work(); + cancel_work_sync(&port->reset_task); + mutex_lock(&port->port_lock); netif_stop_queue(dev); port_napi_disable(port); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index dde9c7e..b36ae41 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -959,7 +959,8 @@ static int epp_close(struct net_device *dev) unsigned char tmp[1]; bc->work_running = 0; - flush_scheduled_work(); + cancel_delayed_work(&bc->run_work); + cancel_work_sync(&bc->run_work.work); bc->stat = EPP_DCDBIT; tmp[0] = 0; pp->ops->epp_write_addr(pp, tmp, 1, 0); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4e28002..5c71098 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1531,16 +1531,8 @@ static int smc911x_close(struct net_device *dev) if (lp->phy_type != 0) { /* We need to ensure that no calls to * smc911x_phy_configure are pending. - - * flush_scheduled_work() cannot be called because we - * are running with the netlink semaphore held (from - * devinet_ioctl()) and the pending work queue - * contains linkwatch_event() (scheduled by - * netif_carrier_off() above). linkwatch_event() also - * wants the netlink semaphore. */ - while (lp->work_pending) - schedule(); + cancel_work_sync(&lp->phy_configure); smc911x_phy_powerdown(dev, lp->mii.phy_id); } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index a188e33..5dbe4d3 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev) /* We need to ensure that no calls to smc_phy_configure are pending. - - flush_scheduled_work() cannot be called because we are - running with the netlink semaphore held (from - devinet_ioctl()) and the pending work queue contains - linkwatch_event() (scheduled by netif_carrier_off() - above). linkwatch_event() also wants the netlink semaphore. */ - while(lp->work_pending) - yield(); + cancel_work_sync(&lp->phy_configure); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 55670b5..af8d2c4 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -731,7 +731,7 @@ static void tulip_down (struct net_device *dev) void __iomem *ioaddr = tp->base_addr; unsigned long flags; - flush_scheduled_work(); + cancel_work_sync(&tp->media_work); #ifdef CONFIG_TULIP_NAPI napi_disable(&tp->napi); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 0dcfc03..d776bcf 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -706,7 +706,8 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); - flush_scheduled_work(); + cancel_delayed_work(&kaweth->lowmem_work); + cancel_work_sync(&kaweth->lowmem_work.work); /* a scheduled work may have resubmitted, we hit them again */ diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 20d387f..57b800f 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -682,7 +682,11 @@ static int prism2_close(struct net_device *dev) netif_device_detach(dev); } - flush_scheduled_work(); + cancel_work_sync(&local->reset_queue); + cancel_work_sync(&local->set_multicast_list_queue); + cancel_work_sync(&local->set_tim_queue); + cancel_work_sync(&local->info_queue); + cancel_work_sync(&local->comms_qual_update); module_put(local->hw_module); ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller @ 2008-06-11 7:08 ` Jarek Poplawski 2008-06-11 7:10 ` David Miller 2008-06-11 9:36 ` Jarek Poplawski ` (4 subsequent siblings) 5 siblings, 1 reply; 28+ messages in thread From: Jarek Poplawski @ 2008-06-11 7:08 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 11-06-2008 07:40, David Miller wrote: ... > Ok, I did an audit of all the drivers under drivers/net that invoke > flush_scheduled_work(). Here is my audit analysis and the patch I > came up with. The only deadlock'y case I couldn't fix right now is > the cassini driver, see below for details and the patch: > > 8139too: Calls flush_scheduled_work() in device remove method, OK. I have some doubt here: this rtl8139_thred() work function seems to rearm if netif_running(). Is it guaranteed a dev is down while running this flush_scheduled_work()? Regards, Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 7:08 ` Jarek Poplawski @ 2008-06-11 7:10 ` David Miller 0 siblings, 0 replies; 28+ messages in thread From: David Miller @ 2008-06-11 7:10 UTC (permalink / raw) To: jarkao2; +Cc: johannes, davej, netdev From: Jarek Poplawski <jarkao2@gmail.com> Date: Wed, 11 Jun 2008 07:08:47 +0000 > On 11-06-2008 07:40, David Miller wrote: > ... > > Ok, I did an audit of all the drivers under drivers/net that invoke > > flush_scheduled_work(). Here is my audit analysis and the patch I > > came up with. The only deadlock'y case I couldn't fix right now is > > the cassini driver, see below for details and the patch: > > > > 8139too: Calls flush_scheduled_work() in device remove method, OK. > > I have some doubt here: this rtl8139_thred() work function seems to > rearm if netif_running(). Is it guaranteed a dev is down while > running this flush_scheduled_work()? Indeed, perhaps it should do the flush_scheduled_work() after the unregister_netdev(). ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller 2008-06-11 7:08 ` Jarek Poplawski @ 2008-06-11 9:36 ` Jarek Poplawski 2008-06-12 0:34 ` David Miller 2008-06-11 10:40 ` Jarek Poplawski ` (3 subsequent siblings) 5 siblings, 1 reply; 28+ messages in thread From: Jarek Poplawski @ 2008-06-11 9:36 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 11-06-2008 07:40, David Miller wrote: ... > ehea_main: Does flush_scheduled_work() in ->stop method, converted to > cancel_work_sync(). Looks like this work could be rearmed afterwards from ehea_qp_aff_irq_handler() (and maybe a few other places). Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 9:36 ` Jarek Poplawski @ 2008-06-12 0:34 ` David Miller 2008-06-12 6:29 ` Jarek Poplawski 0 siblings, 1 reply; 28+ messages in thread From: David Miller @ 2008-06-12 0:34 UTC (permalink / raw) To: jarkao2; +Cc: johannes, davej, netdev From: Jarek Poplawski <jarkao2@gmail.com> Date: Wed, 11 Jun 2008 09:36:45 +0000 > On 11-06-2008 07:40, David Miller wrote: > ... > > ehea_main: Does flush_scheduled_work() in ->stop method, converted to > > cancel_work_sync(). > > Looks like this work could be rearmed afterwards from > ehea_qp_aff_irq_handler() (and maybe a few other places). Good catch, but this bug exists both before and after my changes :-) It is certainly something which should be reported to the EHEA developers. Could you please do this? ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-12 0:34 ` David Miller @ 2008-06-12 6:29 ` Jarek Poplawski 0 siblings, 0 replies; 28+ messages in thread From: Jarek Poplawski @ 2008-06-12 6:29 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev, Jan-Bernd Themann, Thomas Klein On Wed, Jun 11, 2008 at 05:34:17PM -0700, David Miller wrote: > From: Jarek Poplawski <jarkao2@gmail.com> > Date: Wed, 11 Jun 2008 09:36:45 +0000 > > > On 11-06-2008 07:40, David Miller wrote: > > ... > > > ehea_main: Does flush_scheduled_work() in ->stop method, converted to > > > cancel_work_sync(). > > > > Looks like this work could be rearmed afterwards from > > ehea_qp_aff_irq_handler() (and maybe a few other places). > > Good catch, but this bug exists both before and after > my changes :-) > > It is certainly something which should be reported to > the EHEA developers. Could you please do this? I hope this RE & CC will suffice. Regards, Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller 2008-06-11 7:08 ` Jarek Poplawski 2008-06-11 9:36 ` Jarek Poplawski @ 2008-06-11 10:40 ` Jarek Poplawski 2008-06-12 0:31 ` David Miller 2008-06-11 13:14 ` Jarek Poplawski ` (2 subsequent siblings) 5 siblings, 1 reply; 28+ messages in thread From: Jarek Poplawski @ 2008-06-11 10:40 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 11-06-2008 07:40, David Miller wrote: ... > diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c > index 0dcfc03..d776bcf 100644 > --- a/drivers/net/usb/kaweth.c > +++ b/drivers/net/usb/kaweth.c > @@ -706,7 +706,8 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) > usb_kill_urb(kaweth->rx_urb); > usb_kill_urb(kaweth->tx_urb); > > - flush_scheduled_work(); > + cancel_delayed_work(&kaweth->lowmem_work); > + cancel_work_sync(&kaweth->lowmem_work.work); > Why not cancel_delayed_work_sync()? Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 10:40 ` Jarek Poplawski @ 2008-06-12 0:31 ` David Miller 0 siblings, 0 replies; 28+ messages in thread From: David Miller @ 2008-06-12 0:31 UTC (permalink / raw) To: jarkao2; +Cc: johannes, davej, netdev From: Jarek Poplawski <jarkao2@gmail.com> Date: Wed, 11 Jun 2008 10:40:27 +0000 > On 11-06-2008 07:40, David Miller wrote: > ... > > diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c > > index 0dcfc03..d776bcf 100644 > > --- a/drivers/net/usb/kaweth.c > > +++ b/drivers/net/usb/kaweth.c > > @@ -706,7 +706,8 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) > > usb_kill_urb(kaweth->rx_urb); > > usb_kill_urb(kaweth->tx_urb); > > > > - flush_scheduled_work(); > > + cancel_delayed_work(&kaweth->lowmem_work); > > + cancel_work_sync(&kaweth->lowmem_work.work); > > > > Why not cancel_delayed_work_sync()? I simply didn't know it existed :-) I've updated my patch to use cancel_delayed_work_sync() as appropriate, thanks! ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller ` (2 preceding siblings ...) 2008-06-11 10:40 ` Jarek Poplawski @ 2008-06-11 13:14 ` Jarek Poplawski 2008-06-12 5:46 ` David Miller 2008-06-12 6:13 ` Jarek Poplawski 5 siblings, 0 replies; 28+ messages in thread From: Jarek Poplawski @ 2008-06-11 13:14 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 11-06-2008 07:40, David Miller wrote: ... > cassini: Does flush_scheduled_work() from ->change_mtu() method, which > also holds RTNL semaphore. Seems tricky to fix as it's trying > to schedule work and then immediately wait for it to > complete synchronously before returning from the ->change_mtu > method. Maybe calling cas_reset_task() directly would work, > but this could conflict with reset tasks scheduled in other > contexts. NOT FIXED Could you give an example of such a conflict? (I wonder how it's avoided with current solution.) Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller ` (3 preceding siblings ...) 2008-06-11 13:14 ` Jarek Poplawski @ 2008-06-12 5:46 ` David Miller 2008-06-12 7:20 ` Johannes Berg 2008-06-12 6:13 ` Jarek Poplawski 5 siblings, 1 reply; 28+ messages in thread From: David Miller @ 2008-06-12 5:46 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: David Miller <davem@davemloft.net> Date: Tue, 10 Jun 2008 22:40:23 -0700 (PDT) > I'm attempting to bring solving this problem back from the dead. Here is my current patch with a proper changelog. Any objections to my pushing this to Linus? net: Eliminate flush_scheduled_work() calls while RTNL is held. If the RTNL is held when we invoke flush_scheduled_work() we could deadlock. One such case is linkwatch, it is a workqueue which tries to grab the RTNL semaphore. The most common case are net driver ->stop() methods. The simplest conversion is to instead use cancel_{delayed_}work_sync() explicitly on the various workqueues the driver uses. This is an OK transformation because these workqueues are doing things like resetting the chip, restarting link negotiation, and so forth. And if we're bringing down the device, we're about to turn the chip off and reset it anways. So if we cancel a pending work event, that's fine here. Some drivers were working around this deadlock by using a msleep() polling loop of some sort, and those cases are converted to instead use cancel_{delayed_}work_sync() as well. Signed-off-by: David S. Miller <davem@davemloft.net> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4b46e68..48ed410 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5907,12 +5907,7 @@ bnx2_close(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 reset_code; - /* Calling flush_scheduled_work() may deadlock because - * linkwatch_event() may be on the workqueue and it will try to get - * the rtnl_lock which we are holding. - */ - while (bp->in_reset_task) - msleep(1); + cancel_work_sync(&bp->reset_task); bnx2_disable_int_sync(bp); bnx2_napi_disable(bp); diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index faae01d..075fd54 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2605,7 +2605,8 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_scheduled_work(); + cancel_work_sync(&port->reset_task); + mutex_lock(&port->port_lock); netif_stop_queue(dev); port_napi_disable(port); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index dde9c7e..00bc7fb 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -959,7 +959,7 @@ static int epp_close(struct net_device *dev) unsigned char tmp[1]; bc->work_running = 0; - flush_scheduled_work(); + cancel_delayed_work_sync(&bc->run_work); bc->stat = EPP_DCDBIT; tmp[0] = 0; pp->ops->epp_write_addr(pp, tmp, 1, 0); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4e28002..5c71098 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1531,16 +1531,8 @@ static int smc911x_close(struct net_device *dev) if (lp->phy_type != 0) { /* We need to ensure that no calls to * smc911x_phy_configure are pending. - - * flush_scheduled_work() cannot be called because we - * are running with the netlink semaphore held (from - * devinet_ioctl()) and the pending work queue - * contains linkwatch_event() (scheduled by - * netif_carrier_off() above). linkwatch_event() also - * wants the netlink semaphore. */ - while (lp->work_pending) - schedule(); + cancel_work_sync(&lp->phy_configure); smc911x_phy_powerdown(dev, lp->mii.phy_id); } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index a188e33..5dbe4d3 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev) /* We need to ensure that no calls to smc_phy_configure are pending. - - flush_scheduled_work() cannot be called because we are - running with the netlink semaphore held (from - devinet_ioctl()) and the pending work queue contains - linkwatch_event() (scheduled by netif_carrier_off() - above). linkwatch_event() also wants the netlink semaphore. */ - while(lp->work_pending) - yield(); + cancel_work_sync(&lp->phy_configure); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 55670b5..af8d2c4 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -731,7 +731,7 @@ static void tulip_down (struct net_device *dev) void __iomem *ioaddr = tp->base_addr; unsigned long flags; - flush_scheduled_work(); + cancel_work_sync(&tp->media_work); #ifdef CONFIG_TULIP_NAPI napi_disable(&tp->napi); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 0dcfc03..7c66b05 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -706,7 +706,7 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); - flush_scheduled_work(); + cancel_delayed_work_sync(&kaweth->lowmem_work); /* a scheduled work may have resubmitted, we hit them again */ diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 20d387f..57b800f 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -682,7 +682,11 @@ static int prism2_close(struct net_device *dev) netif_device_detach(dev); } - flush_scheduled_work(); + cancel_work_sync(&local->reset_queue); + cancel_work_sync(&local->set_multicast_list_queue); + cancel_work_sync(&local->set_tim_queue); + cancel_work_sync(&local->info_queue); + cancel_work_sync(&local->comms_qual_update); module_put(local->hw_module); ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-12 5:46 ` David Miller @ 2008-06-12 7:20 ` Johannes Berg 2008-06-12 8:23 ` David Miller 0 siblings, 1 reply; 28+ messages in thread From: Johannes Berg @ 2008-06-12 7:20 UTC (permalink / raw) To: David Miller; +Cc: davej, netdev [-- Attachment #1: Type: text/plain, Size: 848 bytes --] Technically, > If the RTNL is held when we invoke flush_scheduled_work() we could > deadlock. One such case is linkwatch, it is a workqueue which tries that ^^^^^^^^^ > The most common case are net driver ->stop() methods. The > simplest conversion is to instead use cancel_{delayed_}work_sync() > explicitly on the various workqueues the driver uses. and that ^^^^^^^^^^ > This is an OK transformation because these workqueues are doing things and that ^^^^^^^^^^ should read "work struct" because it all uses the global workqueue. I haven't looked at the drivers in more detail (sorry) but the patch itself looks fine to me (but I wouldn't have caught something like Jarek did with the now-unused variables.) johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 836 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-12 7:20 ` Johannes Berg @ 2008-06-12 8:23 ` David Miller 0 siblings, 0 replies; 28+ messages in thread From: David Miller @ 2008-06-12 8:23 UTC (permalink / raw) To: johannes; +Cc: davej, netdev From: Johannes Berg <johannes@sipsolutions.net> Date: Thu, 12 Jun 2008 09:20:34 +0200 > > If the RTNL is held when we invoke flush_scheduled_work() we could > > deadlock. One such case is linkwatch, it is a workqueue which tries > that ^^^^^^^^^ > > > The most common case are net driver ->stop() methods. The > > simplest conversion is to instead use cancel_{delayed_}work_sync() > > explicitly on the various workqueues the driver uses. > and that ^^^^^^^^^^ > > > This is an OK transformation because these workqueues are doing things > and that ^^^^^^^^^^ > > should read "work struct" because it all uses the global workqueue. > > I haven't looked at the drivers in more detail (sorry) but the patch > itself looks fine to me (but I wouldn't have caught something like Jarek > did with the now-unused variables.) I've made those corrections to the commit message, thanks for the feedback. Since Jarek appears to be happy with the patch at this point I'll commit this and sned it to Linus in my next push of bug fixes. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-11 5:40 ` David Miller ` (4 preceding siblings ...) 2008-06-12 5:46 ` David Miller @ 2008-06-12 6:13 ` Jarek Poplawski 2008-06-12 7:01 ` David Miller 5 siblings, 1 reply; 28+ messages in thread From: Jarek Poplawski @ 2008-06-12 6:13 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On 11-06-2008 07:40, David Miller wrote: ... > diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c > index 4b46e68..48ed410 100644 > --- a/drivers/net/bnx2.c > +++ b/drivers/net/bnx2.c > @@ -5907,12 +5907,7 @@ bnx2_close(struct net_device *dev) > struct bnx2 *bp = netdev_priv(dev); > u32 reset_code; > > - /* Calling flush_scheduled_work() may deadlock because > - * linkwatch_event() may be on the workqueue and it will try to get > - * the rtnl_lock which we are holding. > - */ > - while (bp->in_reset_task) > - msleep(1); > + cancel_work_sync(&bp->reset_task); It seems after this change bp->in_reset_task could be removed totally from the code. ... > diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c > index 4e28002..5c71098 100644 > --- a/drivers/net/smc911x.c > +++ b/drivers/net/smc911x.c > @@ -1531,16 +1531,8 @@ static int smc911x_close(struct net_device *dev) > if (lp->phy_type != 0) { > /* We need to ensure that no calls to > * smc911x_phy_configure are pending. > - > - * flush_scheduled_work() cannot be called because we > - * are running with the netlink semaphore held (from > - * devinet_ioctl()) and the pending work queue > - * contains linkwatch_event() (scheduled by > - * netif_carrier_off() above). linkwatch_event() also > - * wants the netlink semaphore. > */ > - while (lp->work_pending) > - schedule(); > + cancel_work_sync(&lp->phy_configure); ... likewise lp->work_pending, > smc911x_phy_powerdown(dev, lp->mii.phy_id); > } > > diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c > index a188e33..5dbe4d3 100644 > --- a/drivers/net/smc91x.c > +++ b/drivers/net/smc91x.c > @@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev) > > /* We need to ensure that no calls to smc_phy_configure are > pending. > - > - flush_scheduled_work() cannot be called because we are > - running with the netlink semaphore held (from > - devinet_ioctl()) and the pending work queue contains > - linkwatch_event() (scheduled by netif_carrier_off() > - above). linkwatch_event() also wants the netlink semaphore. > */ > - while(lp->work_pending) > - yield(); > + cancel_work_sync(&lp->phy_configure); ... likewise lp->work_pending. ... > diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c > index 20d387f..57b800f 100644 > --- a/drivers/net/wireless/hostap/hostap_main.c > +++ b/drivers/net/wireless/hostap/hostap_main.c > @@ -682,7 +682,11 @@ static int prism2_close(struct net_device *dev) > netif_device_detach(dev); > } > > - flush_scheduled_work(); > + cancel_work_sync(&local->reset_queue); > + cancel_work_sync(&local->set_multicast_list_queue); > + cancel_work_sync(&local->set_tim_queue); > + cancel_work_sync(&local->info_queue); local->info_queue probably needs some #ifndef like in hostap_info_init() or could be skipped here at all (waiting for remove). > + cancel_work_sync(&local->comms_qual_update); > > module_put(local->hw_module); Regards, Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-12 6:13 ` Jarek Poplawski @ 2008-06-12 7:01 ` David Miller 2008-06-12 7:47 ` Jarek Poplawski 0 siblings, 1 reply; 28+ messages in thread From: David Miller @ 2008-06-12 7:01 UTC (permalink / raw) To: jarkao2; +Cc: johannes, davej, netdev From: Jarek Poplawski <jarkao2@gmail.com> Date: Thu, 12 Jun 2008 06:13:34 +0000 > It seems after this change bp->in_reset_task could be removed totally > from the code. ... > ... likewise lp->work_pending, ... > ... likewise lp->work_pending. ... > local->info_queue probably needs some #ifndef like in hostap_info_init() > or could be skipped here at all (waiting for remove). Thanks for the feedback, here's a new patch with your suggestions added. net: Eliminate flush_scheduled_work() calls while RTNL is held. If the RTNL is held when we invoke flush_scheduled_work() we could deadlock. One such case is linkwatch, it is a workqueue which tries to grab the RTNL semaphore. The most common case are net driver ->stop() methods. The simplest conversion is to instead use cancel_{delayed_}work_sync() explicitly on the various workqueues the driver uses. This is an OK transformation because these workqueues are doing things like resetting the chip, restarting link negotiation, and so forth. And if we're bringing down the device, we're about to turn the chip off and reset it anways. So if we cancel a pending work event, that's fine here. Some drivers were working around this deadlock by using a msleep() polling loop of some sort, and those cases are converted to instead use cancel_{delayed_}work_sync() as well. Signed-off-by: David S. Miller <davem@davemloft.net> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4b46e68..367b6d4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5724,14 +5724,12 @@ bnx2_reset_task(struct work_struct *work) if (!netif_running(bp->dev)) return; - bp->in_reset_task = 1; bnx2_netif_stop(bp); bnx2_init_nic(bp); atomic_set(&bp->intr_sem, 1); bnx2_netif_start(bp); - bp->in_reset_task = 0; } static void @@ -5907,12 +5905,7 @@ bnx2_close(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 reset_code; - /* Calling flush_scheduled_work() may deadlock because - * linkwatch_event() may be on the workqueue and it will try to get - * the rtnl_lock which we are holding. - */ - while (bp->in_reset_task) - msleep(1); + cancel_work_sync(&bp->reset_task); bnx2_disable_int_sync(bp); bnx2_napi_disable(bp); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 1eaf5bb..2377cc1 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6656,7 +6656,6 @@ struct bnx2 { int current_interval; struct timer_list timer; struct work_struct reset_task; - int in_reset_task; /* Used to synchronize phy accesses. */ spinlock_t phy_lock; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index faae01d..075fd54 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2605,7 +2605,8 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_scheduled_work(); + cancel_work_sync(&port->reset_task); + mutex_lock(&port->port_lock); netif_stop_queue(dev); port_napi_disable(port); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index dde9c7e..00bc7fb 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -959,7 +959,7 @@ static int epp_close(struct net_device *dev) unsigned char tmp[1]; bc->work_running = 0; - flush_scheduled_work(); + cancel_delayed_work_sync(&bc->run_work); bc->stat = EPP_DCDBIT; tmp[0] = 0; pp->ops->epp_write_addr(pp, tmp, 1, 0); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4e28002..e2ee91a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -136,7 +136,6 @@ struct smc911x_local { /* work queue */ struct work_struct phy_configure; - int work_pending; int tx_throttle; spinlock_t lock; @@ -960,11 +959,11 @@ static void smc911x_phy_configure(struct work_struct *work) * We should not be called if phy_type is zero. */ if (lp->phy_type == 0) - goto smc911x_phy_configure_exit_nolock; + return; if (smc911x_phy_reset(dev, phyaddr)) { printk("%s: PHY reset timed out\n", dev->name); - goto smc911x_phy_configure_exit_nolock; + return; } spin_lock_irqsave(&lp->lock, flags); @@ -1033,8 +1032,6 @@ static void smc911x_phy_configure(struct work_struct *work) smc911x_phy_configure_exit: spin_unlock_irqrestore(&lp->lock, flags); -smc911x_phy_configure_exit_nolock: - lp->work_pending = 0; } /* @@ -1356,11 +1353,8 @@ static void smc911x_timeout(struct net_device *dev) * smc911x_phy_configure() calls msleep() which calls schedule_timeout() * which calls schedule(). Hence we use a work queue. */ - if (lp->phy_type != 0) { - if (schedule_work(&lp->phy_configure)) { - lp->work_pending = 1; - } - } + if (lp->phy_type != 0) + schedule_work(&lp->phy_configure); /* We can accept TX packets again */ dev->trans_start = jiffies; @@ -1531,16 +1525,8 @@ static int smc911x_close(struct net_device *dev) if (lp->phy_type != 0) { /* We need to ensure that no calls to * smc911x_phy_configure are pending. - - * flush_scheduled_work() cannot be called because we - * are running with the netlink semaphore held (from - * devinet_ioctl()) and the pending work queue - * contains linkwatch_event() (scheduled by - * netif_carrier_off() above). linkwatch_event() also - * wants the netlink semaphore. */ - while (lp->work_pending) - schedule(); + cancel_work_sync(&lp->phy_configure); smc911x_phy_powerdown(dev, lp->mii.phy_id); } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index a188e33..f2051b2 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev) /* We need to ensure that no calls to smc_phy_configure are pending. - - flush_scheduled_work() cannot be called because we are - running with the netlink semaphore held (from - devinet_ioctl()) and the pending work queue contains - linkwatch_event() (scheduled by netif_carrier_off() - above). linkwatch_event() also wants the netlink semaphore. */ - while(lp->work_pending) - yield(); + cancel_work_sync(&lp->phy_configure); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); @@ -1161,7 +1154,6 @@ static void smc_phy_configure(struct work_struct *work) smc_phy_configure_exit: SMC_SELECT_BANK(lp, 2); spin_unlock_irq(&lp->lock); - lp->work_pending = 0; } /* @@ -1389,11 +1381,8 @@ static void smc_timeout(struct net_device *dev) * smc_phy_configure() calls msleep() which calls schedule_timeout() * which calls schedule(). Hence we use a work queue. */ - if (lp->phy_type != 0) { - if (schedule_work(&lp->phy_configure)) { - lp->work_pending = 1; - } - } + if (lp->phy_type != 0) + schedule_work(&lp->phy_configure); /* We can accept TX packets again */ dev->trans_start = jiffies; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 55670b5..af8d2c4 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -731,7 +731,7 @@ static void tulip_down (struct net_device *dev) void __iomem *ioaddr = tp->base_addr; unsigned long flags; - flush_scheduled_work(); + cancel_work_sync(&tp->media_work); #ifdef CONFIG_TULIP_NAPI napi_disable(&tp->napi); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 0dcfc03..7c66b05 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -706,7 +706,7 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); - flush_scheduled_work(); + cancel_delayed_work_sync(&kaweth->lowmem_work); /* a scheduled work may have resubmitted, we hit them again */ diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 20d387f..f7aec93 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -682,7 +682,13 @@ static int prism2_close(struct net_device *dev) netif_device_detach(dev); } - flush_scheduled_work(); + cancel_work_sync(&local->reset_queue); + cancel_work_sync(&local->set_multicast_list_queue); + cancel_work_sync(&local->set_tim_queue); +#ifndef PRISM2_NO_STATION_MODES + cancel_work_sync(&local->info_queue); +#endif + cancel_work_sync(&local->comms_qual_update); module_put(local->hw_module); ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: 2.6.25rc7 lockdep trace 2008-06-12 7:01 ` David Miller @ 2008-06-12 7:47 ` Jarek Poplawski 0 siblings, 0 replies; 28+ messages in thread From: Jarek Poplawski @ 2008-06-12 7:47 UTC (permalink / raw) To: David Miller; +Cc: johannes, davej, netdev On Thu, Jun 12, 2008 at 12:01:53AM -0700, David Miller wrote: ... > net: Eliminate flush_scheduled_work() calls while RTNL is held. > ... Very nice! BTW, I guess this cassini fix with direct calling the work function (and maybe moving flush_ after unregister_netdev() in 8139too, like in a few other places) could be re-considered here as well. Jarek P. ^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2008-06-12 8:23 UTC | newest] Thread overview: 28+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-03-28 0:00 2.6.25rc7 lockdep trace Dave Jones 2008-03-28 1:55 ` Dave Jones 2008-03-29 0:34 ` David Miller 2008-03-29 0:54 ` Johannes Berg 2008-03-29 1:01 ` Johannes Berg 2008-03-29 1:09 ` David Miller 2008-04-02 8:51 ` Oleg Nesterov 2008-03-29 1:06 ` David Miller 2008-03-29 10:02 ` Johannes Berg 2008-03-29 12:52 ` Jarek Poplawski 2008-03-29 12:50 ` Johannes Berg 2008-04-03 20:48 ` David Miller 2008-04-04 14:48 ` Johannes Berg 2008-06-11 5:40 ` David Miller 2008-06-11 7:08 ` Jarek Poplawski 2008-06-11 7:10 ` David Miller 2008-06-11 9:36 ` Jarek Poplawski 2008-06-12 0:34 ` David Miller 2008-06-12 6:29 ` Jarek Poplawski 2008-06-11 10:40 ` Jarek Poplawski 2008-06-12 0:31 ` David Miller 2008-06-11 13:14 ` Jarek Poplawski 2008-06-12 5:46 ` David Miller 2008-06-12 7:20 ` Johannes Berg 2008-06-12 8:23 ` David Miller 2008-06-12 6:13 ` Jarek Poplawski 2008-06-12 7:01 ` David Miller 2008-06-12 7:47 ` Jarek Poplawski
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).