Skip to content

Commit 9e3680b

Browse files
darbyShawKAGA-KOKO
authored andcommitted
timekeeping: Provide fast accessor to the seconds part of CLOCK_MONOTONIC
This is the counterpart to get_seconds() based on CLOCK_MONOTONIC. The use case for this interface are kernel internal coarse grained timestamps which do neither require the nanoseconds fraction of current time nor the CLOCK_REALTIME properties. Such timestamps can currently only retrieved by calling ktime_get_ts64() and using the tv_sec field of the returned timespec64. That's inefficient as it involves the read of the clocksource, math operations and must be protected by the timekeeper sequence counter. To avoid the sequence counter protection we restrict the return value to unsigned 32bit on 32bit machines. This covers ~136 years of uptime and therefor an overflow is not expected to hit anytime soon. To avoid math in the function we calculate the current seconds portion of CLOCK_MONOTONIC when the timekeeper gets updated in tk_update_ktime_data() similar to the CLOCK_REALTIME counterpart xtime_sec. [ tglx: Massaged changelog, simplified and commented the update function, added docbook comment ] Signed-off-by: Heena Sirwani <heenasirwani@gmail.com> Reviewed-by: Arnd Bergman <arnd@arndb.de> Cc: John Stultz <john.stultz@linaro.org> Cc: opw-kernel@googlegroups.com Link: http://lkml.kernel.org/r/da0b63f4bdf3478909f92becb35861197da3a905.1414578445.git.heenasirwani@gmail.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent cac7f24 commit 9e3680b

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct timespec __current_kernel_time(void);
2828
struct timespec get_monotonic_coarse(void);
2929
extern void getrawmonotonic(struct timespec *ts);
3030
extern void ktime_get_ts64(struct timespec64 *ts);
31+
extern time64_t ktime_get_seconds(void);
3132

3233
extern int __getnstimeofday64(struct timespec64 *tv);
3334
extern void getnstimeofday64(struct timespec64 *tv);

kernel/time/timekeeping.c

Lines changed: 33 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,24 @@ 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+
651679
#ifdef CONFIG_NTP_PPS
652680

653681
/**

0 commit comments

Comments
 (0)