diff options
author | Yury Polyanskiy <ypolyans@princeton.edu> | 2010-05-24 17:33:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 11:07:02 -0400 |
commit | 940370fc86b920b51a34217a1facc3e9e97c2456 (patch) | |
tree | 6d53529bc158408c42df40d78ee728adb399f787 /drivers/char | |
parent | b3b77c8caef1750ebeea1054e39e358550ea9f55 (diff) |
hangcheck-timer: fix x86_32 bugs
drivers/char/hangcheck-timer.c is doubly broken. When the overflown value
of TIMER_FREQ is abnormally low, it spams the syslog with KERN_CRIT
messages "Hangcheck: hangcheck value past margin!" But whether it happens
or not depends on HZ and lpj in a complex way. People have hit it
occasionally as far as google search can tell.
First, the following line overflows unsigned long:
# define TIMER_FREQ (HZ*loops_per_jiffy)
Second, and more importantly, loops_per_jiffy has little to do with the
con= version from the the time scale of get_cycles() (aka rdtsc) to the
time scale of jiffies.
The attached patch resolves both of the problems.
Acked-by: Joel Becker <joel.becker@oracle.com>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Jan Glauber <jan.glauber@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hangcheck-timer.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 712d9f271aa6..e0249722d25f 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c | |||
@@ -49,8 +49,9 @@ | |||
49 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
50 | #include <linux/sysrq.h> | 50 | #include <linux/sysrq.h> |
51 | #include <linux/timer.h> | 51 | #include <linux/timer.h> |
52 | #include <linux/time.h> | ||
52 | 53 | ||
53 | #define VERSION_STR "0.9.0" | 54 | #define VERSION_STR "0.9.1" |
54 | 55 | ||
55 | #define DEFAULT_IOFENCE_MARGIN 60 /* Default fudge factor, in seconds */ | 56 | #define DEFAULT_IOFENCE_MARGIN 60 /* Default fudge factor, in seconds */ |
56 | #define DEFAULT_IOFENCE_TICK 180 /* Default timer timeout, in seconds */ | 57 | #define DEFAULT_IOFENCE_TICK 180 /* Default timer timeout, in seconds */ |
@@ -119,10 +120,8 @@ __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); | |||
119 | #if defined(CONFIG_S390) | 120 | #if defined(CONFIG_S390) |
120 | # define HAVE_MONOTONIC | 121 | # define HAVE_MONOTONIC |
121 | # define TIMER_FREQ 1000000000ULL | 122 | # define TIMER_FREQ 1000000000ULL |
122 | #elif defined(CONFIG_IA64) | ||
123 | # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) | ||
124 | #else | 123 | #else |
125 | # define TIMER_FREQ (HZ*loops_per_jiffy) | 124 | # define TIMER_FREQ 1000000000ULL |
126 | #endif | 125 | #endif |
127 | 126 | ||
128 | #ifdef HAVE_MONOTONIC | 127 | #ifdef HAVE_MONOTONIC |
@@ -130,7 +129,9 @@ extern unsigned long long monotonic_clock(void); | |||
130 | #else | 129 | #else |
131 | static inline unsigned long long monotonic_clock(void) | 130 | static inline unsigned long long monotonic_clock(void) |
132 | { | 131 | { |
133 | return get_cycles(); | 132 | struct timespec ts; |
133 | getrawmonotonic(&ts); | ||
134 | return timespec_to_ns(&ts); | ||
134 | } | 135 | } |
135 | #endif /* HAVE_MONOTONIC */ | 136 | #endif /* HAVE_MONOTONIC */ |
136 | 137 | ||
@@ -168,6 +169,13 @@ static void hangcheck_fire(unsigned long data) | |||
168 | printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n"); | 169 | printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n"); |
169 | } | 170 | } |
170 | } | 171 | } |
172 | #if 0 | ||
173 | /* | ||
174 | * Enable to investigate delays in detail | ||
175 | */ | ||
176 | printk("Hangcheck: called %Ld ns since last time (%Ld ns overshoot)\n", | ||
177 | tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ); | ||
178 | #endif | ||
171 | mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); | 179 | mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); |
172 | hangcheck_tsc = monotonic_clock(); | 180 | hangcheck_tsc = monotonic_clock(); |
173 | } | 181 | } |
@@ -180,7 +188,7 @@ static int __init hangcheck_init(void) | |||
180 | #if defined (HAVE_MONOTONIC) | 188 | #if defined (HAVE_MONOTONIC) |
181 | printk("Hangcheck: Using monotonic_clock().\n"); | 189 | printk("Hangcheck: Using monotonic_clock().\n"); |
182 | #else | 190 | #else |
183 | printk("Hangcheck: Using get_cycles().\n"); | 191 | printk("Hangcheck: Using getrawmonotonic().\n"); |
184 | #endif /* HAVE_MONOTONIC */ | 192 | #endif /* HAVE_MONOTONIC */ |
185 | hangcheck_tsc_margin = | 193 | hangcheck_tsc_margin = |
186 | (unsigned long long)(hangcheck_margin + hangcheck_tick); | 194 | (unsigned long long)(hangcheck_margin + hangcheck_tick); |