diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-09-22 12:46:37 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-09-23 05:38:52 -0400 |
commit | 6441402b1f173fa38e561d3cee7c01c32e5281ad (patch) | |
tree | fd7c81337354f39e44581530d499bcdda06d76c4 /kernel/time | |
parent | 72d31053f62c4bc464c2783974926969614a8649 (diff) |
clockevents: prevent cpu online to interfere with nohz
Impact: rare hang which can be triggered on CPU online.
tick_do_timer_cpu keeps track of the CPU which updates jiffies
via do_timer. The value -1 is used to signal, that currently no
CPU is doing this. There are two cases, where the variable can
have this state:
boot:
necessary for systems where the boot cpu id can be != 0
nohz long idle sleep:
When the CPU which did the jiffies update last goes into
a long idle sleep it drops the update jiffies duty so
another CPU which is not idle can pick it up and keep
jiffies going.
Using the same value for both situations is wrong, as the CPU online
code can see the -1 state when the timer of the newly onlined CPU is
setup. The setup for a newly onlined CPU goes through periodic mode
and can pick up the do_timer duty without being aware of the nohz /
highres mode of the already running system.
Use two separate states and make them constants to avoid magic
numbers confusion.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/tick-common.c | 7 | ||||
-rw-r--r-- | kernel/time/tick-internal.h | 4 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 8 |
3 files changed, 12 insertions, 7 deletions
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 019315ebf9de..b523d095decf 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
@@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device); | |||
33 | */ | 33 | */ |
34 | ktime_t tick_next_period; | 34 | ktime_t tick_next_period; |
35 | ktime_t tick_period; | 35 | ktime_t tick_period; |
36 | int tick_do_timer_cpu __read_mostly = -1; | 36 | int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT; |
37 | DEFINE_SPINLOCK(tick_device_lock); | 37 | DEFINE_SPINLOCK(tick_device_lock); |
38 | 38 | ||
39 | /* | 39 | /* |
@@ -148,7 +148,7 @@ static void tick_setup_device(struct tick_device *td, | |||
148 | * If no cpu took the do_timer update, assign it to | 148 | * If no cpu took the do_timer update, assign it to |
149 | * this cpu: | 149 | * this cpu: |
150 | */ | 150 | */ |
151 | if (tick_do_timer_cpu == -1) { | 151 | if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) { |
152 | tick_do_timer_cpu = cpu; | 152 | tick_do_timer_cpu = cpu; |
153 | tick_next_period = ktime_get(); | 153 | tick_next_period = ktime_get(); |
154 | tick_period = ktime_set(0, NSEC_PER_SEC / HZ); | 154 | tick_period = ktime_set(0, NSEC_PER_SEC / HZ); |
@@ -300,7 +300,8 @@ static void tick_shutdown(unsigned int *cpup) | |||
300 | if (*cpup == tick_do_timer_cpu) { | 300 | if (*cpup == tick_do_timer_cpu) { |
301 | int cpu = first_cpu(cpu_online_map); | 301 | int cpu = first_cpu(cpu_online_map); |
302 | 302 | ||
303 | tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1; | 303 | tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : |
304 | TICK_DO_TIMER_NONE; | ||
304 | } | 305 | } |
305 | spin_unlock_irqrestore(&tick_device_lock, flags); | 306 | spin_unlock_irqrestore(&tick_device_lock, flags); |
306 | } | 307 | } |
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 6e9db9734aa6..e18014fadf95 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h | |||
@@ -1,6 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * tick internal variable and functions used by low/high res code | 2 | * tick internal variable and functions used by low/high res code |
3 | */ | 3 | */ |
4 | |||
5 | #define TICK_DO_TIMER_NONE -1 | ||
6 | #define TICK_DO_TIMER_BOOT -2 | ||
7 | |||
4 | DECLARE_PER_CPU(struct tick_device, tick_cpu_device); | 8 | DECLARE_PER_CPU(struct tick_device, tick_cpu_device); |
5 | extern spinlock_t tick_device_lock; | 9 | extern spinlock_t tick_device_lock; |
6 | extern ktime_t tick_next_period; | 10 | extern ktime_t tick_next_period; |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a87b0468568b..31a14e8caac1 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -221,7 +221,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
221 | */ | 221 | */ |
222 | if (unlikely(!cpu_online(cpu))) { | 222 | if (unlikely(!cpu_online(cpu))) { |
223 | if (cpu == tick_do_timer_cpu) | 223 | if (cpu == tick_do_timer_cpu) |
224 | tick_do_timer_cpu = -1; | 224 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; |
225 | } | 225 | } |
226 | 226 | ||
227 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) | 227 | if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) |
@@ -303,7 +303,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
303 | * invoked. | 303 | * invoked. |
304 | */ | 304 | */ |
305 | if (cpu == tick_do_timer_cpu) | 305 | if (cpu == tick_do_timer_cpu) |
306 | tick_do_timer_cpu = -1; | 306 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; |
307 | 307 | ||
308 | ts->idle_sleeps++; | 308 | ts->idle_sleeps++; |
309 | 309 | ||
@@ -468,7 +468,7 @@ static void tick_nohz_handler(struct clock_event_device *dev) | |||
468 | * this duty, then the jiffies update is still serialized by | 468 | * this duty, then the jiffies update is still serialized by |
469 | * xtime_lock. | 469 | * xtime_lock. |
470 | */ | 470 | */ |
471 | if (unlikely(tick_do_timer_cpu == -1)) | 471 | if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) |
472 | tick_do_timer_cpu = cpu; | 472 | tick_do_timer_cpu = cpu; |
473 | 473 | ||
474 | /* Check, if the jiffies need an update */ | 474 | /* Check, if the jiffies need an update */ |
@@ -570,7 +570,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) | |||
570 | * this duty, then the jiffies update is still serialized by | 570 | * this duty, then the jiffies update is still serialized by |
571 | * xtime_lock. | 571 | * xtime_lock. |
572 | */ | 572 | */ |
573 | if (unlikely(tick_do_timer_cpu == -1)) | 573 | if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) |
574 | tick_do_timer_cpu = cpu; | 574 | tick_do_timer_cpu = cpu; |
575 | #endif | 575 | #endif |
576 | 576 | ||