• Anna-Maria Behnsen's avatar
    hrtimer: Update softirq_expires_next correctly after __hrtimer_get_next_event() · 46eb1701
    Anna-Maria Behnsen authored
    hrtimer_force_reprogram() and hrtimer_interrupt() invokes
    __hrtimer_get_next_event() to find the earliest expiry time of hrtimer
    bases. __hrtimer_get_next_event() does not update
    cpu_base::[softirq_]_expires_next to preserve reprogramming logic. That
    needs to be done at the callsites.
    
    hrtimer_force_reprogram() updates cpu_base::softirq_expires_next only when
    the first expiring timer is a softirq timer and the soft interrupt is not
    activated. That's wrong because cpu_base::softirq_expires_next is left
    stale when the first expiring timer of all bases is a timer which expires
    in hard interrupt context. hrtimer_interrupt() does never update
    cpu_base::softirq_expires_next which is wrong too.
    
    That becomes a problem when clock_settime() sets CLOCK_REALTIME forward and
    the first soft expiring timer is in the CLOCK_REALTIME_SOFT base. Setting
    CLOCK_REALTIME forward moves the clock MONOTONIC based expiry time of that
    timer before the stale cpu_base::softirq_expires_next.
    
    cpu_base::softirq_expires_next is cached to make the check for raising the
    soft interrupt fast. In the above case the soft interrupt won't be raised
    until clock monotonic reaches the stale cpu_base::softirq_expires_next
    value. That's incorrect, but what's worse it that if the softirq timer
    becomes the first expiring timer of all clock bases after the hard expiry
    timer has been handled the reprogramming of the clockevent from
    hrtimer_interrupt() will result in an interrupt storm. That happens because
    the reprogramming does not use cpu_base::softirq_expires_next, it uses
    __hrtimer_get_next_event() which returns the actual expiry time. Once clock
    MONOTONIC reaches cpu_base::softirq_expires_next the soft interrupt is
    raised and the storm subsides.
    
    Change the logic in hrtimer_force_reprogram() to evaluate the soft and hard
    bases seperately, update softirq_expires_next and handle the case when a
    soft expiring timer is the first of all bases by comparing the expiry times
    and updating the required cpu base fields. Split this functionality into a
    separate function to be able to use it in hrtimer_interrupt() as well
    without copy paste.
    
    Fixes: 5da70160 ("hrtimer: Implement support for softirq based hrtimers")
    Reported-by: default avatarMikael Beckius <mikael.beckius@windriver.com>
    Suggested-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Tested-by: default avatarMikael Beckius <mikael.beckius@windriver.com>
    Signed-off-by: default avatarAnna-Maria Behnsen <anna-maria@linutronix.de>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
    Link: https://lore.kernel.org/r/20210223160240.27518-1-anna-maria@linutronix.de
    46eb1701
hrtimer.c 61.3 KB