Commit 48228f7b authored by Steven Rostedt's avatar Steven Rostedt Committed by Ingo Molnar

lockdep/timers: Explain in detail the locking problems del_timer_sync() may cause

Twice I had to explain the output about why lockdep gives an error with
locks in IRQ context and with del_timer_sync(). Might as well write it
up and place it in the comments above the code in del_timer_sync().
Perhaps the next time this lockdep dump triggers people will understand
the issues.

It is a ticky issue and very subtle, explaining it in detail in the code
may help others understand the issue when they stumble upon the bug
again.
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1297186794.23343.19.camel@gandalf.stny.rr.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent a3ec4a60
...@@ -964,6 +964,25 @@ EXPORT_SYMBOL(try_to_del_timer_sync); ...@@ -964,6 +964,25 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
* add_timer_on(). Upon exit the timer is not queued and the handler is * add_timer_on(). Upon exit the timer is not queued and the handler is
* not running on any CPU. * not running on any CPU.
* *
* Note: You must not hold locks that are held in interrupt context
* while calling this function. Even if the lock has nothing to do
* with the timer in question. Here's why:
*
* CPU0 CPU1
* ---- ----
* <SOFTIRQ>
* call_timer_fn();
* base->running_timer = mytimer;
* spin_lock_irq(somelock);
* <IRQ>
* spin_lock(somelock);
* del_timer_sync(mytimer);
* while (base->running_timer == mytimer);
*
* Now del_timer_sync() will never return and never release somelock.
* The interrupt on the other CPU is waiting to grab somelock but
* it has interrupted the softirq that CPU0 is waiting to finish.
*
* The function returns whether it has deactivated a pending timer or not. * The function returns whether it has deactivated a pending timer or not.
*/ */
int del_timer_sync(struct timer_list *timer) int del_timer_sync(struct timer_list *timer)
...@@ -971,6 +990,10 @@ int del_timer_sync(struct timer_list *timer) ...@@ -971,6 +990,10 @@ int del_timer_sync(struct timer_list *timer)
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
unsigned long flags; unsigned long flags;
/*
* If lockdep gives a backtrace here, please reference
* the synchronization rules above.
*/
local_irq_save(flags); local_irq_save(flags);
lock_map_acquire(&timer->lockdep_map); lock_map_acquire(&timer->lockdep_map);
lock_map_release(&timer->lockdep_map); lock_map_release(&timer->lockdep_map);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment