lkml.org 
[lkml]   [2011]   [Feb]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip:core/locking] lockdep/timers: Explain in detail the locking problems del_timer_sync() may cause
    Commit-ID:  48228f7b470a74b6469a250d2977a13128d8fe96
    Gitweb: http://git.kernel.org/tip/48228f7b470a74b6469a250d2977a13128d8fe96
    Author: Steven Rostedt <rostedt@goodmis.org>
    AuthorDate: Tue, 8 Feb 2011 12:39:54 -0500
    Committer: Ingo Molnar <mingo@elte.hu>
    CommitDate: Wed, 16 Feb 2011 13:35:08 +0100

    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>
    ---
    kernel/timer.c | 23 +++++++++++++++++++++++
    1 files changed, 23 insertions(+), 0 deletions(-)

    diff --git a/kernel/timer.c b/kernel/timer.c
    index d645992..5f40c2e 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);

    \
     
     \ /
      Last update: 2011-02-16 14:53    [W:0.025 / U:30.364 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site