提交 d8201269 编写于 作者: L Linus Torvalds

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
...@@ -42,6 +42,7 @@ struct tk_read_base { ...@@ -42,6 +42,7 @@ struct tk_read_base {
* struct timekeeper - Structure holding internal timekeeping values. * struct timekeeper - Structure holding internal timekeeping values.
* @tkr: The readout base structure * @tkr: The readout base structure
* @xtime_sec: Current CLOCK_REALTIME time in seconds * @xtime_sec: Current CLOCK_REALTIME time in seconds
* @ktime_sec: Current CLOCK_MONOTONIC time in seconds
* @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
* @offs_real: Offset clock monotonic -> clock realtime * @offs_real: Offset clock monotonic -> clock realtime
* @offs_boot: Offset clock monotonic -> clock boottime * @offs_boot: Offset clock monotonic -> clock boottime
...@@ -77,6 +78,7 @@ struct tk_read_base { ...@@ -77,6 +78,7 @@ struct tk_read_base {
struct timekeeper { struct timekeeper {
struct tk_read_base tkr; struct tk_read_base tkr;
u64 xtime_sec; u64 xtime_sec;
unsigned long ktime_sec;
struct timespec64 wall_to_monotonic; struct timespec64 wall_to_monotonic;
ktime_t offs_real; ktime_t offs_real;
ktime_t offs_boot; ktime_t offs_boot;
......
...@@ -28,6 +28,8 @@ struct timespec __current_kernel_time(void); ...@@ -28,6 +28,8 @@ struct timespec __current_kernel_time(void);
struct timespec64 get_monotonic_coarse64(void); struct timespec64 get_monotonic_coarse64(void);
extern void getrawmonotonic64(struct timespec64 *ts); extern void getrawmonotonic64(struct timespec64 *ts);
extern void ktime_get_ts64(struct timespec64 *ts); extern void ktime_get_ts64(struct timespec64 *ts);
extern time64_t ktime_get_seconds(void);
extern time64_t ktime_get_real_seconds(void);
extern int __getnstimeofday64(struct timespec64 *tv); extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv); extern void getnstimeofday64(struct timespec64 *tv);
......
...@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); ...@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
*/ */
static inline void tk_update_ktime_data(struct timekeeper *tk) static inline void tk_update_ktime_data(struct timekeeper *tk)
{ {
s64 nsec; u64 seconds;
u32 nsec;
/* /*
* The xtime based monotonic readout is: * The xtime based monotonic readout is:
...@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk) ...@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
* nsec = base_mono + now(); * nsec = base_mono + now();
* ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
*/ */
nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
nsec *= NSEC_PER_SEC; nsec = (u32) tk->wall_to_monotonic.tv_nsec;
nsec += tk->wall_to_monotonic.tv_nsec; tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
tk->tkr.base_mono = ns_to_ktime(nsec);
/* Update the monotonic raw base */ /* Update the monotonic raw base */
tk->base_raw = timespec64_to_ktime(tk->raw_time); tk->base_raw = timespec64_to_ktime(tk->raw_time);
/*
* The sum of the nanoseconds portions of xtime and
* wall_to_monotonic can be greater/equal one second. Take
* this into account before updating tk->ktime_sec.
*/
nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
if (nsec >= NSEC_PER_SEC)
seconds++;
tk->ktime_sec = seconds;
} }
/* must hold timekeeper_lock */ /* must hold timekeeper_lock */
...@@ -648,6 +658,54 @@ void ktime_get_ts64(struct timespec64 *ts) ...@@ -648,6 +658,54 @@ void ktime_get_ts64(struct timespec64 *ts)
} }
EXPORT_SYMBOL_GPL(ktime_get_ts64); EXPORT_SYMBOL_GPL(ktime_get_ts64);
/**
* ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
*
* Returns the seconds portion of CLOCK_MONOTONIC with a single non
* serialized read. tk->ktime_sec is of type 'unsigned long' so this
* works on both 32 and 64 bit systems. On 32 bit systems the readout
* covers ~136 years of uptime which should be enough to prevent
* premature wrap arounds.
*/
time64_t ktime_get_seconds(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
WARN_ON(timekeeping_suspended);
return tk->ktime_sec;
}
EXPORT_SYMBOL_GPL(ktime_get_seconds);
/**
* ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME
*
* Returns the wall clock seconds since 1970. This replaces the
* get_seconds() interface which is not y2038 safe on 32bit systems.
*
* For 64bit systems the fast access to tk->xtime_sec is preserved. On
* 32bit systems the access must be protected with the sequence
* counter to provide "atomic" access to the 64bit tk->xtime_sec
* value.
*/
time64_t ktime_get_real_seconds(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
time64_t seconds;
unsigned int seq;
if (IS_ENABLED(CONFIG_64BIT))
return tk->xtime_sec;
do {
seq = read_seqcount_begin(&tk_core.seq);
seconds = tk->xtime_sec;
} while (read_seqcount_retry(&tk_core.seq, seq));
return seconds;
}
EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
#ifdef CONFIG_NTP_PPS #ifdef CONFIG_NTP_PPS
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册