Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+21 −16
Original line number Diff line number Diff line
@@ -343,11 +343,13 @@ void out_of_line_bug(void)
static DEFINE_SPINLOCK(die_lock);
static int die_owner = -1;

void oops_begin(void)
unsigned long oops_begin(void)
{
	int cpu = safe_smp_processor_id();
	unsigned long flags;

	/* racy, but better than risking deadlock. */
	local_irq_disable();
	local_irq_save(flags);
	if (!spin_trylock(&die_lock)) { 
		if (cpu == die_owner) 
			/* nested oops. should stop eventually */;
@@ -357,13 +359,14 @@ void oops_begin(void)
	die_owner = cpu;
	console_verbose();
	bust_spinlocks(1);
	return flags;
}

void oops_end(void)
void oops_end(unsigned long flags)
{ 
	die_owner = -1;
	bust_spinlocks(0);
	spin_unlock(&die_lock); 
	spin_unlock_irqrestore(&die_lock, flags);
	if (panic_on_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)
{
	oops_begin();
	unsigned long flags = oops_begin();

	handle_BUG(regs);
	__die(str, regs, err);
	oops_end();
	oops_end(flags);
	do_exit(SIGSEGV); 
}
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)
{
	oops_begin();
	unsigned long flags = oops_begin();

	/*
	 * We are in trouble anyway, lets at least try
	 * 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)
		panic("nmi watchdog");
	printk("console shuts up ...\n");
	oops_end();
	oops_end(flags);
	do_exit(SIGSEGV);
}

+6 −4
Original line number Diff line number Diff line
@@ -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,
				 unsigned long error_code)
{
	oops_begin();
	unsigned long flags = oops_begin();

	printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
	       current->comm, address);
	dump_pagetable(address);
	__die("Bad pagetable", regs, error_code);
	oops_end();
	oops_end(flags);
	do_exit(SIGKILL);
}

@@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
	unsigned long address;
	const struct exception_table_entry *fixup;
	int write;
	unsigned long flags;
	siginfo_t info;

#ifdef CONFIG_CHECKING
@@ -521,7 +523,7 @@ no_context:
 * terminate things with extreme prejudice.
 */

	oops_begin(); 
	flags = oops_begin();

	if (address < PAGE_SIZE)
		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
@@ -534,7 +536,7 @@ no_context:
	__die("Oops", regs, error_code);
	/* Executive summary in case the body of the oops scrolled away */
	printk(KERN_EMERG "CR2: %016lx\n", address);
	oops_end(); 
	oops_end(flags);
	do_exit(SIGKILL);

/*
+2 −2
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ 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 dump_pagetable(unsigned long);
extern void oops_begin(void);
extern void oops_end(void);
extern unsigned long oops_begin(void);
extern void oops_end(unsigned long);

#endif
+0 −3
Original line number Diff line number Diff line
@@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(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);