diff options
author | Jan Beulich <jbeulich@novell.com> | 2005-09-12 12:49:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-12 13:50:57 -0400 |
commit | 1209140c3c70aaa32d1a0462d79557f2a44a4ef8 (patch) | |
tree | 2dc299ad357392f7d81e85131615bb61f0b1a14c | |
parent | 059bf0f6c33058680e4381f17d554baaa4f45d68 (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>
-rw-r--r-- | arch/x86_64/kernel/traps.c | 37 | ||||
-rw-r--r-- | arch/x86_64/mm/fault.c | 10 | ||||
-rw-r--r-- | include/asm-x86_64/kdebug.h | 4 | ||||
-rw-r--r-- | include/asm-x86_64/proto.h | 3 |
4 files changed, 29 insertions, 25 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) | |||
343 | static DEFINE_SPINLOCK(die_lock); | 343 | static DEFINE_SPINLOCK(die_lock); |
344 | static int die_owner = -1; | 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(); | 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 | ||
362 | void oops_end(void) | 365 | void 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 | ||
371 | void __die(const char * str, struct pt_regs * regs, long err) | 374 | void __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 | ||
393 | void die(const char * str, struct pt_regs * regs, long err) | 396 | void 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 | } |
401 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | 405 | static 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 | ||
407 | void die_nmi(char *str, struct pt_regs *regs) | 411 | void 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) | |||
221 | static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | 221 | static 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 | /* |
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b90341994d80..f604e84c5303 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h | |||
@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long); | |||
46 | extern void __die(const char *,struct pt_regs *,long); | 46 | extern void __die(const char *,struct pt_regs *,long); |
47 | extern void show_registers(struct pt_regs *regs); | 47 | extern void show_registers(struct pt_regs *regs); |
48 | extern void dump_pagetable(unsigned long); | 48 | extern void dump_pagetable(unsigned long); |
49 | extern void oops_begin(void); | 49 | extern unsigned long oops_begin(void); |
50 | extern void oops_end(void); | 50 | extern void oops_end(unsigned long); |
51 | 51 | ||
52 | #endif | 52 | #endif |
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index 764b5f822ce2..dbb37b0adb43 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h | |||
@@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void); | |||
74 | 74 | ||
75 | extern void swap_low_mappings(void); | 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 | extern void __show_regs(struct pt_regs * regs); | 77 | extern void __show_regs(struct pt_regs * regs); |
81 | extern void show_regs(struct pt_regs * regs); | 78 | extern void show_regs(struct pt_regs * regs); |
82 | 79 | ||