diff options
Diffstat (limited to 'kernel/timer.c')
| -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 33a67925d90..3503c17ac1d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -970,6 +970,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) @@ -977,6 +996,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);  |