diff options
author | pang.xunlei <pang.xunlei@linaro.org> | 2014-11-18 06:15:16 -0500 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2014-11-21 14:59:57 -0500 |
commit | 21f7eca555ad14e7c7b2cb59a6c6252e74ee5c8b (patch) | |
tree | 1d3beb73efb551aa006118bcf753b1df187ce72c | |
parent | 659bc17b80c692e0ccda757e207fc4666d9b3e71 (diff) |
time: Provide y2038 safe do_settimeofday() replacement
The kernel uses 32-bit signed value(time_t) for seconds elapsed
1970-01-01:00:00:00, thus it will overflow at 2038-01-19 03:14:08
on 32-bit systems. This is widely known as the y2038 problem.
As part of addressing "y2038 problem" for in-kernel uses, this patch
adds safe do_settimeofday64() using timespec64.
After this patch, do_settimeofday() is deprecated and all its call
sites will be fixed using do_settimeofday64(), after that it can be
removed.
Signed-off-by: pang.xunlei <pang.xunlei@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r-- | include/linux/timekeeping.h | 21 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 19 |
2 files changed, 29 insertions, 11 deletions
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 1caa6b04fdc5..071ad7e0c981 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h | |||
@@ -10,7 +10,7 @@ extern int timekeeping_suspended; | |||
10 | * Get and set timeofday | 10 | * Get and set timeofday |
11 | */ | 11 | */ |
12 | extern void do_gettimeofday(struct timeval *tv); | 12 | extern void do_gettimeofday(struct timeval *tv); |
13 | extern int do_settimeofday(const struct timespec *tv); | 13 | extern int do_settimeofday64(const struct timespec64 *ts); |
14 | extern int do_sys_settimeofday(const struct timespec *tv, | 14 | extern int do_sys_settimeofday(const struct timespec *tv, |
15 | const struct timezone *tz); | 15 | const struct timezone *tz); |
16 | 16 | ||
@@ -33,6 +33,14 @@ extern int __getnstimeofday64(struct timespec64 *tv); | |||
33 | extern void getnstimeofday64(struct timespec64 *tv); | 33 | extern void getnstimeofday64(struct timespec64 *tv); |
34 | 34 | ||
35 | #if BITS_PER_LONG == 64 | 35 | #if BITS_PER_LONG == 64 |
36 | /** | ||
37 | * Deprecated. Use do_settimeofday64(). | ||
38 | */ | ||
39 | static inline int do_settimeofday(const struct timespec *ts) | ||
40 | { | ||
41 | return do_settimeofday64(ts); | ||
42 | } | ||
43 | |||
36 | static inline int __getnstimeofday(struct timespec *ts) | 44 | static inline int __getnstimeofday(struct timespec *ts) |
37 | { | 45 | { |
38 | return __getnstimeofday64(ts); | 46 | return __getnstimeofday64(ts); |
@@ -54,6 +62,17 @@ static inline void ktime_get_real_ts(struct timespec *ts) | |||
54 | } | 62 | } |
55 | 63 | ||
56 | #else | 64 | #else |
65 | /** | ||
66 | * Deprecated. Use do_settimeofday64(). | ||
67 | */ | ||
68 | static inline int do_settimeofday(const struct timespec *ts) | ||
69 | { | ||
70 | struct timespec64 ts64; | ||
71 | |||
72 | ts64 = timespec_to_timespec64(*ts); | ||
73 | return do_settimeofday64(&ts64); | ||
74 | } | ||
75 | |||
57 | static inline int __getnstimeofday(struct timespec *ts) | 76 | static inline int __getnstimeofday(struct timespec *ts) |
58 | { | 77 | { |
59 | struct timespec64 ts64; | 78 | struct timespec64 ts64; |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 41fcbe19ccfe..10140dae71c6 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -703,18 +703,18 @@ void do_gettimeofday(struct timeval *tv) | |||
703 | EXPORT_SYMBOL(do_gettimeofday); | 703 | EXPORT_SYMBOL(do_gettimeofday); |
704 | 704 | ||
705 | /** | 705 | /** |
706 | * do_settimeofday - Sets the time of day | 706 | * do_settimeofday64 - Sets the time of day. |
707 | * @tv: pointer to the timespec variable containing the new time | 707 | * @ts: pointer to the timespec64 variable containing the new time |
708 | * | 708 | * |
709 | * Sets the time of day to the new time and update NTP and notify hrtimers | 709 | * Sets the time of day to the new time and update NTP and notify hrtimers |
710 | */ | 710 | */ |
711 | int do_settimeofday(const struct timespec *tv) | 711 | int do_settimeofday64(const struct timespec64 *ts) |
712 | { | 712 | { |
713 | struct timekeeper *tk = &tk_core.timekeeper; | 713 | struct timekeeper *tk = &tk_core.timekeeper; |
714 | struct timespec64 ts_delta, xt, tmp; | 714 | struct timespec64 ts_delta, xt; |
715 | unsigned long flags; | 715 | unsigned long flags; |
716 | 716 | ||
717 | if (!timespec_valid_strict(tv)) | 717 | if (!timespec64_valid_strict(ts)) |
718 | return -EINVAL; | 718 | return -EINVAL; |
719 | 719 | ||
720 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 720 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
@@ -723,13 +723,12 @@ int do_settimeofday(const struct timespec *tv) | |||
723 | timekeeping_forward_now(tk); | 723 | timekeeping_forward_now(tk); |
724 | 724 | ||
725 | xt = tk_xtime(tk); | 725 | xt = tk_xtime(tk); |
726 | ts_delta.tv_sec = tv->tv_sec - xt.tv_sec; | 726 | ts_delta.tv_sec = ts->tv_sec - xt.tv_sec; |
727 | ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec; | 727 | ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec; |
728 | 728 | ||
729 | tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); | 729 | tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); |
730 | 730 | ||
731 | tmp = timespec_to_timespec64(*tv); | 731 | tk_set_xtime(tk, ts); |
732 | tk_set_xtime(tk, &tmp); | ||
733 | 732 | ||
734 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); | 733 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
735 | 734 | ||
@@ -741,7 +740,7 @@ int do_settimeofday(const struct timespec *tv) | |||
741 | 740 | ||
742 | return 0; | 741 | return 0; |
743 | } | 742 | } |
744 | EXPORT_SYMBOL(do_settimeofday); | 743 | EXPORT_SYMBOL(do_settimeofday64); |
745 | 744 | ||
746 | /** | 745 | /** |
747 | * timekeeping_inject_offset - Adds or subtracts from the current time. | 746 | * timekeeping_inject_offset - Adds or subtracts from the current time. |