1 From e1d7ba8735551ed79c7a0463a042353574b96da3 Mon Sep 17 00:00:00 2001
2 From: Wang YanQing <udknight@gmail.com>
3 Date: Tue, 23 Jun 2015 18:38:54 +0800
4 Subject: time: Always make sure wall_to_monotonic isn't positive
6 From: Wang YanQing <udknight@gmail.com>
8 commit e1d7ba8735551ed79c7a0463a042353574b96da3 upstream.
10 Two issues were found on an IMX6 development board without an
11 enabled RTC device(resulting in the boot time and monotonic
12 time being initialized to 0).
14 Issue 1:exportfs -a generate:
15 "exportfs: /opt/nfs/arm does not support NFS export"
16 Issue 2:cat /proc/stat:
19 The same issues can be reproduced on x86 after running the
28 ret = settimeofday(&val, NULL);
32 Two issues are different symptoms of same problem:
33 The reason is a positive wall_to_monotonic pushes boot time back
34 to the time before Epoch, and getboottime will return negative
38 negative boot time cause get_expiry() to overflow time_t
39 when input expire time is 2147483647, then cache_flush()
40 always clears entries just added in ip_map_parse.
42 show_stat() uses "unsigned long" to print negative btime
43 value returned by getboottime.
45 This patch fix the problem by prohibiting time from being set to a value which
46 would cause a negative boot time. As a result one can't set the CLOCK_REALTIME
47 time prior to (1970 + system uptime).
49 Cc: Prarit Bhargava <prarit@redhat.com>
50 Cc: Richard Cochran <richardcochran@gmail.com>
51 Cc: Ingo Molnar <mingo@kernel.org>
52 Cc: Thomas Gleixner <tglx@linutronix.de>
53 Signed-off-by: Wang YanQing <udknight@gmail.com>
54 [jstultz: reworded commit message]
55 [msfjarvis: Backport to 3.18 as we are missing the do_settimeofday64
56 function the upstream commit patches, so we apply the changes to
58 Signed-off-by: John Stultz <john.stultz@linaro.org>
59 Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com>
60 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
62 kernel/time/timekeeping.c | 13 ++++++++++---
63 1 file changed, 10 insertions(+), 3 deletions(-)
65 --- a/kernel/time/timekeeping.c
66 +++ b/kernel/time/timekeeping.c
67 @@ -712,6 +712,7 @@ int do_settimeofday(const struct timespe
68 struct timekeeper *tk = &tk_core.timekeeper;
69 struct timespec64 ts_delta, xt, tmp;
73 if (!timespec_valid_strict(tv))
75 @@ -725,11 +726,16 @@ int do_settimeofday(const struct timespe
76 ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
77 ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
79 + if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
84 tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
86 tmp = timespec_to_timespec64(*tv);
87 tk_set_xtime(tk, &tmp);
90 timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
92 write_seqcount_end(&tk_core.seq);
93 @@ -738,7 +744,7 @@ int do_settimeofday(const struct timespe
94 /* signal hrtimers about time change */
100 EXPORT_SYMBOL(do_settimeofday);
102 @@ -767,7 +773,8 @@ int timekeeping_inject_offset(struct tim
104 /* Make sure the proposed value is valid */
105 tmp = timespec64_add(tk_xtime(tk), ts64);
106 - if (!timespec64_valid_strict(&tmp)) {
107 + if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 ||
108 + !timespec64_valid_strict(&tmp)) {