diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2013-07-05 06:09:18 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-28 19:30:22 -0400 |
| commit | 2d06fa0f825ec1d7943a3bcceecbd85aa82ef27d (patch) | |
| tree | a94823276431964d5c6de69a386bfb74aa8dcadf /kernel | |
| parent | c4d98e2535e0269fcd513cbb79e937ef3ccc3d01 (diff) | |
hrtimers: Move SMP function call to thread context
commit 5ec2481b7b47a4005bb446d176e5d0257400c77d upstream.
smp_call_function_* must not be called from softirq context.
But clock_was_set() which calls on_each_cpu() is called from softirq
context to implement a delayed clock_was_set() for the timer interrupt
handler. Though that almost never gets invoked. A recent change in the
resume code uses the softirq based delayed clock_was_set to support
Xens resume mechanism.
linux-next contains a new warning which warns if smp_call_function_*
is called from softirq context which gets triggered by that Xen
change.
Fix this by moving the delayed clock_was_set() call to a work context.
Reported-and-tested-by: Artem Savkov <artem.savkov@gmail.com>
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: H. Peter Anvin <hpa@zytor.com>,
Cc: Konrad Wilk <konrad.wilk@oracle.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: xen-devel@lists.xen.org
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/hrtimer.c | 28 |
1 files changed, 13 insertions, 15 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index fd4b13b131f8..2288fbdada16 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
| @@ -721,17 +721,20 @@ static int hrtimer_switch_to_hres(void) | |||
| 721 | return 1; | 721 | return 1; |
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | static void clock_was_set_work(struct work_struct *work) | ||
| 725 | { | ||
| 726 | clock_was_set(); | ||
| 727 | } | ||
| 728 | |||
| 729 | static DECLARE_WORK(hrtimer_work, clock_was_set_work); | ||
| 730 | |||
| 724 | /* | 731 | /* |
| 725 | * Called from timekeeping code to reprogramm the hrtimer interrupt | 732 | * Called from timekeeping and resume code to reprogramm the hrtimer |
| 726 | * device. If called from the timer interrupt context we defer it to | 733 | * interrupt device on all cpus. |
| 727 | * softirq context. | ||
| 728 | */ | 734 | */ |
| 729 | void clock_was_set_delayed(void) | 735 | void clock_was_set_delayed(void) |
| 730 | { | 736 | { |
| 731 | struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); | 737 | schedule_work(&hrtimer_work); |
| 732 | |||
| 733 | cpu_base->clock_was_set = 1; | ||
| 734 | __raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
| 735 | } | 738 | } |
| 736 | 739 | ||
| 737 | #else | 740 | #else |
| @@ -780,8 +783,10 @@ void hrtimers_resume(void) | |||
| 780 | WARN_ONCE(!irqs_disabled(), | 783 | WARN_ONCE(!irqs_disabled(), |
| 781 | KERN_INFO "hrtimers_resume() called with IRQs enabled!"); | 784 | KERN_INFO "hrtimers_resume() called with IRQs enabled!"); |
| 782 | 785 | ||
| 786 | /* Retrigger on the local CPU */ | ||
| 783 | retrigger_next_event(NULL); | 787 | retrigger_next_event(NULL); |
| 784 | timerfd_clock_was_set(); | 788 | /* And schedule a retrigger for all others */ |
| 789 | clock_was_set_delayed(); | ||
| 785 | } | 790 | } |
| 786 | 791 | ||
| 787 | static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) | 792 | static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) |
| @@ -1432,13 +1437,6 @@ void hrtimer_peek_ahead_timers(void) | |||
| 1432 | 1437 | ||
| 1433 | static void run_hrtimer_softirq(struct softirq_action *h) | 1438 | static void run_hrtimer_softirq(struct softirq_action *h) |
| 1434 | { | 1439 | { |
| 1435 | struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); | ||
| 1436 | |||
| 1437 | if (cpu_base->clock_was_set) { | ||
| 1438 | cpu_base->clock_was_set = 0; | ||
| 1439 | clock_was_set(); | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | hrtimer_peek_ahead_timers(); | 1440 | hrtimer_peek_ahead_timers(); |
| 1443 | } | 1441 | } |
| 1444 | 1442 | ||
