aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2005-09-12 12:49:24 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-12 13:50:57 -0400
commit1209140c3c70aaa32d1a0462d79557f2a44a4ef8 (patch)
tree2dc299ad357392f7d81e85131615bb61f0b1a14c /arch/x86_64
parent059bf0f6c33058680e4381f17d554baaa4f45d68 (diff)
[PATCH] x86-64: Safe interrupts in oops_begin/end
Rather than blindly re-enabling interrupts in oops_end(), save their state in oope_begin() and then restore that state. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/traps.c37
-rw-r--r--arch/x86_64/mm/fault.c10
2 files changed, 27 insertions, 20 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index f238d6078a5a..64a59cb49411 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -343,30 +343,33 @@ void out_of_line_bug(void)
343static DEFINE_SPINLOCK(die_lock); 343static DEFINE_SPINLOCK(die_lock);
344static int die_owner = -1; 344static int die_owner = -1;
345 345
346void oops_begin(void) 346unsigned long oops_begin(void)
347{ 347{
348 int cpu = safe_smp_processor_id(); 348 int cpu = safe_smp_processor_id();
349 /* racy, but better than risking deadlock. */ 349 unsigned long flags;
350 local_irq_disable(); 350
351 /* racy, but better than risking deadlock. */
352 local_irq_save(flags);
351 if (!spin_trylock(&die_lock)) { 353 if (!spin_trylock(&die_lock)) {
352 if (cpu == die_owner) 354 if (cpu == die_owner)
353 /* nested oops. should stop eventually */; 355 /* nested oops. should stop eventually */;
354 else 356 else
355 spin_lock(&die_lock); 357 spin_lock(&die_lock);
356 } 358 }
357 die_owner = cpu; 359 die_owner = cpu;
358 console_verbose(); 360 console_verbose();
359 bust_spinlocks(1); 361 bust_spinlocks(1);
362 return flags;
360} 363}
361 364
362void oops_end(void) 365void oops_end(unsigned long flags)
363{ 366{
364 die_owner = -1; 367 die_owner = -1;
365 bust_spinlocks(0); 368 bust_spinlocks(0);
366 spin_unlock(&die_lock); 369 spin_unlock_irqrestore(&die_lock, flags);
367 if (panic_on_oops) 370 if (panic_on_oops)
368 panic("Oops"); 371 panic("Oops");
369} 372}
370 373
371void __die(const char * str, struct pt_regs * regs, long err) 374void __die(const char * str, struct pt_regs * regs, long err)
372{ 375{
@@ -392,10 +395,11 @@ void __die(const char * str, struct pt_regs * regs, long err)
392 395
393void die(const char * str, struct pt_regs * regs, long err) 396void die(const char * str, struct pt_regs * regs, long err)
394{ 397{
395 oops_begin(); 398 unsigned long flags = oops_begin();
399
396 handle_BUG(regs); 400 handle_BUG(regs);
397 __die(str, regs, err); 401 __die(str, regs, err);
398 oops_end(); 402 oops_end(flags);
399 do_exit(SIGSEGV); 403 do_exit(SIGSEGV);
400} 404}
401static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) 405static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
@@ -406,7 +410,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
406 410
407void die_nmi(char *str, struct pt_regs *regs) 411void die_nmi(char *str, struct pt_regs *regs)
408{ 412{
409 oops_begin(); 413 unsigned long flags = oops_begin();
414
410 /* 415 /*
411 * We are in trouble anyway, lets at least try 416 * We are in trouble anyway, lets at least try
412 * to get a message out. 417 * to get a message out.
@@ -416,7 +421,7 @@ void die_nmi(char *str, struct pt_regs *regs)
416 if (panic_on_timeout || panic_on_oops) 421 if (panic_on_timeout || panic_on_oops)
417 panic("nmi watchdog"); 422 panic("nmi watchdog");
418 printk("console shuts up ...\n"); 423 printk("console shuts up ...\n");
419 oops_end(); 424 oops_end(flags);
420 do_exit(SIGSEGV); 425 do_exit(SIGSEGV);
421} 426}
422 427
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 816732d8858c..b75b872ec154 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig)
221static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, 221static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
222 unsigned long error_code) 222 unsigned long error_code)
223{ 223{
224 oops_begin(); 224 unsigned long flags = oops_begin();
225
225 printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", 226 printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
226 current->comm, address); 227 current->comm, address);
227 dump_pagetable(address); 228 dump_pagetable(address);
228 __die("Bad pagetable", regs, error_code); 229 __die("Bad pagetable", regs, error_code);
229 oops_end(); 230 oops_end(flags);
230 do_exit(SIGKILL); 231 do_exit(SIGKILL);
231} 232}
232 233
@@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
304 unsigned long address; 305 unsigned long address;
305 const struct exception_table_entry *fixup; 306 const struct exception_table_entry *fixup;
306 int write; 307 int write;
308 unsigned long flags;
307 siginfo_t info; 309 siginfo_t info;
308 310
309#ifdef CONFIG_CHECKING 311#ifdef CONFIG_CHECKING
@@ -521,7 +523,7 @@ no_context:
521 * terminate things with extreme prejudice. 523 * terminate things with extreme prejudice.
522 */ 524 */
523 525
524 oops_begin(); 526 flags = oops_begin();
525 527
526 if (address < PAGE_SIZE) 528 if (address < PAGE_SIZE)
527 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); 529 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
@@ -534,7 +536,7 @@ no_context:
534 __die("Oops", regs, error_code); 536 __die("Oops", regs, error_code);
535 /* Executive summary in case the body of the oops scrolled away */ 537 /* Executive summary in case the body of the oops scrolled away */
536 printk(KERN_EMERG "CR2: %016lx\n", address); 538 printk(KERN_EMERG "CR2: %016lx\n", address);
537 oops_end(); 539 oops_end(flags);
538 do_exit(SIGKILL); 540 do_exit(SIGKILL);
539 541
540/* 542/*