diff options
author | Arnd Bergmann <arnd@arndb.de> | 2017-10-19 07:14:45 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2017-10-30 18:14:17 -0400 |
commit | 1572fa03784831b81ec26ec379374cf6bdec04fb (patch) | |
tree | f8a09ed5ae333a1e2d3828bcbb6f80cdc9f85724 | |
parent | e0956dcc4ba74ec4b17e32fc9a156fcba1ef6610 (diff) |
timekeeping: Use timespec64 in timekeeping_inject_offset
As part of changing all the timekeeping code to use 64-bit
time_t consistently, this removes the uses of timeval
and timespec as much as possible from do_adjtimex() and
timekeeping_inject_offset(). The timeval_inject_offset_valid()
and timespec_inject_offset_valid() just complicate this,
so I'm folding them into the respective callers.
This leaves the actual 'struct timex' definition, which
is part of the user-space ABI and should be dealt with
separately when we have agreed on the ABI change.
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>
Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r-- | kernel/time/timekeeping.c | 72 |
1 files changed, 25 insertions, 47 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 7d8e0e842484..c6a35fb3cf76 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -1258,65 +1258,37 @@ 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 | |||
1287 | /** | 1261 | /** |
1288 | * timekeeping_inject_offset - Adds or subtracts from the current time. | 1262 | * timekeeping_inject_offset - Adds or subtracts from the current time. |
1289 | * @tv: pointer to the timespec variable containing the offset | 1263 | * @tv: pointer to the timespec variable containing the offset |
1290 | * | 1264 | * |
1291 | * Adds or subtracts an offset value from the current time. | 1265 | * Adds or subtracts an offset value from the current time. |
1292 | */ | 1266 | */ |
1293 | static int timekeeping_inject_offset(struct timespec *ts) | 1267 | static int timekeeping_inject_offset(struct timespec64 *ts) |
1294 | { | 1268 | { |
1295 | struct timekeeper *tk = &tk_core.timekeeper; | 1269 | struct timekeeper *tk = &tk_core.timekeeper; |
1296 | unsigned long flags; | 1270 | unsigned long flags; |
1297 | struct timespec64 ts64, tmp; | 1271 | struct timespec64 tmp; |
1298 | int ret = 0; | 1272 | int ret = 0; |
1299 | 1273 | ||
1300 | if (!timespec_inject_offset_valid(ts)) | 1274 | if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC) |
1301 | return -EINVAL; | 1275 | return -EINVAL; |
1302 | 1276 | ||
1303 | ts64 = timespec_to_timespec64(*ts); | ||
1304 | |||
1305 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 1277 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
1306 | write_seqcount_begin(&tk_core.seq); | 1278 | write_seqcount_begin(&tk_core.seq); |
1307 | 1279 | ||
1308 | timekeeping_forward_now(tk); | 1280 | timekeeping_forward_now(tk); |
1309 | 1281 | ||
1310 | /* Make sure the proposed value is valid */ | 1282 | /* Make sure the proposed value is valid */ |
1311 | tmp = timespec64_add(tk_xtime(tk), ts64); | 1283 | tmp = timespec64_add(tk_xtime(tk), *ts); |
1312 | if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 || | 1284 | if (timespec64_compare(&tk->wall_to_monotonic, ts) > 0 || |
1313 | !timespec64_valid_strict(&tmp)) { | 1285 | !timespec64_valid_strict(&tmp)) { |
1314 | ret = -EINVAL; | 1286 | ret = -EINVAL; |
1315 | goto error; | 1287 | goto error; |
1316 | } | 1288 | } |
1317 | 1289 | ||
1318 | tk_xtime_add(tk, &ts64); | 1290 | tk_xtime_add(tk, ts); |
1319 | tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts64)); | 1291 | tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *ts)); |
1320 | 1292 | ||
1321 | error: /* even if we error out, we forwarded the time, so call update */ | 1293 | error: /* even if we error out, we forwarded the time, so call update */ |
1322 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); | 1294 | timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); |
@@ -1355,7 +1327,7 @@ int persistent_clock_is_local; | |||
1355 | void timekeeping_warp_clock(void) | 1327 | void timekeeping_warp_clock(void) |
1356 | { | 1328 | { |
1357 | if (sys_tz.tz_minuteswest != 0) { | 1329 | if (sys_tz.tz_minuteswest != 0) { |
1358 | struct timespec adjust; | 1330 | struct timespec64 adjust; |
1359 | 1331 | ||
1360 | persistent_clock_is_local = 1; | 1332 | persistent_clock_is_local = 1; |
1361 | adjust.tv_sec = sys_tz.tz_minuteswest * 60; | 1333 | adjust.tv_sec = sys_tz.tz_minuteswest * 60; |
@@ -2307,9 +2279,9 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, | |||
2307 | } | 2279 | } |
2308 | 2280 | ||
2309 | /** | 2281 | /** |
2310 | * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex | 2282 | * timekeeping_validate_timex - Ensures the timex is ok for use in do_adjtimex |
2311 | */ | 2283 | */ |
2312 | static int ntp_validate_timex(struct timex *txc) | 2284 | static int timekeeping_validate_timex(struct timex *txc) |
2313 | { | 2285 | { |
2314 | if (txc->modes & ADJ_ADJTIME) { | 2286 | if (txc->modes & ADJ_ADJTIME) { |
2315 | /* singleshot must not be used with any other mode bits */ | 2287 | /* singleshot must not be used with any other mode bits */ |
@@ -2337,16 +2309,22 @@ static int ntp_validate_timex(struct timex *txc) | |||
2337 | if (!capable(CAP_SYS_TIME)) | 2309 | if (!capable(CAP_SYS_TIME)) |
2338 | return -EPERM; | 2310 | return -EPERM; |
2339 | 2311 | ||
2340 | if (txc->modes & ADJ_NANO) { | 2312 | /* |
2341 | struct timespec ts; | 2313 | * Validate if a timespec/timeval used to inject a time |
2314 | * offset is valid. Offsets can be postive or negative, so | ||
2315 | * we don't check tv_sec. The value of the timeval/timespec | ||
2316 | * is the sum of its fields,but *NOTE*: | ||
2317 | * The field tv_usec/tv_nsec must always be non-negative and | ||
2318 | * we can't have more nanoseconds/microseconds than a second. | ||
2319 | */ | ||
2320 | if (txc->time.tv_usec < 0) | ||
2321 | return -EINVAL; | ||
2342 | 2322 | ||
2343 | ts.tv_sec = txc->time.tv_sec; | 2323 | if (txc->modes & ADJ_NANO) { |
2344 | ts.tv_nsec = txc->time.tv_usec; | 2324 | if (txc->time.tv_usec >= NSEC_PER_SEC) |
2345 | if (!timespec_inject_offset_valid(&ts)) | ||
2346 | return -EINVAL; | 2325 | return -EINVAL; |
2347 | |||
2348 | } else { | 2326 | } else { |
2349 | if (!timeval_inject_offset_valid(&txc->time)) | 2327 | if (txc->time.tv_usec >= USEC_PER_SEC) |
2350 | return -EINVAL; | 2328 | return -EINVAL; |
2351 | } | 2329 | } |
2352 | } | 2330 | } |
@@ -2378,12 +2356,12 @@ int do_adjtimex(struct timex *txc) | |||
2378 | int ret; | 2356 | int ret; |
2379 | 2357 | ||
2380 | /* Validate the data before disabling interrupts */ | 2358 | /* Validate the data before disabling interrupts */ |
2381 | ret = ntp_validate_timex(txc); | 2359 | ret = timekeeping_validate_timex(txc); |
2382 | if (ret) | 2360 | if (ret) |
2383 | return ret; | 2361 | return ret; |
2384 | 2362 | ||
2385 | if (txc->modes & ADJ_SETOFFSET) { | 2363 | if (txc->modes & ADJ_SETOFFSET) { |
2386 | struct timespec delta; | 2364 | struct timespec64 delta; |
2387 | delta.tv_sec = txc->time.tv_sec; | 2365 | delta.tv_sec = txc->time.tv_sec; |
2388 | delta.tv_nsec = txc->time.tv_usec; | 2366 | delta.tv_nsec = txc->time.tv_usec; |
2389 | if (!(txc->modes & ADJ_NANO)) | 2367 | if (!(txc->modes & ADJ_NANO)) |