[PATCH] fix x86-64 interrupt re-enabling in oops_end()

From: Jan Beulich
Date: Thu Sep 08 2005 - 11:09:05 EST


(Note: Patch also attached because the inline version is certain to get
line wrapped.)

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@xxxxxxxxxx>

diff -Npru 2.6.13/arch/x86_64/kernel/traps.c
2.6.13-x86_64-oops-irq/arch/x86_64/kernel/traps.c
--- 2.6.13/arch/x86_64/kernel/traps.c 2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-x86_64-oops-irq/arch/x86_64/kernel/traps.c 2005-09-07
15:37:52.000000000 +0200
@@ -342,30 +342,33 @@ 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();
- /* racy, but better than risking deadlock. */
- local_irq_disable();
+ int cpu = safe_smp_processor_id();
+ unsigned long flags;
+
+ /* racy, but better than risking deadlock. */
+ local_irq_save(flags);
if (!spin_trylock(&die_lock)) {
if (cpu == die_owner)
/* nested oops. should stop eventually */;
else
- spin_lock(&die_lock);
+ spin_lock(&die_lock);
}
- die_owner = cpu;
+ die_owner = cpu;
console_verbose();
- bust_spinlocks(1);
+ 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);
+ bust_spinlocks(0);
+ spin_unlock_irqrestore(&die_lock, flags);
if (panic_on_oops)
- panic("Oops");
-}
+ panic("Oops");
+}

void __die(const char * str, struct pt_regs * regs, long err)
{
@@ -391,10 +394,11 @@ void __die(const char * str, struct pt_r

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)
@@ -405,7 +409,8 @@ static inline void die_if_kernel(const c

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.
@@ -415,7 +420,7 @@ void die_nmi(char *str, struct pt_regs *
if (panic_on_timeout || panic_on_oops)
panic("nmi watchdog");
printk("console shuts up ...\n");
- oops_end();
+ oops_end(flags);
do_exit(SIGSEGV);
}

diff -Npru 2.6.13/arch/x86_64/mm/fault.c
2.6.13-x86_64-oops-irq/arch/x86_64/mm/fault.c
--- 2.6.13/arch/x86_64/mm/fault.c 2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-x86_64-oops-irq/arch/x86_64/mm/fault.c 2005-09-07
16:15:13.000000000 +0200
@@ -220,12 +220,13 @@ int unhandled_signal(struct task_struct
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);
}

@@ -302,6 +303,7 @@ asmlinkage void do_page_fault(struct pt_
unsigned long address;
const struct exception_table_entry *fixup;
int write;
+ unsigned long flags;
siginfo_t info;

#ifdef CONFIG_CHECKING
@@ -519,7 +521,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");
@@ -532,7 +534,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);

/*
diff -Npru 2.6.13/include/asm-x86_64/kdebug.h
2.6.13-x86_64-oops-irq/include/asm-x86_64/kdebug.h
--- 2.6.13/include/asm-x86_64/kdebug.h 2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-x86_64-oops-irq/include/asm-x86_64/kdebug.h 2005-09-01
11:32:12.000000000 +0200
@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_r
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
diff -Npru 2.6.13/include/asm-x86_64/proto.h
2.6.13-x86_64-oops-irq/include/asm-x86_64/proto.h
--- 2.6.13/include/asm-x86_64/proto.h 2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-x86_64-oops-irq/include/asm-x86_64/proto.h 2005-09-01
11:32:12.000000000 +0200
@@ -75,9 +75,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);


Attachment: linux-2.6.13-x86_64-oops-irq.patch
Description: Binary data