Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer fixes from Thomas Gleixner:
"Mostly small fixes for the fallout of the timekeeping overhaul in 3.6
along with stable fixes to address an accumulation problem and missing
sanity checks for RTC readouts and user space provided values."

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
time: Avoid making adjustments if we haven't accumulated anything
time: Avoid potential shift overflow with large shift values
time: Fix casting issue in timekeeping_forward_now
time: Ensure we normalize the timekeeper in tk_xtime_add
time: Improve sanity checking of timekeeping inputs

+52 -14
-7
include/linux/ktime.h
··· 58 58 59 59 typedef union ktime ktime_t; /* Kill this */ 60 60 61 - #define KTIME_MAX ((s64)~((u64)1 << 63)) 62 - #if (BITS_PER_LONG == 64) 63 - # define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) 64 - #else 65 - # define KTIME_SEC_MAX LONG_MAX 66 - #endif 67 - 68 61 /* 69 62 * ktime_t definitions when using the 64-bit scalar representation: 70 63 */
+20 -2
include/linux/time.h
··· 107 107 return ts_delta; 108 108 } 109 109 110 + #define KTIME_MAX ((s64)~((u64)1 << 63)) 111 + #if (BITS_PER_LONG == 64) 112 + # define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) 113 + #else 114 + # define KTIME_SEC_MAX LONG_MAX 115 + #endif 116 + 110 117 /* 111 118 * Returns true if the timespec is norm, false if denorm: 112 119 */ 113 - #define timespec_valid(ts) \ 114 - (((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC)) 120 + static inline bool timespec_valid(const struct timespec *ts) 121 + { 122 + /* Dates before 1970 are bogus */ 123 + if (ts->tv_sec < 0) 124 + return false; 125 + /* Can't have more nanoseconds then a second */ 126 + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) 127 + return false; 128 + /* Disallow values that could overflow ktime_t */ 129 + if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) 130 + return false; 131 + return true; 132 + } 115 133 116 134 extern void read_persistent_clock(struct timespec *ts); 117 135 extern void read_boot_clock(struct timespec *ts);
+32 -5
kernel/time/timekeeping.c
··· 115 115 { 116 116 tk->xtime_sec += ts->tv_sec; 117 117 tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; 118 + tk_normalize_xtime(tk); 118 119 } 119 120 120 121 static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) ··· 277 276 tk->xtime_nsec += cycle_delta * tk->mult; 278 277 279 278 /* If arch requires, add in gettimeoffset() */ 280 - tk->xtime_nsec += arch_gettimeoffset() << tk->shift; 279 + tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift; 281 280 282 281 tk_normalize_xtime(tk); 283 282 ··· 428 427 struct timespec ts_delta, xt; 429 428 unsigned long flags; 430 429 431 - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) 430 + if (!timespec_valid(tv)) 432 431 return -EINVAL; 433 432 434 433 write_seqlock_irqsave(&tk->lock, flags); ··· 464 463 { 465 464 struct timekeeper *tk = &timekeeper; 466 465 unsigned long flags; 466 + struct timespec tmp; 467 + int ret = 0; 467 468 468 469 if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) 469 470 return -EINVAL; ··· 474 471 475 472 timekeeping_forward_now(tk); 476 473 474 + /* Make sure the proposed value is valid */ 475 + tmp = timespec_add(tk_xtime(tk), *ts); 476 + if (!timespec_valid(&tmp)) { 477 + ret = -EINVAL; 478 + goto error; 479 + } 477 480 478 481 tk_xtime_add(tk, ts); 479 482 tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); 480 483 484 + error: /* even if we error out, we forwarded the time, so call update */ 481 485 timekeeping_update(tk, true); 482 486 483 487 write_sequnlock_irqrestore(&tk->lock, flags); ··· 492 482 /* signal hrtimers about time change */ 493 483 clock_was_set(); 494 484 495 - return 0; 485 + return ret; 496 486 } 497 487 EXPORT_SYMBOL(timekeeping_inject_offset); 498 488 ··· 659 649 struct timespec now, boot, tmp; 660 650 661 651 read_persistent_clock(&now); 652 + if (!timespec_valid(&now)) { 653 + pr_warn("WARNING: Persistent clock returned invalid value!\n" 654 + " Check your CMOS/BIOS settings.\n"); 655 + now.tv_sec = 0; 656 + now.tv_nsec = 0; 657 + } 658 + 662 659 read_boot_clock(&boot); 660 + if (!timespec_valid(&boot)) { 661 + pr_warn("WARNING: Boot clock returned invalid value!\n" 662 + " Check your CMOS/BIOS settings.\n"); 663 + boot.tv_sec = 0; 664 + boot.tv_nsec = 0; 665 + } 663 666 664 667 seqlock_init(&tk->lock); 665 668 ··· 1152 1129 offset = (clock->read(clock) - clock->cycle_last) & clock->mask; 1153 1130 #endif 1154 1131 1132 + /* Check if there's really nothing to do */ 1133 + if (offset < tk->cycle_interval) 1134 + goto out; 1135 + 1155 1136 /* 1156 1137 * With NO_HZ we may have to accumulate many cycle_intervals 1157 1138 * (think "ticks") worth of time at once. To do this efficiently, ··· 1188 1161 * the vsyscall implementations are converted to use xtime_nsec 1189 1162 * (shifted nanoseconds), this can be killed. 1190 1163 */ 1191 - remainder = tk->xtime_nsec & ((1 << tk->shift) - 1); 1164 + remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); 1192 1165 tk->xtime_nsec -= remainder; 1193 - tk->xtime_nsec += 1 << tk->shift; 1166 + tk->xtime_nsec += 1ULL << tk->shift; 1194 1167 tk->ntp_error += remainder << tk->ntp_error_shift; 1195 1168 1196 1169 /*