[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>
This commit is contained in:
committed by
Linus Torvalds
parent
059bf0f6c3
commit
1209140c3c
@@ -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)
|
|||||||
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)
|
|||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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:
|
|||||||
* 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:
|
|||||||
__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);
|
|||||||
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);
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user