aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c58
1 files changed, 45 insertions, 13 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e16af197a2bc..d3b91e75cecd 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -115,6 +115,7 @@ static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts)
115{ 115{
116 tk->xtime_sec += ts->tv_sec; 116 tk->xtime_sec += ts->tv_sec;
117 tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; 117 tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift;
118 tk_normalize_xtime(tk);
118} 119}
119 120
120static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) 121static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
@@ -276,7 +277,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)
276 tk->xtime_nsec += cycle_delta * tk->mult; 277 tk->xtime_nsec += cycle_delta * tk->mult;
277 278
278 /* If arch requires, add in gettimeoffset() */ 279 /* If arch requires, add in gettimeoffset() */
279 tk->xtime_nsec += arch_gettimeoffset() << tk->shift; 280 tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift;
280 281
281 tk_normalize_xtime(tk); 282 tk_normalize_xtime(tk);
282 283
@@ -302,10 +303,11 @@ void getnstimeofday(struct timespec *ts)
302 seq = read_seqbegin(&tk->lock); 303 seq = read_seqbegin(&tk->lock);
303 304
304 ts->tv_sec = tk->xtime_sec; 305 ts->tv_sec = tk->xtime_sec;
305 ts->tv_nsec = timekeeping_get_ns(tk); 306 nsecs = timekeeping_get_ns(tk);
306 307
307 } while (read_seqretry(&tk->lock, seq)); 308 } while (read_seqretry(&tk->lock, seq));
308 309
310 ts->tv_nsec = 0;
309 timespec_add_ns(ts, nsecs); 311 timespec_add_ns(ts, nsecs);
310} 312}
311EXPORT_SYMBOL(getnstimeofday); 313EXPORT_SYMBOL(getnstimeofday);
@@ -344,6 +346,7 @@ void ktime_get_ts(struct timespec *ts)
344{ 346{
345 struct timekeeper *tk = &timekeeper; 347 struct timekeeper *tk = &timekeeper;
346 struct timespec tomono; 348 struct timespec tomono;
349 s64 nsec;
347 unsigned int seq; 350 unsigned int seq;
348 351
349 WARN_ON(timekeeping_suspended); 352 WARN_ON(timekeeping_suspended);
@@ -351,13 +354,14 @@ void ktime_get_ts(struct timespec *ts)
351 do { 354 do {
352 seq = read_seqbegin(&tk->lock); 355 seq = read_seqbegin(&tk->lock);
353 ts->tv_sec = tk->xtime_sec; 356 ts->tv_sec = tk->xtime_sec;
354 ts->tv_nsec = timekeeping_get_ns(tk); 357 nsec = timekeeping_get_ns(tk);
355 tomono = tk->wall_to_monotonic; 358 tomono = tk->wall_to_monotonic;
356 359
357 } while (read_seqretry(&tk->lock, seq)); 360 } while (read_seqretry(&tk->lock, seq));
358 361
359 set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec, 362 ts->tv_sec += tomono.tv_sec;
360 ts->tv_nsec + tomono.tv_nsec); 363 ts->tv_nsec = 0;
364 timespec_add_ns(ts, nsec + tomono.tv_nsec);
361} 365}
362EXPORT_SYMBOL_GPL(ktime_get_ts); 366EXPORT_SYMBOL_GPL(ktime_get_ts);
363 367
@@ -427,7 +431,7 @@ int do_settimeofday(const struct timespec *tv)
427 struct timespec ts_delta, xt; 431 struct timespec ts_delta, xt;
428 unsigned long flags; 432 unsigned long flags;
429 433
430 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) 434 if (!timespec_valid_strict(tv))
431 return -EINVAL; 435 return -EINVAL;
432 436
433 write_seqlock_irqsave(&tk->lock, flags); 437 write_seqlock_irqsave(&tk->lock, flags);
@@ -463,6 +467,8 @@ int timekeeping_inject_offset(struct timespec *ts)
463{ 467{
464 struct timekeeper *tk = &timekeeper; 468 struct timekeeper *tk = &timekeeper;
465 unsigned long flags; 469 unsigned long flags;
470 struct timespec tmp;
471 int ret = 0;
466 472
467 if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) 473 if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
468 return -EINVAL; 474 return -EINVAL;
@@ -471,10 +477,17 @@ int timekeeping_inject_offset(struct timespec *ts)
471 477
472 timekeeping_forward_now(tk); 478 timekeeping_forward_now(tk);
473 479
480 /* Make sure the proposed value is valid */
481 tmp = timespec_add(tk_xtime(tk), *ts);
482 if (!timespec_valid_strict(&tmp)) {
483 ret = -EINVAL;
484 goto error;
485 }
474 486
475 tk_xtime_add(tk, ts); 487 tk_xtime_add(tk, ts);
476 tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); 488 tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
477 489
490error: /* even if we error out, we forwarded the time, so call update */
478 timekeeping_update(tk, true); 491 timekeeping_update(tk, true);
479 492
480 write_sequnlock_irqrestore(&tk->lock, flags); 493 write_sequnlock_irqrestore(&tk->lock, flags);
@@ -482,7 +495,7 @@ int timekeeping_inject_offset(struct timespec *ts)
482 /* signal hrtimers about time change */ 495 /* signal hrtimers about time change */
483 clock_was_set(); 496 clock_was_set();
484 497
485 return 0; 498 return ret;
486} 499}
487EXPORT_SYMBOL(timekeeping_inject_offset); 500EXPORT_SYMBOL(timekeeping_inject_offset);
488 501
@@ -649,7 +662,20 @@ void __init timekeeping_init(void)
649 struct timespec now, boot, tmp; 662 struct timespec now, boot, tmp;
650 663
651 read_persistent_clock(&now); 664 read_persistent_clock(&now);
665 if (!timespec_valid_strict(&now)) {
666 pr_warn("WARNING: Persistent clock returned invalid value!\n"
667 " Check your CMOS/BIOS settings.\n");
668 now.tv_sec = 0;
669 now.tv_nsec = 0;
670 }
671
652 read_boot_clock(&boot); 672 read_boot_clock(&boot);
673 if (!timespec_valid_strict(&boot)) {
674 pr_warn("WARNING: Boot clock returned invalid value!\n"
675 " Check your CMOS/BIOS settings.\n");
676 boot.tv_sec = 0;
677 boot.tv_nsec = 0;
678 }
653 679
654 seqlock_init(&tk->lock); 680 seqlock_init(&tk->lock);
655 681
@@ -690,7 +716,7 @@ static struct timespec timekeeping_suspend_time;
690static void __timekeeping_inject_sleeptime(struct timekeeper *tk, 716static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
691 struct timespec *delta) 717 struct timespec *delta)
692{ 718{
693 if (!timespec_valid(delta)) { 719 if (!timespec_valid_strict(delta)) {
694 printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " 720 printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid "
695 "sleep delta value!\n"); 721 "sleep delta value!\n");
696 return; 722 return;
@@ -1129,6 +1155,10 @@ static void update_wall_time(void)
1129 offset = (clock->read(clock) - clock->cycle_last) & clock->mask; 1155 offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
1130#endif 1156#endif
1131 1157
1158 /* Check if there's really nothing to do */
1159 if (offset < tk->cycle_interval)
1160 goto out;
1161
1132 /* 1162 /*
1133 * With NO_HZ we may have to accumulate many cycle_intervals 1163 * With NO_HZ we may have to accumulate many cycle_intervals
1134 * (think "ticks") worth of time at once. To do this efficiently, 1164 * (think "ticks") worth of time at once. To do this efficiently,
@@ -1161,9 +1191,9 @@ static void update_wall_time(void)
1161 * the vsyscall implementations are converted to use xtime_nsec 1191 * the vsyscall implementations are converted to use xtime_nsec
1162 * (shifted nanoseconds), this can be killed. 1192 * (shifted nanoseconds), this can be killed.
1163 */ 1193 */
1164 remainder = tk->xtime_nsec & ((1 << tk->shift) - 1); 1194 remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1);
1165 tk->xtime_nsec -= remainder; 1195 tk->xtime_nsec -= remainder;
1166 tk->xtime_nsec += 1 << tk->shift; 1196 tk->xtime_nsec += 1ULL << tk->shift;
1167 tk->ntp_error += remainder << tk->ntp_error_shift; 1197 tk->ntp_error += remainder << tk->ntp_error_shift;
1168 1198
1169 /* 1199 /*
@@ -1217,6 +1247,7 @@ void get_monotonic_boottime(struct timespec *ts)
1217{ 1247{
1218 struct timekeeper *tk = &timekeeper; 1248 struct timekeeper *tk = &timekeeper;
1219 struct timespec tomono, sleep; 1249 struct timespec tomono, sleep;
1250 s64 nsec;
1220 unsigned int seq; 1251 unsigned int seq;
1221 1252
1222 WARN_ON(timekeeping_suspended); 1253 WARN_ON(timekeeping_suspended);
@@ -1224,14 +1255,15 @@ void get_monotonic_boottime(struct timespec *ts)
1224 do { 1255 do {
1225 seq = read_seqbegin(&tk->lock); 1256 seq = read_seqbegin(&tk->lock);
1226 ts->tv_sec = tk->xtime_sec; 1257 ts->tv_sec = tk->xtime_sec;
1227 ts->tv_nsec = timekeeping_get_ns(tk); 1258 nsec = timekeeping_get_ns(tk);
1228 tomono = tk->wall_to_monotonic; 1259 tomono = tk->wall_to_monotonic;
1229 sleep = tk->total_sleep_time; 1260 sleep = tk->total_sleep_time;
1230 1261
1231 } while (read_seqretry(&tk->lock, seq)); 1262 } while (read_seqretry(&tk->lock, seq));
1232 1263
1233 set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, 1264 ts->tv_sec += tomono.tv_sec + sleep.tv_sec;
1234 ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec); 1265 ts->tv_nsec = 0;
1266 timespec_add_ns(ts, nsec + tomono.tv_nsec + sleep.tv_nsec);
1235} 1267}
1236EXPORT_SYMBOL_GPL(get_monotonic_boottime); 1268EXPORT_SYMBOL_GPL(get_monotonic_boottime);
1237 1269