diff options
Diffstat (limited to 'kernel/panic.c')
-rw-r--r-- | kernel/panic.c | 97 |
1 files changed, 96 insertions, 1 deletions
diff --git a/kernel/panic.c b/kernel/panic.c index 126dc43f1c74..acd95adddb93 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -20,10 +20,13 @@ | |||
20 | #include <linux/nmi.h> | 20 | #include <linux/nmi.h> |
21 | #include <linux/kexec.h> | 21 | #include <linux/kexec.h> |
22 | 22 | ||
23 | int panic_timeout; | ||
24 | int panic_on_oops; | 23 | int panic_on_oops; |
25 | int tainted; | 24 | int tainted; |
25 | static int pause_on_oops; | ||
26 | static int pause_on_oops_flag; | ||
27 | static DEFINE_SPINLOCK(pause_on_oops_lock); | ||
26 | 28 | ||
29 | int panic_timeout; | ||
27 | EXPORT_SYMBOL(panic_timeout); | 30 | EXPORT_SYMBOL(panic_timeout); |
28 | 31 | ||
29 | struct notifier_block *panic_notifier_list; | 32 | struct notifier_block *panic_notifier_list; |
@@ -174,3 +177,95 @@ void add_taint(unsigned flag) | |||
174 | tainted |= flag; | 177 | tainted |= flag; |
175 | } | 178 | } |
176 | EXPORT_SYMBOL(add_taint); | 179 | EXPORT_SYMBOL(add_taint); |
180 | |||
181 | static int __init pause_on_oops_setup(char *str) | ||
182 | { | ||
183 | pause_on_oops = simple_strtoul(str, NULL, 0); | ||
184 | return 1; | ||
185 | } | ||
186 | __setup("pause_on_oops=", pause_on_oops_setup); | ||
187 | |||
188 | static void spin_msec(int msecs) | ||
189 | { | ||
190 | int i; | ||
191 | |||
192 | for (i = 0; i < msecs; i++) { | ||
193 | touch_nmi_watchdog(); | ||
194 | mdelay(1); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * It just happens that oops_enter() and oops_exit() are identically | ||
200 | * implemented... | ||
201 | */ | ||
202 | static void do_oops_enter_exit(void) | ||
203 | { | ||
204 | unsigned long flags; | ||
205 | static int spin_counter; | ||
206 | |||
207 | if (!pause_on_oops) | ||
208 | return; | ||
209 | |||
210 | spin_lock_irqsave(&pause_on_oops_lock, flags); | ||
211 | if (pause_on_oops_flag == 0) { | ||
212 | /* This CPU may now print the oops message */ | ||
213 | pause_on_oops_flag = 1; | ||
214 | } else { | ||
215 | /* We need to stall this CPU */ | ||
216 | if (!spin_counter) { | ||
217 | /* This CPU gets to do the counting */ | ||
218 | spin_counter = pause_on_oops; | ||
219 | do { | ||
220 | spin_unlock(&pause_on_oops_lock); | ||
221 | spin_msec(MSEC_PER_SEC); | ||
222 | spin_lock(&pause_on_oops_lock); | ||
223 | } while (--spin_counter); | ||
224 | pause_on_oops_flag = 0; | ||
225 | } else { | ||
226 | /* This CPU waits for a different one */ | ||
227 | while (spin_counter) { | ||
228 | spin_unlock(&pause_on_oops_lock); | ||
229 | spin_msec(1); | ||
230 | spin_lock(&pause_on_oops_lock); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | spin_unlock_irqrestore(&pause_on_oops_lock, flags); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Return true if the calling CPU is allowed to print oops-related info. This | ||
239 | * is a bit racy.. | ||
240 | */ | ||
241 | int oops_may_print(void) | ||
242 | { | ||
243 | return pause_on_oops_flag == 0; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Called when the architecture enters its oops handler, before it prints | ||
248 | * anything. If this is the first CPU to oops, and it's oopsing the first time | ||
249 | * then let it proceed. | ||
250 | * | ||
251 | * This is all enabled by the pause_on_oops kernel boot option. We do all this | ||
252 | * to ensure that oopses don't scroll off the screen. It has the side-effect | ||
253 | * of preventing later-oopsing CPUs from mucking up the display, too. | ||
254 | * | ||
255 | * It turns out that the CPU which is allowed to print ends up pausing for the | ||
256 | * right duration, whereas all the other CPUs pause for twice as long: once in | ||
257 | * oops_enter(), once in oops_exit(). | ||
258 | */ | ||
259 | void oops_enter(void) | ||
260 | { | ||
261 | do_oops_enter_exit(); | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * Called when the architecture exits its oops handler, after printing | ||
266 | * everything. | ||
267 | */ | ||
268 | void oops_exit(void) | ||
269 | { | ||
270 | do_oops_enter_exit(); | ||
271 | } | ||