| From 012a45e3f4af68e86d85cce060c6c2fed56498b2 Mon Sep 17 00:00:00 2001 |
| From: Leon Ma <xindong.ma@intel.com> |
| Date: Wed, 30 Apr 2014 16:43:10 +0800 |
| Subject: hrtimer: Prevent remote enqueue of leftmost timers |
| |
| From: Leon Ma <xindong.ma@intel.com> |
| |
| commit 012a45e3f4af68e86d85cce060c6c2fed56498b2 upstream. |
| |
| If a cpu is idle and starts an hrtimer which is not pinned on that |
| same cpu, the nohz code might target the timer to a different cpu. |
| |
| In the case that we switch the cpu base of the timer we already have a |
| sanity check in place, which determines whether the timer is earlier |
| than the current leftmost timer on the target cpu. In that case we |
| enqueue the timer on the current cpu because we cannot reprogram the |
| clock event device on the target. |
| |
| If the timers base is already the target CPU we do not have this |
| sanity check in place so we enqueue the timer as the leftmost timer in |
| the target cpus rb tree, but we cannot reprogram the clock event |
| device on the target cpu. So the timer expires late and subsequently |
| prevents the reprogramming of the target cpu clock event device until |
| the previously programmed event fires or a timer with an earlier |
| expiry time gets enqueued on the target cpu itself. |
| |
| Add the same target check as we have for the switch base case and |
| start the timer on the current cpu if it would become the leftmost |
| timer on the target. |
| |
| [ tglx: Rewrote subject and changelog ] |
| |
| Signed-off-by: Leon Ma <xindong.ma@intel.com> |
| Link: http://lkml.kernel.org/r/1398847391-5994-1-git-send-email-xindong.ma@intel.com |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/hrtimer.c | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/kernel/hrtimer.c |
| +++ b/kernel/hrtimer.c |
| @@ -245,6 +245,11 @@ again: |
| goto again; |
| } |
| timer->base = new_base; |
| + } else { |
| + if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) { |
| + cpu = this_cpu; |
| + goto again; |
| + } |
| } |
| return new_base; |
| } |