]>
Commit | Line | Data |
---|---|---|
bcd4f083 GKH |
1 | From 398812159e328478ae49b4bd01f0d71efea96c39 Mon Sep 17 00:00:00 2001 |
2 | From: Heiko Carstens <heiko.carstens@de.ibm.com> | |
3 | Date: Wed, 1 Dec 2010 10:08:01 +0100 | |
4 | Subject: [S390] nohz/s390: fix arch_needs_cpu() return value on offline cpus | |
5 | ||
6 | From: Heiko Carstens <heiko.carstens@de.ibm.com> | |
7 | ||
8 | commit 398812159e328478ae49b4bd01f0d71efea96c39 upstream. | |
9 | ||
10 | This fixes the same problem as described in the patch "nohz: fix | |
11 | printk_needs_cpu() return value on offline cpus" for the arch_needs_cpu() | |
12 | primitive: | |
13 | ||
14 | arch_needs_cpu() may return 1 if called on offline cpus. When a cpu gets | |
15 | offlined it schedules the idle process which, before killing its own cpu, | |
16 | will call tick_nohz_stop_sched_tick(). | |
17 | That function in turn will call arch_needs_cpu() in order to check if the | |
18 | local tick can be disabled. On offline cpus this function should naturally | |
19 | return 0 since regardless if the tick gets disabled or not the cpu will be | |
20 | dead short after. That is besides the fact that __cpu_disable() should already | |
21 | have made sure that no interrupts on the offlined cpu will be delivered anyway. | |
22 | ||
23 | In this case it prevents tick_nohz_stop_sched_tick() to call | |
24 | select_nohz_load_balancer(). No idea if that really is a problem. However what | |
25 | made me debug this is that on 2.6.32 the function get_nohz_load_balancer() is | |
26 | used within __mod_timer() to select a cpu on which a timer gets enqueued. | |
27 | If arch_needs_cpu() returns 1 then the nohz_load_balancer cpu doesn't get | |
28 | updated when a cpu gets offlined. It may contain the cpu number of an offline | |
29 | cpu. In turn timers get enqueued on an offline cpu and not very surprisingly | |
30 | they never expire and cause system hangs. | |
31 | ||
32 | This has been observed 2.6.32 kernels. On current kernels __mod_timer() uses | |
33 | get_nohz_timer_target() which doesn't have that problem. However there might | |
34 | be other problems because of the too early exit tick_nohz_stop_sched_tick() | |
35 | in case a cpu goes offline. | |
36 | ||
37 | This specific bug was indrocuded with 3c5d92a0 "nohz: Introduce | |
38 | arch_needs_cpu". | |
39 | ||
40 | In this case a cpu hotplug notifier is used to fix the issue in order to keep | |
41 | the normal/fast path small. All we need to do is to clear the condition that | |
42 | makes arch_needs_cpu() return 1 since it is just a performance improvement | |
43 | which is supposed to keep the local tick running for a short period if a cpu | |
44 | goes idle. Nothing special needs to be done except for clearing the condition. | |
45 | ||
46 | Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> | |
47 | Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> | |
48 | Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> | |
49 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
50 | ||
51 | --- | |
52 | arch/s390/kernel/vtime.c | 19 +++++++++++++++++++ | |
53 | 1 file changed, 19 insertions(+) | |
54 | ||
55 | --- a/arch/s390/kernel/vtime.c | |
56 | +++ b/arch/s390/kernel/vtime.c | |
57 | @@ -19,6 +19,7 @@ | |
58 | #include <linux/kernel_stat.h> | |
59 | #include <linux/rcupdate.h> | |
60 | #include <linux/posix-timers.h> | |
61 | +#include <linux/cpu.h> | |
62 | ||
63 | #include <asm/s390_ext.h> | |
64 | #include <asm/timer.h> | |
65 | @@ -565,6 +566,23 @@ void init_cpu_vtimer(void) | |
66 | __ctl_set_bit(0,10); | |
67 | } | |
68 | ||
69 | +static int __cpuinit s390_nohz_notify(struct notifier_block *self, | |
70 | + unsigned long action, void *hcpu) | |
71 | +{ | |
72 | + struct s390_idle_data *idle; | |
73 | + long cpu = (long) hcpu; | |
74 | + | |
75 | + idle = &per_cpu(s390_idle, cpu); | |
76 | + switch (action) { | |
77 | + case CPU_DYING: | |
78 | + case CPU_DYING_FROZEN: | |
79 | + idle->nohz_delay = 0; | |
80 | + default: | |
81 | + break; | |
82 | + } | |
83 | + return NOTIFY_OK; | |
84 | +} | |
85 | + | |
86 | void __init vtime_init(void) | |
87 | { | |
88 | /* request the cpu timer external interrupt */ | |
89 | @@ -573,5 +591,6 @@ void __init vtime_init(void) | |
90 | ||
91 | /* Enable cpu timer interrupts on the boot cpu. */ | |
92 | init_cpu_vtimer(); | |
93 | + cpu_notifier(s390_nohz_notify, 0); | |
94 | } | |
95 |