Skip to content
  • Thomas Gleixner's avatar
    hrtimer: Prevent stale expiry time in hrtimer_interrupt() · 9bc74919
    Thomas Gleixner authored
    
    
    hrtimer_interrupt() has the following subtle issue:
    
    hrtimer_interrupt()
      lock(cpu_base);
      expires_next = KTIME_MAX;
    
      expire_timers(CLOCK_MONOTONIC);
      expires = get_next_timer(CLOCK_MONOTONIC);
      if (expires < expires_next)
        expires_next = expires;
    
      expire_timers(CLOCK_REALTIME);
        unlock(cpu_base);
        wakeup()
        hrtimer_start(CLOCK_MONOTONIC, newtimer);
        lock(cpu_base();  
      expires = get_next_timer(CLOCK_REALTIME);
      if (expires < expires_next)
        expires_next = expires;
    
    So because we already evaluated the next expiring timer of
    CLOCK_MONOTONIC we ignore that the expiry time of newtimer might be
    earlier than the overall next expiry time in hrtimer_interrupt().
    
    To solve this, remove the caching of the next expiry value from
    hrtimer_interrupt() and reevaluate all active clock bases for the next
    expiry value. To avoid another code duplication, create a shared
    evaluation function and use it for hrtimer_get_next_event(),
    hrtimer_force_reprogram() and hrtimer_interrupt().
    
    There is another subtlety in this mechanism:
    
    While hrtimer_interrupt() is running, we want to avoid to touch the
    hardware device because we will reprogram it anyway at the end of
    hrtimer_interrupt(). This works nicely for hrtimers which get rearmed
    via the HRTIMER_RESTART mechanism, because we drop out when the
    callback on that CPU is running. But that fails, if a new timer gets
    enqueued like in the example above.
    
    This has another implication: While hrtimer_interrupt() is running we
    refuse remote enqueueing of timers - see hrtimer_interrupt() and
    hrtimer_check_target().
    
    hrtimer_interrupt() tries to prevent this by setting cpu_base->expires
    to KTIME_MAX, but that fails if a new timer gets queued.
    
    Prevent both the hardware access and the remote enqueue
    explicitely. We can loosen the restriction on the remote enqueue now
    due to reevaluation of the next expiry value, but that needs a
    seperate patch.
    
    Folded in a fix from Vignesh Radhakrishnan.
    
    Reported-and-tested-by: default avatarStanislav Fomichev <stfomichev@yandex-team.ru>
    Based-on-patch-by: default avatarStanislav Fomichev <stfomichev@yandex-team.ru>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Cc: vigneshr@codeaurora.org
    Cc: john.stultz@linaro.org
    Cc: viresh.kumar@linaro.org
    Cc: fweisbec@gmail.com
    Cc: cl@linux.com
    Cc: stuart.w.hayes@gmail.com
    Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1501202049190.5526@nanos
    
    
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    9bc74919