Commit 1209140c authored by Jan Beulich's avatar Jan Beulich Committed by Linus Torvalds

[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: default avatarJan Beulich <jbeulich@novell.com>
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 059bf0f6
...@@ -343,11 +343,13 @@ void out_of_line_bug(void) ...@@ -343,11 +343,13 @@ void out_of_line_bug(void)
static DEFINE_SPINLOCK(die_lock); static DEFINE_SPINLOCK(die_lock);
static int die_owner = -1; static int die_owner = -1;
void oops_begin(void) unsigned long oops_begin(void)
{ {
int cpu = safe_smp_processor_id(); int cpu = safe_smp_processor_id();
unsigned long flags;
/* racy, but better than risking deadlock. */ /* racy, but better than risking deadlock. */
local_irq_disable(); local_irq_save(flags);
if (!spin_trylock(&die_lock)) { if (!spin_trylock(&die_lock)) {
if (cpu == die_owner) if (cpu == die_owner)
/* nested oops. should stop eventually */; /* nested oops. should stop eventually */;
...@@ -357,13 +359,14 @@ void oops_begin(void) ...@@ -357,13 +359,14 @@ void oops_begin(void)
die_owner = cpu; die_owner = cpu;
console_verbose(); console_verbose();
bust_spinlocks(1); bust_spinlocks(1);
return flags;
} }
void oops_end(void) void oops_end(unsigned long flags)
{ {
die_owner = -1; die_owner = -1;
bust_spinlocks(0); bust_spinlocks(0);
spin_unlock(&die_lock); spin_unlock_irqrestore(&die_lock, flags);
if (panic_on_oops) if (panic_on_oops)
panic("Oops"); panic("Oops");
} }
...@@ -392,10 +395,11 @@ void __die(const char * str, struct pt_regs * regs, long err) ...@@ -392,10 +395,11 @@ void __die(const char * str, struct pt_regs * regs, long err)
void die(const char * str, struct pt_regs * regs, long err) void die(const char * str, struct pt_regs * regs, long err)
{ {
oops_begin(); unsigned long flags = oops_begin();
handle_BUG(regs); handle_BUG(regs);
__die(str, regs, err); __die(str, regs, err);
oops_end(); oops_end(flags);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) 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,7 +410,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
void die_nmi(char *str, struct pt_regs *regs) void die_nmi(char *str, struct pt_regs *regs)
{ {
oops_begin(); unsigned long flags = oops_begin();
/* /*
* We are in trouble anyway, lets at least try * We are in trouble anyway, lets at least try
* to get a message out. * to get a message out.
...@@ -416,7 +421,7 @@ void die_nmi(char *str, struct pt_regs *regs) ...@@ -416,7 +421,7 @@ void die_nmi(char *str, struct pt_regs *regs)
if (panic_on_timeout || panic_on_oops) if (panic_on_timeout || panic_on_oops)
panic("nmi watchdog"); panic("nmi watchdog");
printk("console shuts up ...\n"); printk("console shuts up ...\n");
oops_end(); oops_end(flags);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
......
...@@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig) ...@@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig)
static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
unsigned long error_code) unsigned long error_code)
{ {
oops_begin(); unsigned long flags = oops_begin();
printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
current->comm, address); current->comm, address);
dump_pagetable(address); dump_pagetable(address);
__die("Bad pagetable", regs, error_code); __die("Bad pagetable", regs, error_code);
oops_end(); oops_end(flags);
do_exit(SIGKILL); do_exit(SIGKILL);
} }
...@@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, ...@@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long address; unsigned long address;
const struct exception_table_entry *fixup; const struct exception_table_entry *fixup;
int write; int write;
unsigned long flags;
siginfo_t info; siginfo_t info;
#ifdef CONFIG_CHECKING #ifdef CONFIG_CHECKING
...@@ -521,7 +523,7 @@ no_context: ...@@ -521,7 +523,7 @@ no_context:
* terminate things with extreme prejudice. * terminate things with extreme prejudice.
*/ */
oops_begin(); flags = oops_begin();
if (address < PAGE_SIZE) if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
...@@ -534,7 +536,7 @@ no_context: ...@@ -534,7 +536,7 @@ no_context:
__die("Oops", regs, error_code); __die("Oops", regs, error_code);
/* Executive summary in case the body of the oops scrolled away */ /* Executive summary in case the body of the oops scrolled away */
printk(KERN_EMERG "CR2: %016lx\n", address); printk(KERN_EMERG "CR2: %016lx\n", address);
oops_end(); oops_end(flags);
do_exit(SIGKILL); do_exit(SIGKILL);
/* /*
......
...@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long); ...@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long);
extern void __die(const char *,struct pt_regs *,long); extern void __die(const char *,struct pt_regs *,long);
extern void show_registers(struct pt_regs *regs); extern void show_registers(struct pt_regs *regs);
extern void dump_pagetable(unsigned long); extern void dump_pagetable(unsigned long);
extern void oops_begin(void); extern unsigned long oops_begin(void);
extern void oops_end(void); extern void oops_end(unsigned long);
#endif #endif
...@@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void); ...@@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void);
extern void swap_low_mappings(void); extern void swap_low_mappings(void);
extern void oops_begin(void);
extern void die(const char *,struct pt_regs *,long);
extern void __die(const char * str, struct pt_regs * regs, long err);
extern void __show_regs(struct pt_regs * regs); extern void __show_regs(struct pt_regs * regs);
extern void show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment