|
@@ -427,7 +427,7 @@ int do_settimeofday(const struct timespec *tv)
|
|
|
struct timespec ts_delta, xt;
|
|
|
unsigned long flags;
|
|
|
|
|
|
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
|
|
|
+ if (!timespec_valid(tv))
|
|
|
return -EINVAL;
|
|
|
|
|
|
write_seqlock_irqsave(&tk->lock, flags);
|
|
@@ -463,6 +463,8 @@ int timekeeping_inject_offset(struct timespec *ts)
|
|
|
{
|
|
|
struct timekeeper *tk = &timekeeper;
|
|
|
unsigned long flags;
|
|
|
+ struct timespec tmp;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
|
|
|
return -EINVAL;
|
|
@@ -471,10 +473,17 @@ int timekeeping_inject_offset(struct timespec *ts)
|
|
|
|
|
|
timekeeping_forward_now(tk);
|
|
|
|
|
|
+ /* Make sure the proposed value is valid */
|
|
|
+ tmp = timespec_add(tk_xtime(tk), *ts);
|
|
|
+ if (!timespec_valid(&tmp)) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
|
|
|
tk_xtime_add(tk, ts);
|
|
|
tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
|
|
|
|
|
|
+error: /* even if we error out, we forwarded the time, so call update */
|
|
|
timekeeping_update(tk, true);
|
|
|
|
|
|
write_sequnlock_irqrestore(&tk->lock, flags);
|
|
@@ -482,7 +491,7 @@ int timekeeping_inject_offset(struct timespec *ts)
|
|
|
/* signal hrtimers about time change */
|
|
|
clock_was_set();
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(timekeeping_inject_offset);
|
|
|
|
|
@@ -649,7 +658,20 @@ void __init timekeeping_init(void)
|
|
|
struct timespec now, boot, tmp;
|
|
|
|
|
|
read_persistent_clock(&now);
|
|
|
+ if (!timespec_valid(&now)) {
|
|
|
+ pr_warn("WARNING: Persistent clock returned invalid value!\n"
|
|
|
+ " Check your CMOS/BIOS settings.\n");
|
|
|
+ now.tv_sec = 0;
|
|
|
+ now.tv_nsec = 0;
|
|
|
+ }
|
|
|
+
|
|
|
read_boot_clock(&boot);
|
|
|
+ if (!timespec_valid(&boot)) {
|
|
|
+ pr_warn("WARNING: Boot clock returned invalid value!\n"
|
|
|
+ " Check your CMOS/BIOS settings.\n");
|
|
|
+ boot.tv_sec = 0;
|
|
|
+ boot.tv_nsec = 0;
|
|
|
+ }
|
|
|
|
|
|
seqlock_init(&tk->lock);
|
|
|
|