| From c52232a49e203a65a6e1a670cd5262f59e9364a0 Mon Sep 17 00:00:00 2001 |
| From: Lingutla Chandrasekhar <clingutla@codeaurora.org> |
| Date: Thu, 18 Jan 2018 17:20:22 +0530 |
| Subject: timers: Forward timer base before migrating timers |
| |
| From: Lingutla Chandrasekhar <clingutla@codeaurora.org> |
| |
| commit c52232a49e203a65a6e1a670cd5262f59e9364a0 upstream. |
| |
| 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: a683f390b93f ("timers: Forward the wheel clock whenever possible") |
| Co-developed-by: Neeraj Upadhyay <neeraju@codeaurora.org> |
| Signed-off-by: Neeraj Upadhyay <neeraju@codeaurora.org> |
| Signed-off-by: Lingutla Chandrasekhar <clingutla@codeaurora.org> |
| Signed-off-by: Thomas 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 |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/time/timer.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/kernel/time/timer.c |
| +++ b/kernel/time/timer.c |
| @@ -1834,6 +1834,12 @@ int timers_dead_cpu(unsigned int cpu) |
| raw_spin_lock_irq(&new_base->lock); |
| raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); |
| |
| + /* |
| + * The current CPUs base clock might be stale. Update it |
| + * before moving the timers over. |
| + */ |
| + forward_timer_base(new_base); |
| + |
| BUG_ON(old_base->running_timer); |
| |
| for (i = 0; i < WHEEL_SIZE; i++) |