Skip to content

Commit d820126

Browse files
committed
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
2 parents 3eb5b89 + dbe7aa6 commit d820126

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

include/linux/timekeeper_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct tk_read_base {
4242
* struct timekeeper - Structure holding internal timekeeping values.
4343
* @tkr: The readout base structure
4444
* @xtime_sec: Current CLOCK_REALTIME time in seconds
45+
* @ktime_sec: Current CLOCK_MONOTONIC time in seconds
4546
* @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
4647
* @offs_real: Offset clock monotonic -> clock realtime
4748
* @offs_boot: Offset clock monotonic -> clock boottime
@@ -77,6 +78,7 @@ struct tk_read_base {
7778
struct timekeeper {
7879
struct tk_read_base tkr;
7980
u64 xtime_sec;
81+
unsigned long ktime_sec;
8082
struct timespec64 wall_to_monotonic;
8183
ktime_t offs_real;
8284
ktime_t offs_boot;

include/linux/timekeeping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct timespec __current_kernel_time(void);
2828
struct timespec64 get_monotonic_coarse64(void);
2929
extern void getrawmonotonic64(struct timespec64 *ts);
3030
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);
3133

3234
extern int __getnstimeofday64(struct timespec64 *tv);
3335
extern void getnstimeofday64(struct timespec64 *tv);

kernel/time/timekeeping.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
417417
*/
418418
static inline void tk_update_ktime_data(struct timekeeper *tk)
419419
{
420-
s64 nsec;
420+
u64 seconds;
421+
u32 nsec;
421422

422423
/*
423424
* The xtime based monotonic readout is:
@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
426427
* nsec = base_mono + now();
427428
* ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
428429
*/
429-
nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
430-
nsec *= NSEC_PER_SEC;
431-
nsec += tk->wall_to_monotonic.tv_nsec;
432-
tk->tkr.base_mono = ns_to_ktime(nsec);
430+
seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
431+
nsec = (u32) tk->wall_to_monotonic.tv_nsec;
432+
tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
433433

434434
/* Update the monotonic raw base */
435435
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;
436446
}
437447

438448
/* must hold timekeeper_lock */
@@ -648,6 +658,54 @@ void ktime_get_ts64(struct timespec64 *ts)
648658
}
649659
EXPORT_SYMBOL_GPL(ktime_get_ts64);
650660

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+
651709
#ifdef CONFIG_NTP_PPS
652710

653711
/**

0 commit comments

Comments
 (0)