diff options
Diffstat (limited to 'kernel/panic.c')
-rw-r--r-- | kernel/panic.c | 87 |
1 files changed, 50 insertions, 37 deletions
diff --git a/kernel/panic.c b/kernel/panic.c index 13d966b4c14a..4c13b1a88ebb 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -24,6 +24,9 @@ | |||
24 | #include <linux/nmi.h> | 24 | #include <linux/nmi.h> |
25 | #include <linux/dmi.h> | 25 | #include <linux/dmi.h> |
26 | 26 | ||
27 | #define PANIC_TIMER_STEP 100 | ||
28 | #define PANIC_BLINK_SPD 18 | ||
29 | |||
27 | int panic_on_oops; | 30 | int panic_on_oops; |
28 | static unsigned long tainted_mask; | 31 | static unsigned long tainted_mask; |
29 | static int pause_on_oops; | 32 | static int pause_on_oops; |
@@ -36,36 +39,15 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); | |||
36 | 39 | ||
37 | EXPORT_SYMBOL(panic_notifier_list); | 40 | EXPORT_SYMBOL(panic_notifier_list); |
38 | 41 | ||
39 | /* Returns how long it waited in ms */ | 42 | static long no_blink(int state) |
40 | long (*panic_blink)(long time); | ||
41 | EXPORT_SYMBOL(panic_blink); | ||
42 | |||
43 | static void panic_blink_one_second(void) | ||
44 | { | 43 | { |
45 | static long i = 0, end; | 44 | return 0; |
46 | |||
47 | if (panic_blink) { | ||
48 | end = i + MSEC_PER_SEC; | ||
49 | |||
50 | while (i < end) { | ||
51 | i += panic_blink(i); | ||
52 | mdelay(1); | ||
53 | i++; | ||
54 | } | ||
55 | } else { | ||
56 | /* | ||
57 | * When running under a hypervisor a small mdelay may get | ||
58 | * rounded up to the hypervisor timeslice. For example, with | ||
59 | * a 1ms in 10ms hypervisor timeslice we might inflate a | ||
60 | * mdelay(1) loop by 10x. | ||
61 | * | ||
62 | * If we have nothing to blink, spin on 1 second calls to | ||
63 | * mdelay to avoid this. | ||
64 | */ | ||
65 | mdelay(MSEC_PER_SEC); | ||
66 | } | ||
67 | } | 45 | } |
68 | 46 | ||
47 | /* Returns how long it waited in ms */ | ||
48 | long (*panic_blink)(int state); | ||
49 | EXPORT_SYMBOL(panic_blink); | ||
50 | |||
69 | /** | 51 | /** |
70 | * panic - halt the system | 52 | * panic - halt the system |
71 | * @fmt: The text string to print | 53 | * @fmt: The text string to print |
@@ -78,7 +60,8 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
78 | { | 60 | { |
79 | static char buf[1024]; | 61 | static char buf[1024]; |
80 | va_list args; | 62 | va_list args; |
81 | long i; | 63 | long i, i_next = 0; |
64 | int state = 0; | ||
82 | 65 | ||
83 | /* | 66 | /* |
84 | * It's possible to come here directly from a panic-assertion and | 67 | * It's possible to come here directly from a panic-assertion and |
@@ -87,6 +70,7 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
87 | */ | 70 | */ |
88 | preempt_disable(); | 71 | preempt_disable(); |
89 | 72 | ||
73 | console_verbose(); | ||
90 | bust_spinlocks(1); | 74 | bust_spinlocks(1); |
91 | va_start(args, fmt); | 75 | va_start(args, fmt); |
92 | vsnprintf(buf, sizeof(buf), fmt, args); | 76 | vsnprintf(buf, sizeof(buf), fmt, args); |
@@ -116,6 +100,9 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
116 | 100 | ||
117 | bust_spinlocks(0); | 101 | bust_spinlocks(0); |
118 | 102 | ||
103 | if (!panic_blink) | ||
104 | panic_blink = no_blink; | ||
105 | |||
119 | if (panic_timeout > 0) { | 106 | if (panic_timeout > 0) { |
120 | /* | 107 | /* |
121 | * Delay timeout seconds before rebooting the machine. | 108 | * Delay timeout seconds before rebooting the machine. |
@@ -123,9 +110,13 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
123 | */ | 110 | */ |
124 | printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout); | 111 | printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout); |
125 | 112 | ||
126 | for (i = 0; i < panic_timeout; i++) { | 113 | for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) { |
127 | touch_nmi_watchdog(); | 114 | touch_nmi_watchdog(); |
128 | panic_blink_one_second(); | 115 | if (i >= i_next) { |
116 | i += panic_blink(state ^= 1); | ||
117 | i_next = i + 3600 / PANIC_BLINK_SPD; | ||
118 | } | ||
119 | mdelay(PANIC_TIMER_STEP); | ||
129 | } | 120 | } |
130 | /* | 121 | /* |
131 | * This will not be a clean reboot, with everything | 122 | * This will not be a clean reboot, with everything |
@@ -151,9 +142,13 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
151 | } | 142 | } |
152 | #endif | 143 | #endif |
153 | local_irq_enable(); | 144 | local_irq_enable(); |
154 | while (1) { | 145 | for (i = 0; ; i += PANIC_TIMER_STEP) { |
155 | touch_softlockup_watchdog(); | 146 | touch_softlockup_watchdog(); |
156 | panic_blink_one_second(); | 147 | if (i >= i_next) { |
148 | i += panic_blink(state ^= 1); | ||
149 | i_next = i + 3600 / PANIC_BLINK_SPD; | ||
150 | } | ||
151 | mdelay(PANIC_TIMER_STEP); | ||
157 | } | 152 | } |
158 | } | 153 | } |
159 | 154 | ||
@@ -178,6 +173,7 @@ static const struct tnt tnts[] = { | |||
178 | { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' }, | 173 | { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' }, |
179 | { TAINT_WARN, 'W', ' ' }, | 174 | { TAINT_WARN, 'W', ' ' }, |
180 | { TAINT_CRAP, 'C', ' ' }, | 175 | { TAINT_CRAP, 'C', ' ' }, |
176 | { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, | ||
181 | }; | 177 | }; |
182 | 178 | ||
183 | /** | 179 | /** |
@@ -194,6 +190,7 @@ static const struct tnt tnts[] = { | |||
194 | * 'A' - ACPI table overridden. | 190 | * 'A' - ACPI table overridden. |
195 | * 'W' - Taint on warning. | 191 | * 'W' - Taint on warning. |
196 | * 'C' - modules from drivers/staging are loaded. | 192 | * 'C' - modules from drivers/staging are loaded. |
193 | * 'I' - Working around severe firmware bug. | ||
197 | * | 194 | * |
198 | * The string is overwritten by the next call to print_tainted(). | 195 | * The string is overwritten by the next call to print_tainted(). |
199 | */ | 196 | */ |
@@ -341,7 +338,7 @@ static int init_oops_id(void) | |||
341 | } | 338 | } |
342 | late_initcall(init_oops_id); | 339 | late_initcall(init_oops_id); |
343 | 340 | ||
344 | static void print_oops_end_marker(void) | 341 | void print_oops_end_marker(void) |
345 | { | 342 | { |
346 | init_oops_id(); | 343 | init_oops_id(); |
347 | printk(KERN_WARNING "---[ end trace %016llx ]---\n", | 344 | printk(KERN_WARNING "---[ end trace %016llx ]---\n", |
@@ -365,7 +362,8 @@ struct slowpath_args { | |||
365 | va_list args; | 362 | va_list args; |
366 | }; | 363 | }; |
367 | 364 | ||
368 | static void warn_slowpath_common(const char *file, int line, void *caller, struct slowpath_args *args) | 365 | static void warn_slowpath_common(const char *file, int line, void *caller, |
366 | unsigned taint, struct slowpath_args *args) | ||
369 | { | 367 | { |
370 | const char *board; | 368 | const char *board; |
371 | 369 | ||
@@ -381,7 +379,7 @@ static void warn_slowpath_common(const char *file, int line, void *caller, struc | |||
381 | print_modules(); | 379 | print_modules(); |
382 | dump_stack(); | 380 | dump_stack(); |
383 | print_oops_end_marker(); | 381 | print_oops_end_marker(); |
384 | add_taint(TAINT_WARN); | 382 | add_taint(taint); |
385 | } | 383 | } |
386 | 384 | ||
387 | void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...) | 385 | void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...) |
@@ -390,14 +388,29 @@ void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...) | |||
390 | 388 | ||
391 | args.fmt = fmt; | 389 | args.fmt = fmt; |
392 | va_start(args.args, fmt); | 390 | va_start(args.args, fmt); |
393 | warn_slowpath_common(file, line, __builtin_return_address(0), &args); | 391 | warn_slowpath_common(file, line, __builtin_return_address(0), |
392 | TAINT_WARN, &args); | ||
394 | va_end(args.args); | 393 | va_end(args.args); |
395 | } | 394 | } |
396 | EXPORT_SYMBOL(warn_slowpath_fmt); | 395 | EXPORT_SYMBOL(warn_slowpath_fmt); |
397 | 396 | ||
397 | void warn_slowpath_fmt_taint(const char *file, int line, | ||
398 | unsigned taint, const char *fmt, ...) | ||
399 | { | ||
400 | struct slowpath_args args; | ||
401 | |||
402 | args.fmt = fmt; | ||
403 | va_start(args.args, fmt); | ||
404 | warn_slowpath_common(file, line, __builtin_return_address(0), | ||
405 | taint, &args); | ||
406 | va_end(args.args); | ||
407 | } | ||
408 | EXPORT_SYMBOL(warn_slowpath_fmt_taint); | ||
409 | |||
398 | void warn_slowpath_null(const char *file, int line) | 410 | void warn_slowpath_null(const char *file, int line) |
399 | { | 411 | { |
400 | warn_slowpath_common(file, line, __builtin_return_address(0), NULL); | 412 | warn_slowpath_common(file, line, __builtin_return_address(0), |
413 | TAINT_WARN, NULL); | ||
401 | } | 414 | } |
402 | EXPORT_SYMBOL(warn_slowpath_null); | 415 | EXPORT_SYMBOL(warn_slowpath_null); |
403 | #endif | 416 | #endif |