aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-sched.c
diff options
context:
space:
mode:
authorJon Hunter <jon-hunter@ti.com>2009-08-18 13:45:10 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-11-13 14:46:24 -0500
commit98962465ed9e6ea99c38e0af63fe1dcb5a79dc25 (patch)
treef3f69ad8f6cd47e72a75da6de49eb3402f15cd9b /kernel/time/tick-sched.c
parent529eaccd900a59724619b4a6ef6579fd518d5218 (diff)
nohz: Prevent clocksource wrapping during idle
The dynamic tick allows the kernel to sleep for periods longer than a single tick, but it does not limit the sleep time currently. In the worst case the kernel could sleep longer than the wrap around time of the time keeping clock source which would result in losing track of time. Prevent this by limiting it to the safe maximum sleep time of the current time keeping clock source. The value is calculated when the clock source is registered. [ tglx: simplified the code a bit and massaged the commit msg ] Signed-off-by: Jon Hunter <jon-hunter@ti.com> Cc: John Stultz <johnstul@us.ibm.com> LKML-Reference: <1250617512-23567-2-git-send-email-jon-hunter@ti.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/tick-sched.c')
-rw-r--r--kernel/time/tick-sched.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index c65ba0faa98f..a80b4644fe6b 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -208,6 +208,7 @@ void tick_nohz_stop_sched_tick(int inidle)
208 struct tick_sched *ts; 208 struct tick_sched *ts;
209 ktime_t last_update, expires, now; 209 ktime_t last_update, expires, now;
210 struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; 210 struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
211 u64 time_delta;
211 int cpu; 212 int cpu;
212 213
213 local_irq_save(flags); 214 local_irq_save(flags);
@@ -262,6 +263,17 @@ void tick_nohz_stop_sched_tick(int inidle)
262 seq = read_seqbegin(&xtime_lock); 263 seq = read_seqbegin(&xtime_lock);
263 last_update = last_jiffies_update; 264 last_update = last_jiffies_update;
264 last_jiffies = jiffies; 265 last_jiffies = jiffies;
266
267 /*
268 * On SMP we really should only care for the CPU which
269 * has the do_timer duty assigned. All other CPUs can
270 * sleep as long as they want.
271 */
272 if (cpu == tick_do_timer_cpu ||
273 tick_do_timer_cpu == TICK_DO_TIMER_NONE)
274 time_delta = timekeeping_max_deferment();
275 else
276 time_delta = KTIME_MAX;
265 } while (read_seqretry(&xtime_lock, seq)); 277 } while (read_seqretry(&xtime_lock, seq));
266 278
267 if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) || 279 if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) ||
@@ -284,11 +296,26 @@ void tick_nohz_stop_sched_tick(int inidle)
284 if ((long)delta_jiffies >= 1) { 296 if ((long)delta_jiffies >= 1) {
285 297
286 /* 298 /*
287 * calculate the expiry time for the next timer wheel 299 * calculate the expiry time for the next timer wheel
288 * timer 300 * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
289 */ 301 * that there is no timer pending or at least extremely
290 expires = ktime_add_ns(last_update, tick_period.tv64 * 302 * far into the future (12 days for HZ=1000). In this
291 delta_jiffies); 303 * case we set the expiry to the end of time.
304 */
305 if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
306 /*
307 * Calculate the time delta for the next timer event.
308 * If the time delta exceeds the maximum time delta
309 * permitted by the current clocksource then adjust
310 * the time delta accordingly to ensure the
311 * clocksource does not wrap.
312 */
313 time_delta = min_t(u64, time_delta,
314 tick_period.tv64 * delta_jiffies);
315 expires = ktime_add_ns(last_update, time_delta);
316 } else {
317 expires.tv64 = KTIME_MAX;
318 }
292 319
293 /* 320 /*
294 * If this cpu is the one which updates jiffies, then 321 * If this cpu is the one which updates jiffies, then
@@ -332,22 +359,19 @@ void tick_nohz_stop_sched_tick(int inidle)
332 359
333 ts->idle_sleeps++; 360 ts->idle_sleeps++;
334 361
362 /* Mark expires */
363 ts->idle_expires = expires;
364
335 /* 365 /*
336 * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that 366 * If the expiration time == KTIME_MAX, then
337 * there is no timer pending or at least extremly far 367 * in this case we simply stop the tick timer.
338 * into the future (12 days for HZ=1000). In this case
339 * we simply stop the tick timer:
340 */ 368 */
341 if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) { 369 if (unlikely(expires.tv64 == KTIME_MAX)) {
342 ts->idle_expires.tv64 = KTIME_MAX;
343 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) 370 if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
344 hrtimer_cancel(&ts->sched_timer); 371 hrtimer_cancel(&ts->sched_timer);
345 goto out; 372 goto out;
346 } 373 }
347 374
348 /* Mark expiries */
349 ts->idle_expires = expires;
350
351 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { 375 if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
352 hrtimer_start(&ts->sched_timer, expires, 376 hrtimer_start(&ts->sched_timer, expires,
353 HRTIMER_MODE_ABS_PINNED); 377 HRTIMER_MODE_ABS_PINNED);