diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2011-02-08 12:39:54 -0500 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2011-02-16 13:35:08 +0100 | 
| commit | 48228f7b470a74b6469a250d2977a13128d8fe96 (patch) | |
| tree | 1ed8f82ffef779ccf665f68c1fcf302d34d09826 | |
| parent | a3ec4a603faf4244e275bf11b467aad092dfbd8a (diff) | |
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: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1297186794.23343.19.camel@gandalf.stny.rr.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | kernel/timer.c | 23 | 
1 files changed, 23 insertions, 0 deletions
| diff --git a/kernel/timer.c b/kernel/timer.c index d6459923d24..5f40c2e0a94 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -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   * 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.   */  int del_timer_sync(struct timer_list *timer) @@ -971,6 +990,10 @@ int del_timer_sync(struct timer_list *timer)  #ifdef CONFIG_LOCKDEP  	unsigned long flags; +	/* +	 * If lockdep gives a backtrace here, please reference +	 * the synchronization rules above. +	 */  	local_irq_save(flags);  	lock_map_acquire(&timer->lockdep_map);  	lock_map_release(&timer->lockdep_map); | 
