diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 13:13:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 13:13:28 -0500 |
commit | d82012695ef29e4e1c8153ccf43098ec8e50369e (patch) | |
tree | 80a379de91a332a6dca5f035d10421bb6d988b80 | |
parent | 3eb5b893ebec7325ac9e6b8e4864af89a9ca1ed1 (diff) | |
parent | dbe7aa622db96b5cd601f59d09c4f00b98b76079 (diff) |
Merge branch 'timers-2038-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull more 2038 timer work from Thomas Gleixner:
"Two more patches for the ongoing 2038 work:
- New accessors to clock MONOTONIC and REALTIME seconds
This is a seperate branch as Arnd has follow up work depending on
this"
* 'timers-2038-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
timekeeping: Provide y2038 safe accessor to the seconds portion of CLOCK_REALTIME
timekeeping: Provide fast accessor to the seconds part of CLOCK_MONOTONIC
-rw-r--r-- | include/linux/timekeeper_internal.h | 2 | ||||
-rw-r--r-- | include/linux/timekeeping.h | 2 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 68 |
3 files changed, 67 insertions, 5 deletions
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index 95640dcd1899..05af9a334893 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h | |||
@@ -42,6 +42,7 @@ struct tk_read_base { | |||
42 | * struct timekeeper - Structure holding internal timekeeping values. | 42 | * struct timekeeper - Structure holding internal timekeeping values. |
43 | * @tkr: The readout base structure | 43 | * @tkr: The readout base structure |
44 | * @xtime_sec: Current CLOCK_REALTIME time in seconds | 44 | * @xtime_sec: Current CLOCK_REALTIME time in seconds |
45 | * @ktime_sec: Current CLOCK_MONOTONIC time in seconds | ||
45 | * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset | 46 | * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset |
46 | * @offs_real: Offset clock monotonic -> clock realtime | 47 | * @offs_real: Offset clock monotonic -> clock realtime |
47 | * @offs_boot: Offset clock monotonic -> clock boottime | 48 | * @offs_boot: Offset clock monotonic -> clock boottime |
@@ -77,6 +78,7 @@ struct tk_read_base { | |||
77 | struct timekeeper { | 78 | struct timekeeper { |
78 | struct tk_read_base tkr; | 79 | struct tk_read_base tkr; |
79 | u64 xtime_sec; | 80 | u64 xtime_sec; |
81 | unsigned long ktime_sec; | ||
80 | struct timespec64 wall_to_monotonic; | 82 | struct timespec64 wall_to_monotonic; |
81 | ktime_t offs_real; | 83 | ktime_t offs_real; |
82 | ktime_t offs_boot; | 84 | ktime_t offs_boot; |
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 961fea373f83..9b63d13ba82b 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h | |||
@@ -28,6 +28,8 @@ struct timespec __current_kernel_time(void); | |||
28 | struct timespec64 get_monotonic_coarse64(void); | 28 | struct timespec64 get_monotonic_coarse64(void); |
29 | extern void getrawmonotonic64(struct timespec64 *ts); | 29 | extern void getrawmonotonic64(struct timespec64 *ts); |
30 | extern void ktime_get_ts64(struct timespec64 *ts); | 30 | extern void ktime_get_ts64(struct timespec64 *ts); |
31 | extern time64_t ktime_get_seconds(void); | ||
32 | extern time64_t ktime_get_real_seconds(void); | ||
31 | 33 | ||
32 | extern int __getnstimeofday64(struct timespec64 *tv); | 34 | extern int __getnstimeofday64(struct timespec64 *tv); |
33 | extern void getnstimeofday64(struct timespec64 *tv); | 35 | extern void getnstimeofday64(struct timespec64 *tv); |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 2dc0646258ae..6a931852082f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); | |||
417 | */ | 417 | */ |
418 | static inline void tk_update_ktime_data(struct timekeeper *tk) | 418 | static inline void tk_update_ktime_data(struct timekeeper *tk) |
419 | { | 419 | { |
420 | s64 nsec; | 420 | u64 seconds; |
421 | u32 nsec; | ||
421 | 422 | ||
422 | /* | 423 | /* |
423 | * The xtime based monotonic readout is: | 424 | * The xtime based monotonic readout is: |
@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) | |||
426 | * nsec = base_mono + now(); | 427 | * nsec = base_mono + now(); |
427 | * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec | 428 | * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec |
428 | */ | 429 | */ |
429 | nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); | 430 | seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); |
430 | nsec *= NSEC_PER_SEC; | 431 | nsec = (u32) tk->wall_to_monotonic.tv_nsec; |
431 | nsec += tk->wall_to_monotonic.tv_nsec; | 432 | tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); |
432 | tk->tkr.base_mono = ns_to_ktime(nsec); | ||
433 | 433 | ||
434 | /* Update the monotonic raw base */ | 434 | /* Update the monotonic raw base */ |
435 | tk->base_raw = timespec64_to_ktime(tk->raw_time); | 435 | tk->base_raw = timespec64_to_ktime(tk->raw_time); |
436 | |||
437 | /* | ||
438 | * The sum of the nanoseconds portions of xtime and | ||
439 | * wall_to_monotonic can be greater/equal one second. Take | ||
440 | * this into account before updating tk->ktime_sec. | ||
441 | */ | ||
442 | nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift); | ||
443 | if (nsec >= NSEC_PER_SEC) | ||
444 | seconds++; | ||
445 | tk->ktime_sec = seconds; | ||
436 | } | 446 | } |
437 | 447 | ||
438 | /* must hold timekeeper_lock */ | 448 | /* must hold timekeeper_lock */ |
@@ -648,6 +658,54 @@ void ktime_get_ts64(struct timespec64 *ts) | |||
648 | } | 658 | } |
649 | EXPORT_SYMBOL_GPL(ktime_get_ts64); | 659 | EXPORT_SYMBOL_GPL(ktime_get_ts64); |
650 | 660 | ||
661 | /** | ||
662 | * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC | ||
663 | * | ||
664 | * Returns the seconds portion of CLOCK_MONOTONIC with a single non | ||
665 | * serialized read. tk->ktime_sec is of type 'unsigned long' so this | ||
666 | * works on both 32 and 64 bit systems. On 32 bit systems the readout | ||
667 | * covers ~136 years of uptime which should be enough to prevent | ||
668 | * premature wrap arounds. | ||
669 | */ | ||
670 | time64_t ktime_get_seconds(void) | ||
671 | { | ||
672 | struct timekeeper *tk = &tk_core.timekeeper; | ||
673 | |||
674 | WARN_ON(timekeeping_suspended); | ||
675 | return tk->ktime_sec; | ||
676 | } | ||
677 | EXPORT_SYMBOL_GPL(ktime_get_seconds); | ||
678 | |||
679 | /** | ||
680 | * ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME | ||
681 | * | ||
682 | * Returns the wall clock seconds since 1970. This replaces the | ||
683 | * get_seconds() interface which is not y2038 safe on 32bit systems. | ||
684 | * | ||
685 | * For 64bit systems the fast access to tk->xtime_sec is preserved. On | ||
686 | * 32bit systems the access must be protected with the sequence | ||
687 | * counter to provide "atomic" access to the 64bit tk->xtime_sec | ||
688 | * value. | ||
689 | */ | ||
690 | time64_t ktime_get_real_seconds(void) | ||
691 | { | ||
692 | struct timekeeper *tk = &tk_core.timekeeper; | ||
693 | time64_t seconds; | ||
694 | unsigned int seq; | ||
695 | |||
696 | if (IS_ENABLED(CONFIG_64BIT)) | ||
697 | return tk->xtime_sec; | ||
698 | |||
699 | do { | ||
700 | seq = read_seqcount_begin(&tk_core.seq); | ||
701 | seconds = tk->xtime_sec; | ||
702 | |||
703 | } while (read_seqcount_retry(&tk_core.seq, seq)); | ||
704 | |||
705 | return seconds; | ||
706 | } | ||
707 | EXPORT_SYMBOL_GPL(ktime_get_real_seconds); | ||
708 | |||
651 | #ifdef CONFIG_NTP_PPS | 709 | #ifdef CONFIG_NTP_PPS |
652 | 710 | ||
653 | /** | 711 | /** |