[patch] delay panic during startup of kernel

From: Michael Sundius
Date: Wed Oct 21 2009 - 19:38:37 EST


We've been, from time to time, running into various problems early on
the initialization of the kernel, encountering situations where we really
should panic, but we can't because its too early to do so.
(see * if you care to know why this is a problem for us). Anyhow, I've
created this patch to have a little better way of orderly finishing the
bring-up to the point where we can panic safely. Any comments?


*One reason this often happens to us is that we have added hooks
for our drivers to allocate contiguous blocks of memory very early and
our driver team doesn't always communicate when changes have been
made.

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index f4e3184..b2e7bac 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -163,6 +163,10 @@ extern struct atomic_notifier_head panic_notifier_list;
extern long (*panic_blink)(long time);
NORET_TYPE void panic(const char * fmt, ...)
__attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
+extern void panic_later(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+extern void panic_later_complete(void);
+extern bool panic_later_pending(void);
extern void oops_enter(void);
extern void oops_exit(void);
extern int oops_may_print(void);
diff --git a/init/main.c b/init/main.c
index 5988deb..2a9347a 100644
--- a/init/main.c
+++ b/init/main.c
@@ -185,7 +185,6 @@ __setup("reset_devices", set_reset_devices);

static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
-static const char *panic_later, *panic_param;

extern struct obs_kernel_param __setup_start[], __setup_end[];

@@ -281,7 +280,7 @@ static int __init unknown_bootoption(char *param, char *val)
return 0;
}

- if (panic_later)
+ if (panic_later_pending())
return 0;

if (val) {
@@ -289,8 +288,7 @@ static int __init unknown_bootoption(char *param, char *val)
unsigned int i;
for (i = 0; envp_init[i]; i++) {
if (i == MAX_INIT_ENVS) {
- panic_later = "Too many boot env vars at `%s'";
- panic_param = param;
+ panic_later("Too many boot env vars at `%s'", param);
}
if (!strncmp(param, envp_init[i], val - param))
break;
@@ -301,8 +299,7 @@ static int __init unknown_bootoption(char *param, char *val)
unsigned int i;
for (i = 0; argv_init[i]; i++) {
if (i == MAX_INIT_ARGS) {
- panic_later = "Too many boot init vars at `%s'";
- panic_param = param;
+ panic_later("Too many boot init vars at `%s'", param);
}
}
argv_init[i] = param;
@@ -621,8 +618,7 @@ asmlinkage void __init start_kernel(void)
* this. But we do want output early, in case something goes wrong.
*/
console_init();
- if (panic_later)
- panic(panic_later, panic_param);
+ panic_later_complete();

lockdep_info();

diff --git a/kernel/panic.c b/kernel/panic.c
index 96b45d0..092bb46 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -23,6 +23,9 @@
#include <linux/nmi.h>
#include <linux/dmi.h>

+#define MAX_PANIC_LATER_LEN 1024
+static char panic_later_msg[MAX_PANIC_LATER_LEN];
+
int panic_on_oops;
static unsigned long tainted_mask;
static int pause_on_oops;
@@ -40,6 +43,28 @@ static long no_blink(long time)
return 0;
}

+void panic_later(const char *fmt, ...)
+{
+ va_list args;
+
+ if (!panic_later_pending()) {
+ va_start(args, fmt);
+ vsnprintf(panic_later_msg, sizeof(panic_later_msg), fmt, args);
+ va_end(args);
+ }
+}
+
+bool panic_later_pending()
+{
+ return panic_later_msg[0] != 0;
+}
+
+void panic_later_complete()
+{
+ if (panic_later_pending())
+ panic("%s", panic_later_msg);
+}
+
/* Returns how long it waited in ms */
long (*panic_blink)(long time);
EXPORT_SYMBOL(panic_blink);
--
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/