summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-04-08 21:31:10 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-04-08 21:31:10 -0700
commit7b78878b47141bb38c217d3d354adb24eb499e34 (patch)
tree52f8b9a730e5e32c1377e26805aba6030b3a437d
parent2040ae819d46e22444db8cb92d01e298a9ca3b51 (diff)
[PATCH] Allow panics and reboots at oops time.
From: Russell Miller <rmiller@duskglow.com> A BUG or an oops will often leave a machine in a useless state. There is no way to remotely recover the machine from that state. The patch adds a /proc/sys/kernel/panic_on_oops sysctl which, when set, will cause the x86 kernel to call panic() at the end of the oops handler. If the user has also set /proc/sys/kernel/panic then a reboot will occur. The implementation will try to sleep for a while before panicing so the oops info has a chance of hitting the logs. The implementation is designed so that other architectures can easily do this in their oops handlers.
-rw-r--r--Documentation/sysctl/kernel.txt12
-rw-r--r--arch/i386/kernel/traps.c9
-rw-r--r--include/linux/kernel.h1
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--kernel/panic.c7
-rw-r--r--kernel/sysctl.c2
6 files changed, 28 insertions, 4 deletions
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index e6f061d1a2f7..74d52720ade6 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -204,6 +204,18 @@ software watchdog, the recommended setting is 60.
==============================================================
+panic_on_oops:
+
+Controls the kernel's behaviour when an oops or BUG is encountered.
+
+0: try to continue operation
+
+1: delay a few seconds (to give klogd time to record the oops output) and
+ then panic. If the `panic' sysctl is also non-zero then the machine will
+ be rebooted.
+
+==============================================================
+
pid_max:
PID allocation wrap value. When the kenrel's next PID value
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 79aa129a6bc4..53c610ea831c 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -257,6 +257,15 @@ void die(const char * str, struct pt_regs * regs, long err)
show_registers(regs);
bust_spinlocks(0);
spin_unlock_irq(&die_lock);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops) {
+ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(5 * HZ);
+ panic("Fatal exception");
+ }
do_exit(SIGSEGV);
}
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index f7f83f129d9f..94d476e7d80f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -104,6 +104,7 @@ static inline void console_verbose(void)
extern void bust_spinlocks(int yes);
extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */
+extern int panic_on_oops;
extern int tainted;
extern const char *print_tainted(void);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 29a5f877d0f3..f6a32a5dc496 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -129,6 +129,7 @@ enum
KERN_CADPID=54, /* int: PID of the process to notify on CAD */
KERN_PIDMAX=55, /* int: PID # limit */
KERN_CORE_PATTERN=56, /* string: pattern for core-file names */
+ KERN_PANIC_ON_OOPS=57, /* int: whether we will panic on an oops */
};
diff --git a/kernel/panic.c b/kernel/panic.c
index 4f4e36663617..66a22b5d9c77 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -20,6 +20,8 @@
asmlinkage void sys_sync(void); /* it's really int */
int panic_timeout;
+int panic_on_oops;
+int tainted;
struct notifier_block *panic_notifier_list;
@@ -28,7 +30,6 @@ static int __init panic_setup(char *str)
panic_timeout = simple_strtoul(str, NULL, 0);
return 1;
}
-
__setup("panic=", panic_setup);
/**
@@ -51,7 +52,7 @@ NORET_TYPE void panic(const char * fmt, ...)
bust_spinlocks(1);
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
printk(KERN_EMERG "Kernel panic: %s\n",buf);
if (in_interrupt())
@@ -123,5 +124,3 @@ const char *print_tainted()
snprintf(buf, sizeof(buf), "Not tainted");
return(buf);
}
-
-int tainted = 0;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 27cd5c65124f..21381e2efa18 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -263,6 +263,8 @@ static ctl_table kern_table[] = {
#endif
{KERN_PIDMAX, "pid_max", &pid_max, sizeof (int),
0600, NULL, &proc_dointvec},
+ {KERN_PANIC_ON_OOPS,"panic_on_oops",
+ &panic_on_oops,sizeof(int),0644,NULL,&proc_dointvec},
{0}
};