| From 891348ca0f66206f1dc0e30d63757e3df1ae2d15 Mon Sep 17 00:00:00 2001 |
| From: Robin Holt <holt@sgi.com> |
| Date: Thu, 20 Dec 2012 15:05:50 -0800 |
| Subject: SGI-XP: handle non-fatal traps |
| |
| From: Robin Holt <holt@sgi.com> |
| |
| commit 891348ca0f66206f1dc0e30d63757e3df1ae2d15 upstream. |
| |
| We found a user code which was raising a divide-by-zero trap. That trap |
| would lead to XPC connections between system-partitions being torn down |
| due to the die_chain notifier callouts it received. |
| |
| This also revealed a different issue where multiple callers into |
| xpc_die_deactivate() would all attempt to do the disconnect in parallel |
| which would sometimes lock up but often overwhelm the console on very |
| large machines as each would print at least one line of output at the |
| end of the deactivate. |
| |
| I reviewed all the users of the die_chain notifier and changed the code |
| to ignore the notifier callouts for reasons which will not actually lead |
| to a system to continue on to call die(). |
| |
| [akpm@linux-foundation.org: fix ia64] |
| Signed-off-by: Robin Holt <holt@sgi.com> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Ingo Molnar <mingo@elte.hu> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/misc/sgi-xp/xpc_main.c | 34 ++++++++++++++++++++++++++++++++-- |
| 1 file changed, 32 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/misc/sgi-xp/xpc_main.c |
| +++ b/drivers/misc/sgi-xp/xpc_main.c |
| @@ -53,6 +53,10 @@ |
| #include <linux/kthread.h> |
| #include "xpc.h" |
| |
| +#ifdef CONFIG_X86_64 |
| +#include <asm/traps.h> |
| +#endif |
| + |
| /* define two XPC debug device structures to be used with dev_dbg() et al */ |
| |
| struct device_driver xpc_dbg_name = { |
| @@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block |
| return NOTIFY_DONE; |
| } |
| |
| +/* Used to only allow one cpu to complete disconnect */ |
| +static unsigned int xpc_die_disconnecting; |
| + |
| /* |
| * Notify other partitions to deactivate from us by first disengaging from all |
| * references to our memory. |
| @@ -1092,6 +1099,9 @@ xpc_die_deactivate(void) |
| long keep_waiting; |
| long wait_to_print; |
| |
| + if (cmpxchg(&xpc_die_disconnecting, 0, 1)) |
| + return; |
| + |
| /* keep xpc_hb_checker thread from doing anything (just in case) */ |
| xpc_exiting = 1; |
| |
| @@ -1159,7 +1169,7 @@ xpc_die_deactivate(void) |
| * about the lack of a heartbeat. |
| */ |
| static int |
| -xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) |
| +xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args) |
| { |
| #ifdef CONFIG_IA64 /* !!! temporary kludge */ |
| switch (event) { |
| @@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb |
| break; |
| } |
| #else |
| - xpc_die_deactivate(); |
| + struct die_args *die_args = _die_args; |
| + |
| + switch (event) { |
| + case DIE_TRAP: |
| + if (die_args->trapnr == X86_TRAP_DF) |
| + xpc_die_deactivate(); |
| + |
| + if (((die_args->trapnr == X86_TRAP_MF) || |
| + (die_args->trapnr == X86_TRAP_XF)) && |
| + !user_mode_vm(die_args->regs)) |
| + xpc_die_deactivate(); |
| + |
| + break; |
| + case DIE_INT3: |
| + case DIE_DEBUG: |
| + break; |
| + case DIE_OOPS: |
| + case DIE_GPF: |
| + default: |
| + xpc_die_deactivate(); |
| + } |
| #endif |
| |
| return NOTIFY_DONE; |