Some more work is needed on this patch, but I'm looking for some feedback about the general direction. X86_64's implementation seems nicer and it would be useful to use a common base for further unification in the oops handling.
Modify the X86_32 implementation of die() using helpers oops_begin()/oops_end(). Small whitespace change in traps_64.c for easier comparison between the two. Signed-off-by: Harvey Harrison <[EMAIL PROTECTED]> --- arch/x86/kernel/traps_32.c | 137 +++++++++++++++++++++++--------------------- arch/x86/kernel/traps_64.c | 11 +-- 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 5f2b38e..a4092ed 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -352,10 +352,61 @@ int is_valid_bugaddr(unsigned long ip) return ud2 == 0x0b0f; } -static int die_counter; +static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; +static int die_owner = -1; +static unsigned int die_nest_count; + +unsigned long __kprobes oops_begin(void) +{ + int cpu; + unsigned long flags; + + oops_enter(); + + raw_local_irq_save(flags); + cpu = smp_processor_id(); + /* racy, but better than risking deadlock. */ + if (!__raw_spin_trylock(&die_lock) && cpu != die_owner) { + __raw_spin_lock(&die_lock); + } + die_nest_count++; + die_owner = cpu; + console_verbose(); + bust_spinlocks(1); + return flags; +} + +void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) +{ + die_owner = -1; + bust_spinlocks(0); + die_nest_count--; + if (!die_nest_count) + /* Nest count reaches zero, release the lock. */ + __raw_spin_unlock(&die_lock); + raw_local_irq_restore(flags); + + if (!regs) { + oops_exit(); + return; + } + + if (kexec_should_crash(current)) + crash_kexec(regs); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + + oops_exit(); + do_exit(signr); +} int __kprobes __die(const char * str, struct pt_regs * regs, long err) { + static int die_counter; unsigned long sp; unsigned short ss; @@ -371,24 +422,23 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err) #endif printk("\n"); - if (notify_die(DIE_OOPS, str, regs, err, - current->thread.trap_no, SIGSEGV) != - NOTIFY_STOP) { - show_registers(regs); - /* Executive summary in case the oops scrolled away */ - sp = (unsigned long) (®s->sp); - savesegment(ss, ss); - if (user_mode(regs)) { - sp = regs->sp; - ss = regs->ss & 0xffff; - } - printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); - print_symbol("%s", regs->ip); - printk(" SS:ESP %04x:%08lx\n", ss, sp); - return 0; - } else { + if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, + SIGSEGV) == NOTIFY_STOP) return 1; + + show_registers(regs); + add_taint(TAINT_DIE); + /* Executive summary in case the oops scrolled away */ + sp = (unsigned long) (®s->sp); + savesegment(ss, ss); + if (user_mode(regs)) { + sp = regs->sp; + ss = regs->ss & 0xffff; } + printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); + print_symbol("%s", regs->ip); + printk(" SS:ESP %04x:%08lx\n", ss, sp); + return 0; } /* @@ -397,58 +447,15 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err) */ void die(const char * str, struct pt_regs * regs, long err) { - static struct { - raw_spinlock_t lock; - u32 lock_owner; - int lock_owner_depth; - } die = { - .lock = __RAW_SPIN_LOCK_UNLOCKED, - .lock_owner = -1, - .lock_owner_depth = 0 - }; - unsigned long flags; + unsigned long flags = oops_begin(); - oops_enter(); - - if (die.lock_owner != raw_smp_processor_id()) { - console_verbose(); - raw_local_irq_save(flags); - __raw_spin_lock(&die.lock); - die.lock_owner = smp_processor_id(); - die.lock_owner_depth = 0; - bust_spinlocks(1); - } else - raw_local_irq_save(flags); - - if (++die.lock_owner_depth < 3) { + if (!user_mode(regs)) report_bug(regs->ip, regs); - if (__die(str, regs, err)) - regs = NULL; - } else { - printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); - } + if (__die(str, regs, err)) + regs = NULL; - bust_spinlocks(0); - die.lock_owner = -1; - add_taint(TAINT_DIE); - __raw_spin_unlock(&die.lock); - raw_local_irq_restore(flags); - - if (!regs) - return; - - if (kexec_should_crash(current)) - crash_kexec(regs); - - if (in_interrupt()) - panic("Fatal exception in interrupt"); - - if (panic_on_oops) - panic("Fatal exception"); - - oops_exit(); - do_exit(SIGSEGV); + oops_end(flags, regs, SIGSEGV); } static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index c173687..c50549e 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c @@ -465,21 +465,18 @@ static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; static int die_owner = -1; static unsigned int die_nest_count; -unsigned __kprobes long oops_begin(void) +unsigned long __kprobes oops_begin(void) { int cpu; unsigned long flags; oops_enter(); - /* racy, but better than risking deadlock. */ raw_local_irq_save(flags); cpu = smp_processor_id(); - if (!__raw_spin_trylock(&die_lock)) { - if (cpu == die_owner) - /* nested oops. should stop eventually */; - else - __raw_spin_lock(&die_lock); + /* racy, but better than risking deadlock. */ + if (!__raw_spin_trylock(&die_lock) && cpu != die_owner) { + __raw_spin_lock(&die_lock); } die_nest_count++; die_owner = cpu; -- 1.5.4.rc2.1164.g6451 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/