diff options
author | Arnd Bergmann <arnd@arndb.de> | 2017-10-19 07:14:44 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2017-10-30 18:13:35 -0400 |
commit | e0956dcc4ba74ec4b17e32fc9a156fcba1ef6610 (patch) | |
tree | 63b47cbfeb91f6118fc72c896be4b6922e1e9433 | |
parent | 0f295b0650c90362b4111f46d7f9149a0a4191be (diff) |
timekeeping: Consolidate timekeeping_inject_offset code
The code to check the adjtimex() or clock_adjtime() arguments is spread
out across multiple files for presumably only historic reasons. As a
preparatation for a rework to get rid of the use of 'struct timeval'
and 'struct timespec' in there, this moves all the portions into
kernel/time/timekeeping.c and marks them as 'static'.
The warp_clock() function here is not as closely related as the others,
but I feel it still makes sense to move it here in order to consolidate
all callers of timekeeping_inject_offset().
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Miroslav Lichvar <mlichvar@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Stephen Boyd <stephen.boyd@linaro.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
[jstultz: Whitespace fixup]
Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r-- | include/linux/time.h | 26 | ||||
-rw-r--r-- | kernel/time/ntp.c | 61 | ||||
-rw-r--r-- | kernel/time/ntp_internal.h | 1 | ||||
-rw-r--r-- | kernel/time/time.c | 36 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 123 | ||||
-rw-r--r-- | kernel/time/timekeeping.h | 2 |
6 files changed, 123 insertions, 126 deletions
diff --git a/include/linux/time.h b/include/linux/time.h index 9bc1f945777c..c0fbad08448f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h | |||
@@ -134,32 +134,6 @@ static inline bool timeval_valid(const struct timeval *tv) | |||
134 | 134 | ||
135 | extern struct timespec timespec_trunc(struct timespec t, unsigned gran); | 135 | extern struct timespec timespec_trunc(struct timespec t, unsigned gran); |
136 | 136 | ||
137 | /* | ||
138 | * Validates if a timespec/timeval used to inject a time offset is valid. | ||
139 | * Offsets can be postive or negative. The value of the timeval/timespec | ||
140 | * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must | ||
141 | * always be non-negative. | ||
142 | */ | ||
143 | static inline bool timeval_inject_offset_valid(const struct timeval *tv) | ||
144 | { | ||
145 | /* We don't check the tv_sec as it can be positive or negative */ | ||
146 | |||
147 | /* Can't have more microseconds then a second */ | ||
148 | if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC) | ||
149 | return false; | ||
150 | return true; | ||
151 | } | ||
152 | |||
153 | static inline bool timespec_inject_offset_valid(const struct timespec *ts) | ||
154 | { | ||
155 | /* We don't check the tv_sec as it can be positive or negative */ | ||
156 | |||
157 | /* Can't have more nanoseconds then a second */ | ||
158 | if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC) | ||
159 | return false; | ||
160 | return true; | ||
161 | } | ||
162 | |||
163 | /* Some architectures do not supply their own clocksource. | 137 | /* Some architectures do not supply their own clocksource. |
164 | * This is mainly the case in architectures that get their | 138 | * This is mainly the case in architectures that get their |
165 | * inter-tick times by reading the counter on their interval | 139 | * inter-tick times by reading the counter on their interval |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index bc19de1a0683..90f84582a076 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -713,67 +713,6 @@ static inline void process_adjtimex_modes(struct timex *txc, | |||
713 | } | 713 | } |
714 | 714 | ||
715 | 715 | ||
716 | |||
717 | /** | ||
718 | * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex | ||
719 | */ | ||
720 | int ntp_validate_timex(struct timex *txc) | ||
721 | { | ||
722 | if (txc->modes & ADJ_ADJTIME) { | ||
723 | /* singleshot must not be used with any other mode bits */ | ||
724 | if (!(txc->modes & ADJ_OFFSET_SINGLESHOT)) | ||
725 | return -EINVAL; | ||
726 | if (!(txc->modes & ADJ_OFFSET_READONLY) && | ||
727 | !capable(CAP_SYS_TIME)) | ||
728 | return -EPERM; | ||
729 | } else { | ||
730 | /* In order to modify anything, you gotta be super-user! */ | ||
731 | if (txc->modes && !capable(CAP_SYS_TIME)) | ||
732 | return -EPERM; | ||
733 | /* | ||
734 | * if the quartz is off by more than 10% then | ||
735 | * something is VERY wrong! | ||
736 | */ | ||
737 | if (txc->modes & ADJ_TICK && | ||
738 | (txc->tick < 900000/USER_HZ || | ||
739 | txc->tick > 1100000/USER_HZ)) | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | |||
743 | if (txc->modes & ADJ_SETOFFSET) { | ||
744 | /* In order to inject time, you gotta be super-user! */ | ||
745 | if (!capable(CAP_SYS_TIME)) | ||
746 | return -EPERM; | ||
747 | |||
748 | if (txc->modes & ADJ_NANO) { | ||
749 | struct timespec ts; | ||
750 | |||
751 | ts.tv_sec = txc->time.tv_sec; | ||
752 | ts.tv_nsec = txc->time.tv_usec; | ||
753 | if (!timespec_inject_offset_valid(&ts)) | ||
754 | return -EINVAL; | ||
755 | |||
756 | } else { | ||
757 | if (!timeval_inject_offset_valid(&txc->time)) | ||
758 | return -EINVAL; | ||
759 | } | ||
760 | } | ||
761 | |||
762 | /* | ||
763 | * Check for potential multiplication overflows that can | ||
764 | * only happen on 64-bit systems: | ||
765 | */ | ||
766 | if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) { | ||
767 | if (LLONG_MIN / PPM_SCALE > txc->freq) | ||
768 | return -EINVAL; | ||
769 | if (LLONG_MAX / PPM_SCALE < txc->freq) | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | |||
777 | /* | 716 | /* |
778 | * adjtimex mainly allows reading (and writing, if superuser) of | 717 | * adjtimex mainly allows reading (and writing, if superuser) of |
779 | * kernel time-keeping variables. used by xntpd. | 718 | * kernel time-keeping variables. used by xntpd. |
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index d8a7c11fa71a..74b52cd48209 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h | |||
@@ -7,7 +7,6 @@ extern void ntp_clear(void); | |||
7 | extern u64 ntp_tick_length(void); | 7 | extern u64 ntp_tick_length(void); |
8 | extern ktime_t ntp_get_next_leap(void); | 8 | extern ktime_t ntp_get_next_leap(void); |
9 | extern int second_overflow(time64_t secs); | 9 | extern int second_overflow(time64_t secs); |
10 | extern int ntp_validate_timex(struct timex *); | ||
11 | extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *); | 10 | extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *); |
12 | extern void __hardpps(const struct timespec64 *, const struct timespec64 *); | 11 | extern void __hardpps(const struct timespec64 *, const struct timespec64 *); |
13 | #endif /* _LINUX_NTP_INTERNAL_H */ | 12 | #endif /* _LINUX_NTP_INTERNAL_H */ |
diff --git a/kernel/time/time.c b/kernel/time/time.c index 44a8c1402133..04684e294f00 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c | |||
@@ -158,40 +158,6 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Indicates if there is an offset between the system clock and the hardware | ||
162 | * clock/persistent clock/rtc. | ||
163 | */ | ||
164 | int persistent_clock_is_local; | ||
165 | |||
166 | /* | ||
167 | * Adjust the time obtained from the CMOS to be UTC time instead of | ||
168 | * local time. | ||
169 | * | ||
170 | * This is ugly, but preferable to the alternatives. Otherwise we | ||
171 | * would either need to write a program to do it in /etc/rc (and risk | ||
172 | * confusion if the program gets run more than once; it would also be | ||
173 | * hard to make the program warp the clock precisely n hours) or | ||
174 | * compile in the timezone information into the kernel. Bad, bad.... | ||
175 | * | ||
176 | * - TYT, 1992-01-01 | ||
177 | * | ||
178 | * The best thing to do is to keep the CMOS clock in universal time (UTC) | ||
179 | * as real UNIX machines always do it. This avoids all headaches about | ||
180 | * daylight saving times and warping kernel clocks. | ||
181 | */ | ||
182 | static inline void warp_clock(void) | ||
183 | { | ||
184 | if (sys_tz.tz_minuteswest != 0) { | ||
185 | struct timespec adjust; | ||
186 | |||
187 | persistent_clock_is_local = 1; | ||
188 | adjust.tv_sec = sys_tz.tz_minuteswest * 60; | ||
189 | adjust.tv_nsec = 0; | ||
190 | timekeeping_inject_offset(&adjust); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * In case for some reason the CMOS clock has not already been running | 161 | * In case for some reason the CMOS clock has not already been running |
196 | * in UTC, but in some local time: The first time we set the timezone, | 162 | * in UTC, but in some local time: The first time we set the timezone, |
197 | * we will warp the clock so that it is ticking UTC time instead of | 163 | * we will warp the clock so that it is ticking UTC time instead of |
@@ -224,7 +190,7 @@ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz | |||
224 | if (firsttime) { | 190 | if (firsttime) { |
225 | firsttime = 0; | 191 | firsttime = 0; |
226 | if (!tv) | 192 | if (!tv) |
227 | warp_clock(); | 193 | timekeeping_warp_clock(); |
228 | } | 194 | } |
229 | } | 195 | } |
230 | if (tv) | 196 | if (tv) |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 2cafb49aa65e..7d8e0e842484 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -1258,13 +1258,39 @@ out: | |||
1258 | } | 1258 | } |
1259 | EXPORT_SYMBOL(do_settimeofday64); | 1259 | EXPORT_SYMBOL(do_settimeofday64); |
1260 | 1260 | ||
1261 | /* | ||
1262 | * Validates if a timespec/timeval used to inject a time offset is valid. | ||
1263 | * Offsets can be postive or negative. The value of the timeval/timespec | ||
1264 | * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must | ||
1265 | * always be non-negative. | ||
1266 | */ | ||
1267 | static inline bool timeval_inject_offset_valid(const struct timeval *tv) | ||
1268 | { | ||
1269 | /* We don't check the tv_sec as it can be positive or negative */ | ||
1270 | |||
1271 | /* Can't have more microseconds then a second */ | ||
1272 | if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC) | ||
1273 | return false; | ||
1274 | return true; | ||
1275 | } | ||
1276 | |||
1277 | static inline bool timespec_inject_offset_valid(const struct timespec *ts) | ||
1278 | { | ||
1279 | /* We don't check the tv_sec as it can be positive or negative */ | ||
1280 | |||
1281 | /* Can't have more nanoseconds then a second */ | ||
1282 | if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC) | ||
1283 | return false; | ||
1284 | return true; | ||
1285 | } | ||
1286 | |||
1261 | /** | 1287 | /** |
1262 | * timekeeping_inject_offset - Adds or subtracts from the current time. | 1288 | * timekeeping_inject_offset - Adds or subtracts from the current time. |
1263 | * @tv: pointer to the timespec variable containing the offset | 1289 | * @tv: pointer to the timespec variable containing the offset |
1264 | * | 1290 | * |
1265 | * Adds or subtracts an offset value from the current time. | 1291 | * Adds or subtracts an offset value from the current time. |
1266 | */ | 1292 | */ |
1267 | int timekeeping_inject_offset(struct timespec *ts) | 1293 | static int timekeeping_inject_offset(struct timespec *ts) |
1268 | { | 1294 | { |
1269 | struct timekeeper *tk = &tk_core.timekeeper; | 1295 | struct timekeeper *tk = &tk_core.timekeeper; |
1270 | unsigned long flags; | 1296 | unsigned long flags; |
@@ -1303,7 +1329,40 @@ error: /* even if we error out, we forwarded the time, so call update */ | |||
1303 | 1329 | ||
1304 | return ret; | 1330 | return ret; |
1305 | } | 1331 | } |
1306 | EXPORT_SYMBOL(timekeeping_inject_offset); | 1332 | |
1333 | /* | ||
1334 | * Indicates if there is an offset between the system clock and the hardware | ||
1335 | * clock/persistent clock/rtc. | ||
1336 | */ | ||
1337 | int persistent_clock_is_local; | ||
1338 | |||
1339 | /* | ||
1340 | * Adjust the time obtained from the CMOS to be UTC time instead of | ||
1341 | * local time. | ||
1342 | * | ||
1343 | * This is ugly, but preferable to the alternatives. Otherwise we | ||
1344 | * would either need to write a program to do it in /etc/rc (and risk | ||
1345 | * confusion if the program gets run more than once; it would also be | ||
1346 | * hard to make the program warp the clock precisely n hours) or | ||
1347 | * compile in the timezone information into the kernel. Bad, bad.... | ||
1348 | * | ||
1349 | * - TYT, 1992-01-01 | ||
1350 | * | ||
1351 | * The best thing to do is to keep the CMOS clock in universal time (UTC) | ||
1352 | * as real UNIX machines always do it. This avoids all headaches about | ||
1353 | * daylight saving times and warping kernel clocks. | ||
1354 | */ | ||
1355 | void timekeeping_warp_clock(void) | ||
1356 | { | ||
1357 | if (sys_tz.tz_minuteswest != 0) { | ||
1358 | struct timespec adjust; | ||
1359 | |||
1360 | persistent_clock_is_local = 1; | ||
1361 | adjust.tv_sec = sys_tz.tz_minuteswest * 60; | ||
1362 | adjust.tv_nsec = 0; | ||
1363 | timekeeping_inject_offset(&adjust); | ||
1364 | } | ||
1365 | } | ||
1307 | 1366 | ||
1308 | /** | 1367 | /** |
1309 | * __timekeeping_set_tai_offset - Sets the TAI offset from UTC and monotonic | 1368 | * __timekeeping_set_tai_offset - Sets the TAI offset from UTC and monotonic |
@@ -2248,6 +2307,66 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, | |||
2248 | } | 2307 | } |
2249 | 2308 | ||
2250 | /** | 2309 | /** |
2310 | * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex | ||
2311 | */ | ||
2312 | static int ntp_validate_timex(struct timex *txc) | ||
2313 | { | ||
2314 | if (txc->modes & ADJ_ADJTIME) { | ||
2315 | /* singleshot must not be used with any other mode bits */ | ||
2316 | if (!(txc->modes & ADJ_OFFSET_SINGLESHOT)) | ||
2317 | return -EINVAL; | ||
2318 | if (!(txc->modes & ADJ_OFFSET_READONLY) && | ||
2319 | !capable(CAP_SYS_TIME)) | ||
2320 | return -EPERM; | ||
2321 | } else { | ||
2322 | /* In order to modify anything, you gotta be super-user! */ | ||
2323 | if (txc->modes && !capable(CAP_SYS_TIME)) | ||
2324 | return -EPERM; | ||
2325 | /* | ||
2326 | * if the quartz is off by more than 10% then | ||
2327 | * something is VERY wrong! | ||
2328 | */ | ||
2329 | if (txc->modes & ADJ_TICK && | ||
2330 | (txc->tick < 900000/USER_HZ || | ||
2331 | txc->tick > 1100000/USER_HZ)) | ||
2332 | return -EINVAL; | ||
2333 | } | ||
2334 | |||
2335 | if (txc->modes & ADJ_SETOFFSET) { | ||
2336 | /* In order to inject time, you gotta be super-user! */ | ||
2337 | if (!capable(CAP_SYS_TIME)) | ||
2338 | return -EPERM; | ||
2339 | |||
2340 | if (txc->modes & ADJ_NANO) { | ||
2341 | struct timespec ts; | ||
2342 | |||
2343 | ts.tv_sec = txc->time.tv_sec; | ||
2344 | ts.tv_nsec = txc->time.tv_usec; | ||
2345 | if (!timespec_inject_offset_valid(&ts)) | ||
2346 | return -EINVAL; | ||
2347 | |||
2348 | } else { | ||
2349 | if (!timeval_inject_offset_valid(&txc->time)) | ||
2350 | return -EINVAL; | ||
2351 | } | ||
2352 | } | ||
2353 | |||
2354 | /* | ||
2355 | * Check for potential multiplication overflows that can | ||
2356 | * only happen on 64-bit systems: | ||
2357 | */ | ||
2358 | if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) { | ||
2359 | if (LLONG_MIN / PPM_SCALE > txc->freq) | ||
2360 | return -EINVAL; | ||
2361 | if (LLONG_MAX / PPM_SCALE < txc->freq) | ||
2362 | return -EINVAL; | ||
2363 | } | ||
2364 | |||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | |||
2369 | /** | ||
2251 | * do_adjtimex() - Accessor function to NTP __do_adjtimex function | 2370 | * do_adjtimex() - Accessor function to NTP __do_adjtimex function |
2252 | */ | 2371 | */ |
2253 | int do_adjtimex(struct timex *txc) | 2372 | int do_adjtimex(struct timex *txc) |
diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h index d0914676d4c5..44aec7893cdd 100644 --- a/kernel/time/timekeeping.h +++ b/kernel/time/timekeeping.h | |||
@@ -10,7 +10,7 @@ extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, | |||
10 | 10 | ||
11 | extern int timekeeping_valid_for_hres(void); | 11 | extern int timekeeping_valid_for_hres(void); |
12 | extern u64 timekeeping_max_deferment(void); | 12 | extern u64 timekeeping_max_deferment(void); |
13 | extern int timekeeping_inject_offset(struct timespec *ts); | 13 | extern void timekeeping_warp_clock(void); |
14 | extern int timekeeping_suspend(void); | 14 | extern int timekeeping_suspend(void); |
15 | extern void timekeeping_resume(void); | 15 | extern void timekeeping_resume(void); |
16 | 16 | ||