[RFC] x86: Add oops_begin, oops_end to X86_32

From: Harvey Harrison
Date: Tue Jan 08 2008 - 22:34:49 EST


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 <harvey.harrison@xxxxxxxxx>
---
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) (&regs->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) (&regs->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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/