Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Jan Beulich and committed by
Linus Torvalds
1209140c 059bf0f6

+29 -25
+21 -16
arch/x86_64/kernel/traps.c
··· 343 343 static DEFINE_SPINLOCK(die_lock); 344 344 static int die_owner = -1; 345 345 346 - void oops_begin(void) 346 + unsigned long oops_begin(void) 347 347 { 348 - int cpu = safe_smp_processor_id(); 349 - /* racy, but better than risking deadlock. */ 350 - local_irq_disable(); 348 + int cpu = safe_smp_processor_id(); 349 + unsigned long flags; 350 + 351 + /* racy, but better than risking deadlock. */ 352 + local_irq_save(flags); 351 353 if (!spin_trylock(&die_lock)) { 352 354 if (cpu == die_owner) 353 355 /* nested oops. should stop eventually */; 354 356 else 355 - spin_lock(&die_lock); 357 + spin_lock(&die_lock); 356 358 } 357 - die_owner = cpu; 359 + die_owner = cpu; 358 360 console_verbose(); 359 - bust_spinlocks(1); 361 + bust_spinlocks(1); 362 + return flags; 360 363 } 361 364 362 - void oops_end(void) 365 + void oops_end(unsigned long flags) 363 366 { 364 367 die_owner = -1; 365 - bust_spinlocks(0); 366 - spin_unlock(&die_lock); 368 + bust_spinlocks(0); 369 + spin_unlock_irqrestore(&die_lock, flags); 367 370 if (panic_on_oops) 368 - panic("Oops"); 369 - } 371 + panic("Oops"); 372 + } 370 373 371 374 void __die(const char * str, struct pt_regs * regs, long err) 372 375 { ··· 395 392 396 393 void die(const char * str, struct pt_regs * regs, long err) 397 394 { 398 - oops_begin(); 395 + unsigned long flags = oops_begin(); 396 + 399 397 handle_BUG(regs); 400 398 __die(str, regs, err); 401 - oops_end(); 399 + oops_end(flags); 402 400 do_exit(SIGSEGV); 403 401 } 404 402 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) ··· 410 406 411 407 void die_nmi(char *str, struct pt_regs *regs) 412 408 { 413 - oops_begin(); 409 + unsigned long flags = oops_begin(); 410 + 414 411 /* 415 412 * We are in trouble anyway, lets at least try 416 413 * to get a message out. ··· 421 416 if (panic_on_timeout || panic_on_oops) 422 417 panic("nmi watchdog"); 423 418 printk("console shuts up ...\n"); 424 - oops_end(); 419 + oops_end(flags); 425 420 do_exit(SIGSEGV); 426 421 } 427 422
+6 -4
arch/x86_64/mm/fault.c
··· 221 221 static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, 222 222 unsigned long error_code) 223 223 { 224 - oops_begin(); 224 + unsigned long flags = oops_begin(); 225 + 225 226 printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", 226 227 current->comm, address); 227 228 dump_pagetable(address); 228 229 __die("Bad pagetable", regs, error_code); 229 - oops_end(); 230 + oops_end(flags); 230 231 do_exit(SIGKILL); 231 232 } 232 233 ··· 305 304 unsigned long address; 306 305 const struct exception_table_entry *fixup; 307 306 int write; 307 + unsigned long flags; 308 308 siginfo_t info; 309 309 310 310 #ifdef CONFIG_CHECKING ··· 523 521 * terminate things with extreme prejudice. 524 522 */ 525 523 526 - oops_begin(); 524 + flags = oops_begin(); 527 525 528 526 if (address < PAGE_SIZE) 529 527 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); ··· 536 534 __die("Oops", regs, error_code); 537 535 /* Executive summary in case the body of the oops scrolled away */ 538 536 printk(KERN_EMERG "CR2: %016lx\n", address); 539 - oops_end(); 537 + oops_end(flags); 540 538 do_exit(SIGKILL); 541 539 542 540 /*
+2 -2
include/asm-x86_64/kdebug.h
··· 46 46 extern void __die(const char *,struct pt_regs *,long); 47 47 extern void show_registers(struct pt_regs *regs); 48 48 extern void dump_pagetable(unsigned long); 49 - extern void oops_begin(void); 50 - extern void oops_end(void); 49 + extern unsigned long oops_begin(void); 50 + extern void oops_end(unsigned long); 51 51 52 52 #endif
-3
include/asm-x86_64/proto.h
··· 74 74 75 75 extern void swap_low_mappings(void); 76 76 77 - extern void oops_begin(void); 78 - extern void die(const char *,struct pt_regs *,long); 79 - extern void __die(const char * str, struct pt_regs * regs, long err); 80 77 extern void __show_regs(struct pt_regs * regs); 81 78 extern void show_regs(struct pt_regs * regs); 82 79