summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-10-19 07:14:44 -0400
committerJohn Stultz <john.stultz@linaro.org>2017-10-30 18:13:35 -0400
commite0956dcc4ba74ec4b17e32fc9a156fcba1ef6610 (patch)
tree63b47cbfeb91f6118fc72c896be4b6922e1e9433
parent0f295b0650c90362b4111f46d7f9149a0a4191be (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.h26
-rw-r--r--kernel/time/ntp.c61
-rw-r--r--kernel/time/ntp_internal.h1
-rw-r--r--kernel/time/time.c36
-rw-r--r--kernel/time/timekeeping.c123
-rw-r--r--kernel/time/timekeeping.h2
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
135extern struct timespec timespec_trunc(struct timespec t, unsigned gran); 135extern 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 */
143static 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
153static 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 */
720int 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);
7extern u64 ntp_tick_length(void); 7extern u64 ntp_tick_length(void);
8extern ktime_t ntp_get_next_leap(void); 8extern ktime_t ntp_get_next_leap(void);
9extern int second_overflow(time64_t secs); 9extern int second_overflow(time64_t secs);
10extern int ntp_validate_timex(struct timex *);
11extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *); 10extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
12extern void __hardpps(const struct timespec64 *, const struct timespec64 *); 11extern 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 */
164int 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 */
182static 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}
1259EXPORT_SYMBOL(do_settimeofday64); 1259EXPORT_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 */
1267static 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
1277static 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 */
1267int timekeeping_inject_offset(struct timespec *ts) 1293static 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}
1306EXPORT_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 */
1337int 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 */
1355void 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 */
2312static 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 */
2253int do_adjtimex(struct timex *txc) 2372int 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
11extern int timekeeping_valid_for_hres(void); 11extern int timekeeping_valid_for_hres(void);
12extern u64 timekeeping_max_deferment(void); 12extern u64 timekeeping_max_deferment(void);
13extern int timekeeping_inject_offset(struct timespec *ts); 13extern void timekeeping_warp_clock(void);
14extern int timekeeping_suspend(void); 14extern int timekeeping_suspend(void);
15extern void timekeeping_resume(void); 15extern void timekeeping_resume(void);
16 16