diff options
author | Paul Gortmaker <paul.gortmaker@windriver.com> | 2012-08-05 12:11:20 -0400 |
---|---|---|
committer | Paul Gortmaker <paul.gortmaker@windriver.com> | 2012-08-05 12:11:20 -0400 |
commit | 132c9fd4eaa9400dc0d5f1f26a6016c275a2235c (patch) | |
tree | 0ee05bd19cd6ff3e22bfbbf40b39137658a503d3 | |
parent | a6adb4ffe71d6a4a3d809d767f5ffe764cf2a9c6 (diff) | |
download | longterm-queue-2.6.34-132c9fd4eaa9400dc0d5f1f26a6016c275a2235c.tar.gz |
add leapsecond fix series from JS
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
12 files changed, 1129 insertions, 0 deletions
diff --git a/queue/hrtimer-Provide-clock_was_set_delayed.patch b/queue/hrtimer-Provide-clock_was_set_delayed.patch new file mode 100644 index 0000000..5c87b2c --- /dev/null +++ b/queue/hrtimer-Provide-clock_was_set_delayed.patch @@ -0,0 +1,121 @@ +From 7c59877ab14cc5a182ca9d289c33f1aac2977e02 Mon Sep 17 00:00:00 2001 +From: John Stultz <johnstul@us.ibm.com> +Date: Tue, 17 Jul 2012 17:49:25 -0400 +Subject: [PATCH] hrtimer: Provide clock_was_set_delayed() + +This is a backport of f55a6faa384304c89cfef162768e88374d3312cb + +clock_was_set() cannot be called from hard interrupt context because +it calls on_each_cpu(). + +For fixing the widely reported leap seconds issue it is necessary to +call it from hard interrupt context, i.e. the timer tick code, which +does the timekeeping updates. + +Provide a new function which denotes it in the hrtimer cpu base +structure of the cpu on which it is called and raise the hrtimer +softirq. We then execute the clock_was_set() notificiation from +softirq context in run_hrtimer_softirq(). The hrtimer softirq is +rarely used, so polling the flag there is not a performance issue. + +[ tglx: Made it depend on CONFIG_HIGH_RES_TIMERS. We really should get + rid of all this ifdeffery ASAP ] + +Signed-off-by: John Stultz <johnstul@us.ibm.com> +Reported-by: Jan Engelhardt <jengelh@inai.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 +Link: http://lkml.kernel.org/r/1341960205-56738-2-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 | 7 +++++++ + kernel/hrtimer.c | 20 ++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h +index 5d86fb2..0325598 100644 +--- a/include/linux/hrtimer.h ++++ b/include/linux/hrtimer.h +@@ -159,6 +159,7 @@ struct hrtimer_clock_base { + * and timers + * @clock_base: array of clock bases for this cpu + * @curr_timer: the timer which is executing a callback right now ++ * @clock_was_set: Indicates that clock was set from irq context. + * @expires_next: absolute time of the next event which was scheduled + * via clock_set_next_event() + * @hres_active: State of high resolution mode +@@ -171,6 +172,7 @@ struct hrtimer_clock_base { + struct hrtimer_cpu_base { + raw_spinlock_t lock; + struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; ++ unsigned int clock_was_set; + #ifdef CONFIG_HIGH_RES_TIMERS + ktime_t expires_next; + int hres_active; +@@ -280,6 +282,8 @@ extern void hrtimer_peek_ahead_timers(void); + # define MONOTONIC_RES_NSEC HIGH_RES_NSEC + # define KTIME_MONOTONIC_RES KTIME_HIGH_RES + ++extern void clock_was_set_delayed(void); ++ + #else + + # define MONOTONIC_RES_NSEC LOW_RES_NSEC +@@ -308,6 +312,9 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) + { + return 0; + } ++ ++static inline void clock_was_set_delayed(void) { } ++ + #endif + + extern ktime_t ktime_get(void); +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index 3c727aa..dc41268 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -738,6 +738,19 @@ static int hrtimer_switch_to_hres(void) + return 1; + } + ++/* ++ * Called from timekeeping code to reprogramm the hrtimer interrupt ++ * device. If called from the timer interrupt context we defer it to ++ * softirq context. ++ */ ++void clock_was_set_delayed(void) ++{ ++ struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); ++ ++ cpu_base->clock_was_set = 1; ++ __raise_softirq_irqoff(HRTIMER_SOFTIRQ); ++} ++ + #else + + static inline int hrtimer_hres_active(void) { return 0; } +@@ -1409,6 +1422,13 @@ void hrtimer_peek_ahead_timers(void) + + static void run_hrtimer_softirq(struct softirq_action *h) + { ++ struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); ++ ++ if (cpu_base->clock_was_set) { ++ cpu_base->clock_was_set = 0; ++ clock_was_set(); ++ } ++ + hrtimer_peek_ahead_timers(); + } + +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/hrtimer-Update-hrtimer-base-offsets-each-hrtimer_int.patch b/queue/hrtimer-Update-hrtimer-base-offsets-each-hrtimer_int.patch new file mode 100644 index 0000000..3e72976 --- /dev/null +++ b/queue/hrtimer-Update-hrtimer-base-offsets-each-hrtimer_int.patch @@ -0,0 +1,131 @@ +From 642d7a2c17a856e2baab2034efd72fc5e7c506fc Mon Sep 17 00:00:00 2001 +From: John Stultz <johnstul@us.ibm.com> +Date: Tue, 17 Jul 2012 17:49:30 -0400 +Subject: [PATCH] hrtimer: Update hrtimer base offsets each hrtimer_interrupt + +This is a backport of 5baefd6d84163443215f4a99f6a20f054ef11236 + +The update of the hrtimer base offsets on all cpus cannot be made +atomically from the timekeeper.lock held and interrupt disabled region +as smp function calls are not allowed there. + +clock_was_set(), which enforces the update on all cpus, is called +either from preemptible process context in case of do_settimeofday() +or from the softirq context when the offset modification happened in +the timer interrupt itself due to a leap second. + +In both cases there is a race window for an hrtimer interrupt between +dropping timekeeper lock, enabling interrupts and clock_was_set() +issuing the updates. Any interrupt which arrives in that window will +see the new time but operate on stale offsets. + +So we need to make sure that an hrtimer interrupt always sees a +consistent state of time and offsets. + +ktime_get_update_offsets() allows us to get the current monotonic time +and update the per cpu hrtimer base offsets from hrtimer_interrupt() +to capture a consistent state of monotonic time and the offsets. The +function replaces the existing ktime_get() calls in hrtimer_interrupt(). + +The overhead of the new function vs. ktime_get() is minimal as it just +adds two store operations. + +This ensures that any changes to realtime or boottime offsets are +noticed and stored into the per-cpu hrtimer base structures, prior to +any hrtimer expiration and guarantees that timers are not expired early. + +Signed-off-by: John Stultz <johnstul@us.ibm.com> +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 +Link: http://lkml.kernel.org/r/1341960205-56738-8-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> +--- + kernel/hrtimer.c | 27 ++++++++++++--------------- + 1 file changed, 12 insertions(+), 15 deletions(-) + +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index 039db35..6b6835f 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -603,6 +603,12 @@ static int hrtimer_reprogram(struct hrtimer *timer, + return res; + } + ++static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) ++{ ++ ktime_t *offs_real = &base->clock_base[CLOCK_REALTIME].offset; ++ ++ return ktime_get_update_offsets(offs_real); ++} + + /* + * Retrigger next event is called after clock was set +@@ -612,26 +618,15 @@ static int hrtimer_reprogram(struct hrtimer *timer, + static void retrigger_next_event(void *arg) + { + struct hrtimer_cpu_base *base; +- struct timespec realtime_offset; +- unsigned long seq; + + if (!hrtimer_hres_active()) + return; + +- do { +- seq = read_seqbegin(&xtime_lock); +- set_normalized_timespec(&realtime_offset, +- -wall_to_monotonic.tv_sec, +- -wall_to_monotonic.tv_nsec); +- } while (read_seqretry(&xtime_lock, seq)); +- + base = &__get_cpu_var(hrtimer_bases); + + /* Adjust CLOCK_REALTIME offset */ + raw_spin_lock(&base->lock); +- base->clock_base[CLOCK_REALTIME].offset = +- timespec_to_ktime(realtime_offset); +- ++ hrtimer_update_base(base); + hrtimer_force_reprogram(base, 0); + raw_spin_unlock(&base->lock); + } +@@ -731,7 +726,6 @@ static int hrtimer_switch_to_hres(void) + base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES; + + tick_setup_sched_timer(); +- + /* "Retrigger" the interrupt to get things going */ + retrigger_next_event(NULL); + local_irq_restore(flags); +@@ -1280,7 +1274,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) + dev->next_event.tv64 = KTIME_MAX; + + raw_spin_lock(&cpu_base->lock); +- entry_time = now = ktime_get(); ++ entry_time = now = hrtimer_update_base(cpu_base); + retry: + expires_next.tv64 = KTIME_MAX; + /* +@@ -1356,9 +1350,12 @@ retry: + * We need to prevent that we loop forever in the hrtimer + * interrupt routine. We give it 3 attempts to avoid + * overreacting on some spurious event. ++ * ++ * Acquire base lock for updating the offsets and retrieving ++ * the current time. + */ + raw_spin_lock(&cpu_base->lock); +- now = ktime_get(); ++ now = hrtimer_update_base(cpu_base); + cpu_base->nr_retries++; + if (++retries < 3) + goto retry; +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/hrtimers-Move-lock-held-region-in-hrtimer_interrupt.patch b/queue/hrtimers-Move-lock-held-region-in-hrtimer_interrupt.patch new file mode 100644 index 0000000..7c4f16c --- /dev/null +++ b/queue/hrtimers-Move-lock-held-region-in-hrtimer_interrupt.patch @@ -0,0 +1,65 @@ +From 1b95391ad67b68c0f3fad6642e7f343d2f6f2050 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Tue, 17 Jul 2012 17:49:28 -0400 +Subject: [PATCH] hrtimers: Move lock held region in hrtimer_interrupt() + +This is a backport of 196951e91262fccda81147d2bcf7fdab08668b40 + +We need to update the base offsets from this code and we need to do +that under base->lock. Move the lock held region around the +ktime_get() calls. The ktime_get() calls are going to be replaced with +a function which gets the time and the offsets atomically. + +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-6-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> +--- + kernel/hrtimer.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index dc41268..039db35 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -1279,11 +1279,10 @@ void hrtimer_interrupt(struct clock_event_device *dev) + cpu_base->nr_events++; + dev->next_event.tv64 = KTIME_MAX; + ++ raw_spin_lock(&cpu_base->lock); + entry_time = now = ktime_get(); + retry: + expires_next.tv64 = KTIME_MAX; +- +- raw_spin_lock(&cpu_base->lock); + /* + * We set expires_next to KTIME_MAX here with cpu_base->lock + * held to prevent that a timer is enqueued in our queue via +@@ -1358,6 +1357,7 @@ retry: + * interrupt routine. We give it 3 attempts to avoid + * overreacting on some spurious event. + */ ++ raw_spin_lock(&cpu_base->lock); + now = ktime_get(); + cpu_base->nr_retries++; + if (++retries < 3) +@@ -1370,6 +1370,7 @@ retry: + */ + cpu_base->nr_hangs++; + cpu_base->hang_detected = 1; ++ raw_spin_unlock(&cpu_base->lock); + delta = ktime_sub(now, entry_time); + if (delta.tv64 > cpu_base->max_hang_time.tv64) + cpu_base->max_hang_time = delta; +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/ntp-Correct-TAI-offset-during-leap-second.patch b/queue/ntp-Correct-TAI-offset-during-leap-second.patch new file mode 100644 index 0000000..421ef90 --- /dev/null +++ b/queue/ntp-Correct-TAI-offset-during-leap-second.patch @@ -0,0 +1,45 @@ +From dc39117bc65c77f555116fd314719d0a5e2fd61f Mon Sep 17 00:00:00 2001 +From: Richard Cochran <richardcochran@gmail.com> +Date: Tue, 17 Jul 2012 17:49:22 -0400 +Subject: [PATCH] ntp: Correct TAI offset during leap second + +This is a backport of dd48d708ff3e917f6d6b6c2b696c3f18c019feed + +When repeating a UTC time value during a leap second (when the UTC +time should be 23:59:60), the TAI timescale should not stop. The kernel +NTP code increments the TAI offset one second too late. This patch fixes +the issue by incrementing the offset during the leap second itself. + +Signed-off-by: Richard Cochran <richardcochran@gmail.com> +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 <john.stultz@linaro.org> +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +--- + kernel/time/ntp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 2522ab8..ec08c06 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -208,6 +208,7 @@ int second_overflow(unsigned long secs) + if (secs % 86400 == 0) { + leap = -1; + time_state = TIME_OOP; ++ time_tai++; + printk(KERN_NOTICE + "Clock: inserting leap second 23:59:60 UTC\n"); + } +@@ -222,7 +223,6 @@ int second_overflow(unsigned long secs) + } + break; + case TIME_OOP: +- time_tai++; + time_state = TIME_WAIT; + break; + +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/ntp-Fix-leap-second-hrtimer-livelock.patch b/queue/ntp-Fix-leap-second-hrtimer-livelock.patch new file mode 100644 index 0000000..c5cad66 --- /dev/null +++ b/queue/ntp-Fix-leap-second-hrtimer-livelock.patch @@ -0,0 +1,334 @@ +From a22e14f51c1d8a6982931aef97d08c0dc4d9e91c Mon Sep 17 00:00:00 2001 +From: John Stultz <john.stultz@linaro.org> +Date: Tue, 17 Jul 2012 17:49:21 -0400 +Subject: [PATCH] ntp: Fix leap-second hrtimer livelock + +This is a backport of 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d + +This should have been backported when it was commited, but I +mistook the problem as requiring the ntp_lock changes +that landed in 3.4 in order for it to occur. + +Unfortunately the same issue can happen (with only one cpu) +as follows: +do_adjtimex() + write_seqlock_irq(&xtime_lock); + process_adjtimex_modes() + process_adj_status() + ntp_start_leap_timer() + hrtimer_start() + hrtimer_reprogram() + tick_program_event() + clockevents_program_event() + ktime_get() + seq = req_seqbegin(xtime_lock); [DEADLOCK] + +This deadlock will no always occur, as it requires the +leap_timer to force a hrtimer_reprogram which only happens +if its set and there's no sooner timer to expire. + +NOTE: This patch, being faithful to the original commit, +introduces a bug (we don't update wall_to_monotonic), +which will be resovled by backporting a following fix. + +Original commit message below: + +Since commit 7dffa3c673fbcf835cd7be80bb4aec8ad3f51168 the ntp +subsystem has used an hrtimer for triggering the leapsecond +adjustment. However, this can cause a potential livelock. + +Thomas diagnosed this as the following pattern: +CPU 0 CPU 1 +do_adjtimex() + spin_lock_irq(&ntp_lock); + process_adjtimex_modes(); timer_interrupt() + process_adj_status(); do_timer() + ntp_start_leap_timer(); write_lock(&xtime_lock); + hrtimer_start(); update_wall_time(); + hrtimer_reprogram(); ntp_tick_length() + tick_program_event() spin_lock(&ntp_lock); + clockevents_program_event() + ktime_get() + seq = req_seqbegin(xtime_lock); + +This patch tries to avoid the problem by reverting back to not using +an hrtimer to inject leapseconds, and instead we handle the leapsecond +processing in the second_overflow() function. + +The downside to this change is that on systems that support highres +timers, the leap second processing will occur on a HZ tick boundary, +(ie: ~1-10ms, depending on HZ) after the leap second instead of +possibly sooner (~34us in my tests w/ x86_64 lapic). + +This patch applies on top of tip/timers/core. + +CC: Sasha Levin <levinsasha928@gmail.com> +CC: Thomas Gleixner <tglx@linutronix.de> +Reported-by: Sasha Levin <levinsasha928@gmail.com> +Diagnoised-by: Thomas Gleixner <tglx@linutronix.de> +Tested-by: Sasha Levin <levinsasha928@gmail.com> +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 <john.stultz@linaro.org> +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +--- + include/linux/timex.h | 2 +- + kernel/time/ntp.c | 122 +++++++++++++++------------------------------- + kernel/time/timekeeping.c | 12 ++--- + 3 files changed, 44 insertions(+), 92 deletions(-) + +diff --git a/include/linux/timex.h b/include/linux/timex.h +index 7a082b3..5674a08 100644 +--- a/include/linux/timex.h ++++ b/include/linux/timex.h +@@ -267,7 +267,7 @@ static inline int ntp_synced(void) + /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ + extern u64 tick_length; + +-extern void second_overflow(void); ++extern int second_overflow(unsigned long secs); + extern void update_ntp_one_tick(void); + extern int do_adjtimex(struct timex *); + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 7c0f180..2522ab8 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -28,8 +28,6 @@ unsigned long tick_nsec; + u64 tick_length; + static u64 tick_length_base; + +-static struct hrtimer leap_timer; +- + #define MAX_TICKADJ 500LL /* usecs */ + #define MAX_TICKADJ_SCALED \ + (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) +@@ -180,60 +178,60 @@ void ntp_clear(void) + } + + /* +- * Leap second processing. If in leap-insert state at the end of the +- * day, the system clock is set back one second; if in leap-delete +- * state, the system clock is set ahead one second. ++ * this routine handles the overflow of the microsecond field ++ * ++ * The tricky bits of code to handle the accurate clock support ++ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. ++ * They were originally developed for SUN and DEC kernels. ++ * All the kudos should go to Dave for this stuff. ++ * ++ * Also handles leap second processing, and returns leap offset + */ +-static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer) ++int second_overflow(unsigned long secs) + { +- enum hrtimer_restart res = HRTIMER_NORESTART; +- +- write_seqlock(&xtime_lock); ++ int leap = 0; ++ s64 delta; + ++ /* ++ * Leap second processing. If in leap-insert state at the end of the ++ * day, the system clock is set back one second; if in leap-delete ++ * state, the system clock is set ahead one second. ++ */ + switch (time_state) { + case TIME_OK: ++ if (time_status & STA_INS) ++ time_state = TIME_INS; ++ else if (time_status & STA_DEL) ++ time_state = TIME_DEL; + break; + case TIME_INS: +- timekeeping_leap_insert(-1); +- time_state = TIME_OOP; +- printk(KERN_NOTICE +- "Clock: inserting leap second 23:59:60 UTC\n"); +- hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC); +- res = HRTIMER_RESTART; ++ if (secs % 86400 == 0) { ++ leap = -1; ++ time_state = TIME_OOP; ++ printk(KERN_NOTICE ++ "Clock: inserting leap second 23:59:60 UTC\n"); ++ } + break; + case TIME_DEL: +- timekeeping_leap_insert(1); +- time_tai--; +- time_state = TIME_WAIT; +- printk(KERN_NOTICE +- "Clock: deleting leap second 23:59:59 UTC\n"); ++ if ((secs + 1) % 86400 == 0) { ++ leap = 1; ++ time_tai--; ++ time_state = TIME_WAIT; ++ printk(KERN_NOTICE ++ "Clock: deleting leap second 23:59:59 UTC\n"); ++ } + break; + case TIME_OOP: + time_tai++; + time_state = TIME_WAIT; +- /* fall through */ ++ break; ++ + case TIME_WAIT: + if (!(time_status & (STA_INS | STA_DEL))) + time_state = TIME_OK; + break; + } + +- write_sequnlock(&xtime_lock); +- +- return res; +-} +- +-/* +- * this routine handles the overflow of the microsecond field +- * +- * The tricky bits of code to handle the accurate clock support +- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. +- * They were originally developed for SUN and DEC kernels. +- * All the kudos should go to Dave for this stuff. +- */ +-void second_overflow(void) +-{ +- s64 delta; + + /* Bump the maxerror field */ + time_maxerror += MAXFREQ / NSEC_PER_USEC; +@@ -253,23 +251,25 @@ void second_overflow(void) + tick_length += delta; + + if (!time_adjust) +- return; ++ goto out; + + if (time_adjust > MAX_TICKADJ) { + time_adjust -= MAX_TICKADJ; + tick_length += MAX_TICKADJ_SCALED; +- return; ++ goto out; + } + + if (time_adjust < -MAX_TICKADJ) { + time_adjust += MAX_TICKADJ; + tick_length -= MAX_TICKADJ_SCALED; +- return; ++ goto out; + } + + tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) + << NTP_SCALE_SHIFT; + time_adjust = 0; ++out: ++ return leap; + } + + #ifdef CONFIG_GENERIC_CMOS_UPDATE +@@ -331,27 +331,6 @@ static void notify_cmos_timer(void) + static inline void notify_cmos_timer(void) { } + #endif + +-/* +- * Start the leap seconds timer: +- */ +-static inline void ntp_start_leap_timer(struct timespec *ts) +-{ +- long now = ts->tv_sec; +- +- if (time_status & STA_INS) { +- time_state = TIME_INS; +- now += 86400 - now % 86400; +- hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); +- +- return; +- } +- +- if (time_status & STA_DEL) { +- time_state = TIME_DEL; +- now += 86400 - (now + 1) % 86400; +- hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); +- } +-} + + /* + * Propagate a new txc->status value into the NTP state: +@@ -374,22 +353,6 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) + time_status &= STA_RONLY; + time_status |= txc->status & ~STA_RONLY; + +- switch (time_state) { +- case TIME_OK: +- ntp_start_leap_timer(ts); +- break; +- case TIME_INS: +- case TIME_DEL: +- time_state = TIME_OK; +- ntp_start_leap_timer(ts); +- case TIME_WAIT: +- if (!(time_status & (STA_INS | STA_DEL))) +- time_state = TIME_OK; +- break; +- case TIME_OOP: +- hrtimer_restart(&leap_timer); +- break; +- } + } + /* + * Called with the xtime lock held, so we can access and modify +@@ -469,9 +432,6 @@ int do_adjtimex(struct timex *txc) + (txc->tick < 900000/USER_HZ || + txc->tick > 1100000/USER_HZ)) + return -EINVAL; +- +- if (txc->modes & ADJ_STATUS && time_state != TIME_OK) +- hrtimer_cancel(&leap_timer); + } + + getnstimeofday(&ts); +@@ -549,6 +509,4 @@ __setup("ntp_tick_adj=", ntp_tick_adj_setup); + void __init ntp_init(void) + { + ntp_clear(); +- hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); +- leap_timer.function = ntp_leap_second; + } +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index 268020d..df1e939 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -176,14 +176,6 @@ void update_xtime_cache(u64 nsec) + timespec_add_ns(&xtime_cache, nsec); + } + +-/* must hold xtime_lock */ +-void timekeeping_leap_insert(int leapsecond) +-{ +- xtime.tv_sec += leapsecond; +- wall_to_monotonic.tv_sec -= leapsecond; +- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult); +-} +- + #ifdef CONFIG_GENERIC_TIME + + /** +@@ -762,9 +754,11 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) + + timekeeper.xtime_nsec += timekeeper.xtime_interval << shift; + while (timekeeper.xtime_nsec >= nsecps) { ++ int leap; + timekeeper.xtime_nsec -= nsecps; + xtime.tv_sec++; +- second_overflow(); ++ leap = second_overflow(xtime.tv_sec); ++ xtime.tv_sec += leap; + } + + /* Accumulate into raw time */ +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/series b/queue/series index 252930e..ba04bd3 100644 --- a/queue/series +++ b/queue/series @@ -111,3 +111,14 @@ ACPI-AC-prevent-OOPS-on-some-boxes-due-to-missing-ch.patch ecryptfs-use-lower-filesystem-stat-if-it-exists.patch eCryptfs-Improve-statfs-reporting.patch +ntp-Fix-leap-second-hrtimer-livelock.patch +ntp-Correct-TAI-offset-during-leap-second.patch +timekeeping-Fix-CLOCK_MONOTONIC-inconsistency-during.patch +time-Move-common-updates-to-a-function.patch +hrtimer-Provide-clock_was_set_delayed.patch +timekeeping-Fix-leapsecond-triggered-load-spike-issu.patch +timekeeping-Maintain-ktime_t-based-offsets-for-hrtim.patch +hrtimers-Move-lock-held-region-in-hrtimer_interrupt.patch +timekeeping-Provide-hrtimer-update-function.patch +hrtimer-Update-hrtimer-base-offsets-each-hrtimer_int.patch +timekeeping-Add-missing-update-call-in-timekeeping_r.patch diff --git a/queue/time-Move-common-updates-to-a-function.patch b/queue/time-Move-common-updates-to-a-function.patch new file mode 100644 index 0000000..318cf1d --- /dev/null +++ b/queue/time-Move-common-updates-to-a-function.patch @@ -0,0 +1,71 @@ +From 8abe8c8722da62b74805dd8b208b7697d0a5bcaa Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Tue, 17 Jul 2012 17:49:24 -0400 +Subject: [PATCH] time: Move common updates to a function + +This is a backport of cc06268c6a87db156af2daed6e96a936b955cc82 + +While not a bugfix itself, it allows following fixes to backport +in a more straightforward manner. + +CC: Thomas Gleixner <tglx@linutronix.de> +CC: Eric Dumazet <eric.dumazet@gmail.com> +CC: Richard Cochran <richardcochran@gmail.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 <john.stultz@linaro.org> +Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> +--- + kernel/time/timekeeping.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index f8d4877..adfa89d 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -166,6 +166,18 @@ static struct timespec total_sleep_time; + */ + struct timespec raw_time; + ++/* must hold write on xtime_lock */ ++static void timekeeping_update(bool clearntp) ++{ ++ if (clearntp) { ++ timekeeper.ntp_error = 0; ++ ntp_clear(); ++ } ++ update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult); ++} ++ ++ ++ + /* flag for if timekeeping is suspended */ + int __read_mostly timekeeping_suspended; + +@@ -330,10 +342,7 @@ int do_settimeofday(struct timespec *tv) + + update_xtime_cache(0); + +- timekeeper.ntp_error = 0; +- ntp_clear(); +- +- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult); ++ timekeeping_update(true); + + write_sequnlock_irqrestore(&xtime_lock, flags); + +@@ -858,8 +867,7 @@ void update_wall_time(void) + nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift); + update_xtime_cache(nsecs); + +- /* check to see if there is a new clocksource to use */ +- update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult); ++ timekeeping_update(false); + } + + /** +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/timekeeping-Add-missing-update-call-in-timekeeping_r.patch b/queue/timekeeping-Add-missing-update-call-in-timekeeping_r.patch new file mode 100644 index 0000000..b638e49 --- /dev/null +++ b/queue/timekeeping-Add-missing-update-call-in-timekeeping_r.patch @@ -0,0 +1,56 @@ +From b3cbfe4eebf5a64dc3a75c12abdcdc734af6e79e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Tue, 17 Jul 2012 17:49:31 -0400 +Subject: [PATCH] timekeeping: Add missing update call in timekeeping_resume() + +This is a backport of 3e997130bd2e8c6f5aaa49d6e3161d4d29b43ab0 + +The leap second rework unearthed another issue of inconsistent data. + +On timekeeping_resume() the timekeeper data is updated, but nothing +calls timekeeping_update(), so now the update code in the timer +interrupt sees stale values. + +This has been the case before those changes, but then the timer +interrupt was using stale data as well so this went unnoticed for quite +some time. + +Add the missing update call, so all the data is consistent everywhere. + +Reported-by: Andreas Schwab <schwab@linux-m68k.org> +Reported-and-tested-by: "Rafael J. Wysocki" <rjw@sisk.pl> +Reported-and-tested-by: Martin Steigerwald <Martin@lichtvoll.de> +Cc: LKML <linux-kernel@vger.kernel.org> +Cc: Linux PM list <linux-pm@vger.kernel.org> +Cc: John Stultz <johnstul@us.ibm.com> +Cc: Ingo Molnar <mingo@kernel.org> +Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>, +Cc: Prarit Bhargava <prarit@redhat.com> +Cc: stable@vger.kernel.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: John Stultz <johnstul@us.ibm.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +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> +--- + kernel/time/timekeeping.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index 0b4f6d1..156fd67 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -626,6 +626,7 @@ static int timekeeping_resume(struct sys_device *dev) + timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); + timekeeper.ntp_error = 0; + timekeeping_suspended = 0; ++ timekeeping_update(false); + write_sequnlock_irqrestore(&xtime_lock, flags); + + touch_softlockup_watchdog(); +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/timekeeping-Fix-CLOCK_MONOTONIC-inconsistency-during.patch b/queue/timekeeping-Fix-CLOCK_MONOTONIC-inconsistency-during.patch new file mode 100644 index 0000000..d636b0d --- /dev/null +++ b/queue/timekeeping-Fix-CLOCK_MONOTONIC-inconsistency-during.patch @@ -0,0 +1,45 @@ +From 67f28bed3781c06940816c35506c6cbca2026d04 Mon Sep 17 00:00:00 2001 +From: John Stultz <john.stultz@linaro.org> +Date: Tue, 17 Jul 2012 17:49:23 -0400 +Subject: [PATCH] timekeeping: Fix CLOCK_MONOTONIC inconsistency during + leapsecond + +This is a backport of fad0c66c4bb836d57a5f125ecd38bed653ca863a +which resolves a bug the previous commit. + +Commit 6b43ae8a61 (ntp: Fix leap-second hrtimer livelock) broke the +leapsecond update of CLOCK_MONOTONIC. The missing leapsecond update to +wall_to_monotonic causes discontinuities in CLOCK_MONOTONIC. + +Adjust wall_to_monotonic when NTP inserted a leapsecond. + +Reported-by: Richard Cochran <richardcochran@gmail.com> +Signed-off-by: John Stultz <john.stultz@linaro.org> +Tested-by: Richard Cochran <richardcochran@gmail.com> +Cc: stable@kernel.org +Link: http://lkml.kernel.org/r/1338400497-12420-1-git-send-email-john.stultz@linaro.org +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> +--- + kernel/time/timekeeping.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index df1e939..f8d4877 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -759,6 +759,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) + xtime.tv_sec++; + leap = second_overflow(xtime.tv_sec); + xtime.tv_sec += leap; ++ wall_to_monotonic.tv_sec -= leap; + } + + /* Accumulate into raw time */ +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/timekeeping-Fix-leapsecond-triggered-load-spike-issu.patch b/queue/timekeeping-Fix-leapsecond-triggered-load-spike-issu.patch new file mode 100644 index 0000000..bb13b53 --- /dev/null +++ b/queue/timekeeping-Fix-leapsecond-triggered-load-spike-issu.patch @@ -0,0 +1,57 @@ +From 796b28aa62cf1656da5cb984d8d483761d9bf7fc Mon Sep 17 00:00:00 2001 +From: John Stultz <johnstul@us.ibm.com> +Date: Tue, 17 Jul 2012 17:49:26 -0400 +Subject: [PATCH] timekeeping: Fix leapsecond triggered load spike issue + +This is a backport of 4873fa070ae84a4115f0b3c9dfabc224f1bc7c51 + +The timekeeping code misses an update of the hrtimer subsystem after a +leap second happened. Due to that timers based on CLOCK_REALTIME are +either expiring a second early or late depending on whether a leap +second has been inserted or deleted until an operation is initiated +which causes that update. Unless the update happens by some other +means this discrepancy between the timekeeping and the hrtimer data +stays forever and timers are expired either early or late. + +The reported immediate workaround - $ data -s "`date`" - is causing a +call to clock_was_set() which updates the hrtimer data structures. +See: http://www.sheeri.com/content/mysql-and-leap-second-high-cpu-and-fix + +Add the missing clock_was_set() call to update_wall_time() in case of +a leap second event. The actual update is deferred to softirq context +as the necessary smp function call cannot be invoked from hard +interrupt context. + +Signed-off-by: John Stultz <johnstul@us.ibm.com> +Reported-by: Jan Engelhardt <jengelh@inai.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 +Link: http://lkml.kernel.org/r/1341960205-56738-3-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> +--- + kernel/time/timekeeping.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index adfa89d..634c9ee 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -769,6 +769,8 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift) + leap = second_overflow(xtime.tv_sec); + xtime.tv_sec += leap; + wall_to_monotonic.tv_sec -= leap; ++ if (leap) ++ clock_was_set_delayed(); + } + + /* Accumulate into raw time */ +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/timekeeping-Maintain-ktime_t-based-offsets-for-hrtim.patch b/queue/timekeeping-Maintain-ktime_t-based-offsets-for-hrtim.patch new file mode 100644 index 0000000..2c144f7 --- /dev/null +++ b/queue/timekeeping-Maintain-ktime_t-based-offsets-for-hrtim.patch @@ -0,0 +1,103 @@ +From 6ca2518b9f77a6a7f713b3a54aa74cdc113356fc Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Tue, 17 Jul 2012 17:49:27 -0400 +Subject: [PATCH] timekeeping: Maintain ktime_t based offsets for hrtimers + +This is a backport of 5b9fe759a678e05be4937ddf03d50e950207c1c0 + +We need to update the hrtimer clock offsets from the hrtimer interrupt +context. To avoid conversions from timespec to ktime_t maintain a +ktime_t based representation of those offsets in the timekeeper. This +puts the conversion overhead into the code which updates the +underlying offsets and provides fast accessible values in the hrtimer +interrupt. + +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: John Stultz <johnstul@us.ibm.com> +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 +Link: http://lkml.kernel.org/r/1341960205-56738-4-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> +--- + kernel/time/timekeeping.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index 634c9ee..3d443b4 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -161,18 +161,34 @@ struct timespec xtime __attribute__ ((aligned (16))); + struct timespec wall_to_monotonic __attribute__ ((aligned (16))); + static struct timespec total_sleep_time; + ++/* Offset clock monotonic -> clock realtime */ ++static ktime_t offs_real; ++ ++/* Offset clock monotonic -> clock boottime */ ++static ktime_t offs_boot; ++ + /* + * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. + */ + struct timespec raw_time; + + /* must hold write on xtime_lock */ ++static void update_rt_offset(void) ++{ ++ struct timespec tmp, *wtm = &wall_to_monotonic; ++ ++ set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec); ++ offs_real = timespec_to_ktime(tmp); ++} ++ ++/* must hold write on xtime_lock */ + static void timekeeping_update(bool clearntp) + { + if (clearntp) { + timekeeper.ntp_error = 0; + ntp_clear(); + } ++ update_rt_offset(); + update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult); + } + +@@ -565,6 +581,7 @@ void __init timekeeping_init(void) + set_normalized_timespec(&wall_to_monotonic, + -boot.tv_sec, -boot.tv_nsec); + update_xtime_cache(0); ++ update_rt_offset(); + total_sleep_time.tv_sec = 0; + total_sleep_time.tv_nsec = 0; + write_sequnlock_irqrestore(&xtime_lock, flags); +@@ -573,6 +590,12 @@ void __init timekeeping_init(void) + /* time in seconds when suspend began */ + static struct timespec timekeeping_suspend_time; + ++static void update_sleep_time(struct timespec t) ++{ ++ total_sleep_time = t; ++ offs_boot = timespec_to_ktime(t); ++} ++ + /** + * timekeeping_resume - Resumes the generic timekeeping subsystem. + * @dev: unused +@@ -596,7 +619,7 @@ static int timekeeping_resume(struct sys_device *dev) + ts = timespec_sub(ts, timekeeping_suspend_time); + xtime = timespec_add_safe(xtime, ts); + wall_to_monotonic = timespec_sub(wall_to_monotonic, ts); +- total_sleep_time = timespec_add_safe(total_sleep_time, ts); ++ update_sleep_time(timespec_add_safe(total_sleep_time, ts)); + } + update_xtime_cache(0); + /* re-base the last cycle value */ +-- +1.7.12.rc1.1.gbce1580 + diff --git a/queue/timekeeping-Provide-hrtimer-update-function.patch b/queue/timekeeping-Provide-hrtimer-update-function.patch new file mode 100644 index 0000000..668fcd0 --- /dev/null +++ b/queue/timekeeping-Provide-hrtimer-update-function.patch @@ -0,0 +1,90 @@ +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 + |