Skip to content

Commit

Permalink
SGI-XP: handle non-fatal traps
Browse files Browse the repository at this point in the history
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().

[[email protected]: fix ia64]
Signed-off-by: Robin Holt <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Robin Holt authored and torvalds committed Dec 21, 2012
1 parent c39540c commit 891348c
Showing 1 changed file with 32 additions and 2 deletions.
34 changes: 32 additions & 2 deletions drivers/misc/sgi-xp/xpc_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
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.
Expand All @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
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;
Expand Down

0 comments on commit 891348c

Please sign in to comment.