Hey Thomas,
Chris and Jason provided some fixes that are needed for
the 2.6.36-rc tree. I'll backport the overflow issue for
2.6.35-stable once it is upstream.
thanks
-john
Cc: Thomas Gleixner <[email protected]>
Chris Wilson (1):
x86/hpet: Use the FSEC_PER_SEC constant for femto-second periods
Jason Wessel (1):
timekeeping: Fix overflow in rawtime tv_nsec on 32 bit archs
arch/x86/kernel/hpet.c | 4 ++--
include/linux/time.h | 2 +-
kernel/time/timekeeping.c | 11 +++++++----
3 files changed, 10 insertions(+), 7 deletions(-)
From: Chris Wilson <[email protected]>
The current computation, introduced with f12a15be63, of FSEC_PER_SEC using
the multiplication of (FSEC_PER_NSEC * NSEC_PER_SEC) is performed only
with 32bit integers on small machines, resulting in an overflow and a
*very* short intervals being programmed. An interrupt storm follows.
Note that we also have to specify FSEC_PER_SEC as being long long to
overcome the same limitations.
Signed-off-by: Chris Wilson <[email protected]>
Signed-off-by: John Stultz <[email protected]>
Cc: Thomas Gleixner <[email protected]>
---
arch/x86/kernel/hpet.c | 4 ++--
include/linux/time.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 33dbcc4..351f9c0 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -582,7 +582,7 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
* scaled math multiplication factor for nanosecond to hpet tick
* conversion.
*/
- hpet_freq = 1000000000000000ULL;
+ hpet_freq = FSEC_PER_SEC;
do_div(hpet_freq, hpet_period);
evt->mult = div_sc((unsigned long) hpet_freq,
NSEC_PER_SEC, evt->shift);
@@ -837,7 +837,7 @@ static int hpet_clocksource_register(void)
* cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc)
* cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period
*/
- hpet_freq = FSEC_PER_NSEC * NSEC_PER_SEC;
+ hpet_freq = FSEC_PER_SEC;
do_div(hpet_freq, hpet_period);
clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
diff --git a/include/linux/time.h b/include/linux/time.h
index cb34e35..1261270 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -38,7 +38,7 @@ extern struct timezone sys_tz;
#define NSEC_PER_MSEC 1000000L
#define USEC_PER_SEC 1000000L
#define NSEC_PER_SEC 1000000000L
-#define FSEC_PER_SEC 1000000000000000L
+#define FSEC_PER_SEC 1000000000000000LL
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
--
1.6.0.4
From: Jason Wessel <[email protected]>
The tv_nsec is a long and when added to the shifted interval it can wrap
and become negative which later causes looping problems in the
getrawmonotonic(). The edge case occurs when the system has slept for
a short period of time of ~2 seconds.
A trace printk of the values in this patch illustrate the problem:
ftrace time stamp: log
43.716079: logarithmic_accumulation: raw: 3d0913 tv_nsec d687faa
43.718513: logarithmic_accumulation: raw: 3d0913 tv_nsec da588bd
43.722161: logarithmic_accumulation: raw: 3d0913 tv_nsec de291d0
46.349925: logarithmic_accumulation: raw: 7a122600 tv_nsec e1f9ae3
46.349930: logarithmic_accumulation: raw: 1e848980 tv_nsec 8831c0e3
The kernel starts looping at 46.349925 in the getrawmonotonic() due to
the negative value from adding the raw value to tv_nsec.
A simple solution is to accumulate into a u64, and then normalize it
to a timespec_t.
Signed-off-by: Jason Wessel <[email protected]>
Reworked variable names and sipmlified some of the code.
Signed-off-by: John Stultz <[email protected]>
CC: Thomas Gleixner <[email protected]>
CC: H. Peter Anvin <[email protected]>
---
kernel/time/timekeeping.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e14c839..e960d82 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -690,6 +690,7 @@ static void timekeeping_adjust(s64 offset)
static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
{
u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
+ u64 raw_nsecs;
/* If the offset is smaller then a shifted interval, do nothing */
if (offset < timekeeper.cycle_interval<<shift)
@@ -706,12 +707,14 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
second_overflow();
}
- /* Accumulate into raw time */
- raw_time.tv_nsec += timekeeper.raw_interval << shift;;
- while (raw_time.tv_nsec >= NSEC_PER_SEC) {
- raw_time.tv_nsec -= NSEC_PER_SEC;
+ /* Accumulate raw time */
+ raw_nsecs = timekeeper.raw_interval << shift;
+ raw_nsecs += raw_time.tv_nsec;
+ while (raw_nsecs >= NSEC_PER_SEC) {
+ raw_nsecs -= NSEC_PER_SEC;
raw_time.tv_sec++;
}
+ raw_time.tv_nsec = raw_nsecs;
/* Accumulate error between NTP and clock interval */
timekeeper.ntp_error += tick_length << shift;
--
1.6.0.4