| From 069ac84a2cbedbf1fa4fe1089db928e538779762 Mon Sep 17 00:00:00 2001 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 17 Jul 2012 17:49:29 -0400 |
| Subject: [PATCH] timekeeping: Provide hrtimer update function |
| |
| This is a backport of f6c06abfb3972ad4914cef57d8348fcb2932bc3b |
| |
| To finally fix the infamous leap second issue and other race windows |
| caused by functions which change the offsets between the various time |
| bases (CLOCK_MONOTONIC, CLOCK_REALTIME and CLOCK_BOOTTIME) we need a |
| function which atomically gets the current monotonic time and updates |
| the offsets of CLOCK_REALTIME and CLOCK_BOOTTIME with minimalistic |
| overhead. The previous patch which provides ktime_t offsets allows us |
| to make this function almost as cheap as ktime_get() which is going to |
| be replaced in hrtimer_interrupt(). |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Reviewed-by: Ingo Molnar <mingo@kernel.org> |
| Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Acked-by: Prarit Bhargava <prarit@redhat.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: John Stultz <johnstul@us.ibm.com> |
| Link: http://lkml.kernel.org/r/1341960205-56738-7-git-send-email-johnstul@us.ibm.com |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Prarit Bhargava <prarit@redhat.com> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Linux Kernel <linux-kernel@vger.kernel.org> |
| Signed-off-by: John Stultz <johnstul@us.ibm.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| include/linux/hrtimer.h | 2 +- |
| kernel/time/timekeeping.c | 32 ++++++++++++++++++++++++++++++++ |
| 2 files changed, 33 insertions(+), 1 deletion(-) |
| |
| diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h |
| index 0325598..887d1e7 100644 |
| --- a/include/linux/hrtimer.h |
| +++ b/include/linux/hrtimer.h |
| @@ -319,7 +319,7 @@ static inline void clock_was_set_delayed(void) { } |
| |
| extern ktime_t ktime_get(void); |
| extern ktime_t ktime_get_real(void); |
| - |
| +extern ktime_t ktime_get_update_offsets(ktime_t *offs_real); |
| |
| DECLARE_PER_CPU(struct tick_device, tick_cpu_device); |
| |
| diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c |
| index 3d443b4..0b4f6d1 100644 |
| --- a/kernel/time/timekeeping.c |
| +++ b/kernel/time/timekeeping.c |
| @@ -969,3 +969,35 @@ struct timespec get_monotonic_coarse(void) |
| now.tv_nsec + mono.tv_nsec); |
| return now; |
| } |
| + |
| +#ifdef CONFIG_HIGH_RES_TIMERS |
| +/** |
| + * ktime_get_update_offsets - hrtimer helper |
| + * @real: pointer to storage for monotonic -> realtime offset |
| + * |
| + * Returns current monotonic time and updates the offsets |
| + * Called from hrtimer_interupt() or retrigger_next_event() |
| + */ |
| +ktime_t ktime_get_update_offsets(ktime_t *real) |
| +{ |
| + ktime_t now; |
| + unsigned int seq; |
| + u64 secs, nsecs; |
| + |
| + do { |
| + seq = read_seqbegin(&xtime_lock); |
| + |
| + secs = xtime.tv_sec; |
| + nsecs = xtime.tv_nsec; |
| + nsecs += timekeeping_get_ns(); |
| + /* If arch requires, add in gettimeoffset() */ |
| + nsecs += arch_gettimeoffset(); |
| + |
| + *real = offs_real; |
| + } while (read_seqretry(&xtime_lock, seq)); |
| + |
| + now = ktime_add_ns(ktime_set(secs, 0), nsecs); |
| + now = ktime_sub(now, *real); |
| + return now; |
| +} |
| +#endif |
| -- |
| 1.7.12.rc1.1.gbce1580 |
| |