lkml.org 
[lkml]   [2010]   [Oct]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[27/66] hrtimer: Preserve timer state in remove_hrtimer()
    2.6.32-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Salman Qazi <sqazi@google.com>

    commit f13d4f979c518119bba5439dd2364d76d31dcd3f upstream.

    The race is described as follows:

    CPU X CPU Y
    remove_hrtimer
    // state & QUEUED == 0
    timer->state = CALLBACK
    unlock timer base
    timer->f(n) //very long
    hrtimer_start
    lock timer base
    remove_hrtimer // no effect
    hrtimer_enqueue
    timer->state = CALLBACK |
    QUEUED
    unlock timer base
    hrtimer_start
    lock timer base
    remove_hrtimer
    mode = INACTIVE
    // CALLBACK bit lost!
    switch_hrtimer_base
    CALLBACK bit not set:
    timer->base
    changes to a
    different CPU.
    lock this CPU's timer base

    The bug was introduced with commit ca109491f (hrtimer: removing all ur
    callback modes) in 2.6.29

    [ tglx: Feed new state via local variable and add a comment. ]

    Signed-off-by: Salman Qazi <sqazi@google.com>
    Cc: akpm@linux-foundation.org
    Cc: Peter Zijlstra <peterz@infradead.org>
    LKML-Reference: <20101012142351.8485.21823.stgit@dungbeetle.mtv.corp.google.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    kernel/hrtimer.c | 13 +++++++++++--
    1 file changed, 11 insertions(+), 2 deletions(-)

    --- a/kernel/hrtimer.c
    +++ b/kernel/hrtimer.c
    @@ -920,6 +920,7 @@ static inline int
    remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
    {
    if (hrtimer_is_queued(timer)) {
    + unsigned long state;
    int reprogram;

    /*
    @@ -933,8 +934,13 @@ remove_hrtimer(struct hrtimer *timer, st
    debug_deactivate(timer);
    timer_stats_hrtimer_clear_start_info(timer);
    reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
    - __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE,
    - reprogram);
    + /*
    + * We must preserve the CALLBACK state flag here,
    + * otherwise we could move the timer base in
    + * switch_hrtimer_base.
    + */
    + state = timer->state & HRTIMER_STATE_CALLBACK;
    + __remove_hrtimer(timer, base, state, reprogram);
    return 1;
    }
    return 0;
    @@ -1221,6 +1227,9 @@ static void __run_hrtimer(struct hrtimer
    BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
    enqueue_hrtimer(timer, base);
    }
    +
    + WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
    +
    timer->state &= ~HRTIMER_STATE_CALLBACK;
    }




    \
     
     \ /
      Last update: 2010-10-22 20:53    [W:0.023 / U:1.964 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site