Skip to content

Commit

Permalink
time: Always make sure wall_to_monotonic isn't positive
Browse files Browse the repository at this point in the history
Two issues were found on an IMX6 development board without an
enabled RTC device(resulting in the boot time and monotonic
time being initialized to 0).

Issue 1:exportfs -a generate:
       "exportfs: /opt/nfs/arm does not support NFS export"
Issue 2:cat /proc/stat:
       "btime 4294967236"

The same issues can be reproduced on x86 after running the
following code:
	int main(void)
	{
	    struct timeval val;
	    int ret;

	    val.tv_sec = 0;
	    val.tv_usec = 0;
	    ret = settimeofday(&val, NULL);
	    return 0;
	}

Two issues are different symptoms of same problem:
The reason is a positive wall_to_monotonic pushes boot time back
to the time before Epoch, and getboottime will return negative
value.

In symptom 1:
          negative boot time cause get_expiry() to overflow time_t
          when input expire time is 2147483647, then cache_flush()
          always clears entries just added in ip_map_parse.
In symptom 2:
          show_stat() uses "unsigned long" to print negative btime
          value returned by getboottime.

This patch fix the problem by prohibiting time from being set to a value which
would cause a negative boot time. As a result one can't set the CLOCK_REALTIME
time prior to (1970 + system uptime).

Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Wang YanQing <udknight@gmail.com>
[jstultz: reworded commit message]
Signed-off-by: John Stultz <john.stultz@linaro.org>
  • Loading branch information
wyqkp authored and johnstultz-work committed Aug 17, 2015
1 parent de4a95f commit e1d7ba8
Showing 1 changed file with 10 additions and 3 deletions.
13 changes: 10 additions & 3 deletions kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ int do_settimeofday64(const struct timespec64 *ts)
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts_delta, xt;
unsigned long flags;
int ret = 0;

if (!timespec64_valid_strict(ts))
return -EINVAL;
Expand All @@ -924,10 +925,15 @@ int do_settimeofday64(const struct timespec64 *ts)
ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;

if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
ret = -EINVAL;
goto out;
}

tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));

tk_set_xtime(tk, ts);

out:
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);

write_seqcount_end(&tk_core.seq);
Expand All @@ -936,7 +942,7 @@ int do_settimeofday64(const struct timespec64 *ts)
/* signal hrtimers about time change */
clock_was_set();

return 0;
return ret;
}
EXPORT_SYMBOL(do_settimeofday64);

Expand Down Expand Up @@ -965,7 +971,8 @@ int timekeeping_inject_offset(struct timespec *ts)

/* Make sure the proposed value is valid */
tmp = timespec64_add(tk_xtime(tk), ts64);
if (!timespec64_valid_strict(&tmp)) {
if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 ||
!timespec64_valid_strict(&tmp)) {
ret = -EINVAL;
goto error;
}
Expand Down

0 comments on commit e1d7ba8

Please sign in to comment.