40 #include <linux/module.h>
42 #include <linux/types.h>
43 #include <linux/kernel.h>
46 #include <linux/reboot.h>
49 #include <asm/uaccess.h>
52 #include <linux/time.h>
54 #define VERSION_STR "0.9.1"
56 #define DEFAULT_IOFENCE_MARGIN 60
57 #define DEFAULT_IOFENCE_TICK 180
61 static int hangcheck_reboot;
62 static int hangcheck_dump_tasks;
68 MODULE_PARM_DESC(hangcheck_margin,
"If the hangcheck timer has been delayed more than hangcheck_margin seconds, the driver will fire.");
70 MODULE_PARM_DESC(hangcheck_reboot,
"If nonzero, the machine will reboot when the timer margin is exceeded.");
72 MODULE_PARM_DESC(hangcheck_dump_tasks,
"If nonzero, the machine will dump the system task state when the timer margin is exceeded.");
75 MODULE_DESCRIPTION(
"Hangcheck-timer detects when the system has gone out to lunch past a certain margin.");
82 static int __init hangcheck_parse_tick(
char *
str)
90 static int __init hangcheck_parse_margin(
char *str)
94 hangcheck_margin = par;
98 static int __init hangcheck_parse_reboot(
char *str)
102 hangcheck_reboot = par;
106 static int __init hangcheck_parse_dump_tasks(
char *str)
110 hangcheck_dump_tasks = par;
114 __setup(
"hcheck_tick", hangcheck_parse_tick);
115 __setup(
"hcheck_margin", hangcheck_parse_margin);
116 __setup(
"hcheck_reboot", hangcheck_parse_reboot);
117 __setup(
"hcheck_dump_tasks", hangcheck_parse_dump_tasks);
120 #if defined(CONFIG_S390)
121 # define HAVE_MONOTONIC
122 # define TIMER_FREQ 1000000000ULL
124 # define TIMER_FREQ 1000000000ULL
127 #ifdef HAVE_MONOTONIC
134 return timespec_to_ns(&
ts);
140 static unsigned long long hangcheck_tsc, hangcheck_tsc_margin;
142 static void hangcheck_fire(
unsigned long);
144 static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0);
147 static void hangcheck_fire(
unsigned long data)
149 unsigned long long cur_tsc, tsc_diff;
153 if (cur_tsc > hangcheck_tsc)
154 tsc_diff = cur_tsc - hangcheck_tsc;
156 tsc_diff = (cur_tsc + (~0ULL - hangcheck_tsc));
158 if (tsc_diff > hangcheck_tsc_margin) {
159 if (hangcheck_dump_tasks) {
161 #ifdef CONFIG_MAGIC_SYSRQ
165 if (hangcheck_reboot) {
176 printk(
"Hangcheck: called %Ld ns since last time (%Ld ns overshoot)\n",
177 tsc_diff, tsc_diff - hangcheck_tick*
TIMER_FREQ);
179 mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*
HZ));
184 static int __init hangcheck_init(
void)
186 printk(
"Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
188 #if defined (HAVE_MONOTONIC)
189 printk(
"Hangcheck: Using monotonic_clock().\n");
191 printk(
"Hangcheck: Using getrawmonotonic().\n");
193 hangcheck_tsc_margin =
194 (
unsigned long long)(hangcheck_margin + hangcheck_tick);
198 mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*
HZ));
204 static void __exit hangcheck_exit(
void)
207 printk(
"Hangcheck: Stopped hangcheck timer.\n");