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

rtc/lib: Provide y2038 safe rtc_tm_to_time()/rtc_time_to_tm() replacement

As part of addressing "y2038 problem" for in-kernel uses, this patch
adds safe rtc_tm_to_time64()/rtc_time64_to_tm() respectively using
time64_t.

After this patch, rtc_tm_to_time() is deprecated and all its call
sites will be fixed using corresponding safe versions, it can be
removed when having no users. Also change rtc_tm_to_time64() to
return time64_t directly instead of just as a parameter like
rtc_tm_to_time() does.

After this patch, rtc_time_to_tm() is deprecated and all its call
sites will be fixed using corresponding safe versions, it can be
removed when having no users.

In addition, change rtc_tm_to_ktime() and rtc_ktime_to_tm() to use
the safe version in passing.

Signed-off-by: pang.xunlei <pang.xunlei@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>

authored by

pang.xunlei and committed by
John Stultz
c2c11ae4 5322e4c2

+39 -20
+20 -18
drivers/rtc/rtc-lib.c
··· 45 45 } 46 46 EXPORT_SYMBOL(rtc_year_days); 47 47 48 + 48 49 /* 50 + * rtc_time_to_tm64 - Converts time64_t to rtc_time. 49 51 * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. 50 52 */ 51 - void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) 53 + void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) 52 54 { 53 55 unsigned int month, year; 56 + unsigned long secs; 54 57 int days; 55 58 56 - days = time / 86400; 57 - time -= (unsigned int) days * 86400; 59 + /* time must be positive */ 60 + days = div_s64(time, 86400); 61 + secs = time - (unsigned int) days * 86400; 58 62 59 63 /* day of the week, 1970-01-01 was a Thursday */ 60 64 tm->tm_wday = (days + 4) % 7; ··· 85 81 tm->tm_mon = month; 86 82 tm->tm_mday = days + 1; 87 83 88 - tm->tm_hour = time / 3600; 89 - time -= tm->tm_hour * 3600; 90 - tm->tm_min = time / 60; 91 - tm->tm_sec = time - tm->tm_min * 60; 84 + tm->tm_hour = secs / 3600; 85 + secs -= tm->tm_hour * 3600; 86 + tm->tm_min = secs / 60; 87 + tm->tm_sec = secs - tm->tm_min * 60; 92 88 93 89 tm->tm_isdst = 0; 94 90 } 95 - EXPORT_SYMBOL(rtc_time_to_tm); 91 + EXPORT_SYMBOL(rtc_time64_to_tm); 96 92 97 93 /* 98 94 * Does the rtc_time represent a valid date/time? ··· 113 109 EXPORT_SYMBOL(rtc_valid_tm); 114 110 115 111 /* 112 + * rtc_tm_to_time64 - Converts rtc_time to time64_t. 116 113 * Convert Gregorian date to seconds since 01-01-1970 00:00:00. 117 114 */ 118 - int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) 115 + time64_t rtc_tm_to_time64(struct rtc_time *tm) 119 116 { 120 - *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 117 + return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 121 118 tm->tm_hour, tm->tm_min, tm->tm_sec); 122 - return 0; 123 119 } 124 - EXPORT_SYMBOL(rtc_tm_to_time); 120 + EXPORT_SYMBOL(rtc_tm_to_time64); 125 121 126 122 /* 127 123 * Convert rtc_time to ktime 128 124 */ 129 125 ktime_t rtc_tm_to_ktime(struct rtc_time tm) 130 126 { 131 - time_t time; 132 - rtc_tm_to_time(&tm, &time); 133 - return ktime_set(time, 0); 127 + return ktime_set(rtc_tm_to_time64(&tm), 0); 134 128 } 135 129 EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); 136 130 ··· 137 135 */ 138 136 struct rtc_time rtc_ktime_to_tm(ktime_t kt) 139 137 { 140 - struct timespec ts; 138 + struct timespec64 ts; 141 139 struct rtc_time ret; 142 140 143 - ts = ktime_to_timespec(kt); 141 + ts = ktime_to_timespec64(kt); 144 142 /* Round up any ns */ 145 143 if (ts.tv_nsec) 146 144 ts.tv_sec++; 147 - rtc_time_to_tm(ts.tv_sec, &ret); 145 + rtc_time64_to_tm(ts.tv_sec, &ret); 148 146 return ret; 149 147 } 150 148 EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
+19 -2
include/linux/rtc.h
··· 19 19 extern int rtc_month_days(unsigned int month, unsigned int year); 20 20 extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year); 21 21 extern int rtc_valid_tm(struct rtc_time *tm); 22 - extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); 23 - extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); 22 + extern time64_t rtc_tm_to_time64(struct rtc_time *tm); 23 + extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm); 24 24 ktime_t rtc_tm_to_ktime(struct rtc_time tm); 25 25 struct rtc_time rtc_ktime_to_tm(ktime_t kt); 26 26 27 + /** 28 + * Deprecated. Use rtc_time64_to_tm(). 29 + */ 30 + static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) 31 + { 32 + rtc_time64_to_tm(time, tm); 33 + } 34 + 35 + /** 36 + * Deprecated. Use rtc_tm_to_time64(). 37 + */ 38 + static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) 39 + { 40 + *time = rtc_tm_to_time64(tm); 41 + 42 + return 0; 43 + } 27 44 28 45 #include <linux/device.h> 29 46 #include <linux/seq_file.h>