• Lingutla Chandrasekhar's avatar
    timers: Forward timer base before migrating timers · c52232a4
    Lingutla Chandrasekhar authored
    On CPU hotunplug the enqueued timers of the unplugged CPU are migrated to a
    live CPU. This happens from the control thread which initiated the unplug.
    
    If the CPU on which the control thread runs came out from a longer idle
    period then the base clock of that CPU might be stale because the control
    thread runs prior to any event which forwards the clock.
    
    In such a case the timers from the unplugged CPU are queued on the live CPU
    based on the stale clock which can cause large delays due to increased
    granularity of the outer timer wheels which are far away from base:;clock.
    
    But there is a worse problem than that. The following sequence of events
    illustrates it:
    
     - CPU0 timer1 is queued expires = 59969 and base->clk = 59131.
    
       The timer is queued at wheel level 2, with resulting expiry time = 60032
       (due to level granularity).
    
     - CPU1 enters idle @60007, with next timer expiry @60020.
    
     - CPU0 is hotplugged at @60009
    
     - CPU1 exits idle and runs the control thread which migrates the
       timers from CPU0
    
       timer1 is now queued in level 0 for immediate handling in the next
       softirq because the requested expiry time 59969 is before CPU1 base->clk
       60007
    
     - CPU1 runs code which forwards the base clock which succeeds because the
       next expiring timer. which was collected at idle entry time is still set
       to 60020.
    
       So it forwards beyond 60007 and therefore misses to expire the migrated
       timer1. That timer gets expired when the wheel wraps around again, which
       takes between 63 and 630ms depending on the HZ setting.
    
    Address both problems by invoking forward_timer_base() for the control CPUs
    timer base. All other places, which might run into a similar problem
    (mod_timer()/add_timer_on()) already invoke forward_timer_base() to avoid
    that.
    
    [ tglx: Massaged comment and changelog ]
    
    Fixes: a683f390 ("timers: Forward the wheel clock whenever possible")
    Co-developed-by: default avatarNeeraj Upadhyay <neeraju@codeaurora.org>
    Signed-off-by: default avatarNeeraj Upadhyay <neeraju@codeaurora.org>
    Signed-off-by: default avatarLingutla Chandrasekhar <clingutla@codeaurora.org>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Cc: Anna-Maria Gleixner <anna-maria@linutronix.de>
    Cc: linux-arm-msm@vger.kernel.org
    Cc: stable@vger.kernel.org
    Link: https://lkml.kernel.org/r/20180118115022.6368-1-clingutla@codeaurora.org
    c52232a4
timer.c 56.7 KB