2013-03-12 19:42:08

by Mike Travis

[permalink] [raw]
Subject: [PATCH 08/14] KDB: Restore call to kdump from KDB

This patch restores the capability of calling kdump from inside
KDB. First it returns to the original CPU that KDB was called
by, and also verifies that the crash_kexec kernel has been loaded.
Both are better than just using the 'sr c' option and possibly
hanging the system.

Cc: Anton Vorontsov <[email protected]>
Cc: Sasha Levin <[email protected]>
Cc: Rusty Russell <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Reviewed-by: Dimitri Sivanich <[email protected]>
Signed-off-by: Mike Travis <[email protected]>
---
include/linux/kdb.h | 7 +++
kernel/debug/kdb/kdb_main.c | 79 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)

--- linux.orig/include/linux/kdb.h
+++ linux/include/linux/kdb.h
@@ -144,6 +144,13 @@ static inline const char *kdb_walk_kalls
}
#endif /* ! CONFIG_KALLSYMS */

+#if defined(CONFIG_KEXEC)
+enum {
+ KDB_KDUMP_RESET,
+ KDB_KDUMP_KDUMP,
+};
+#endif
+
/* Dynamic kdb shell command registration */
extern int kdb_register(char *, kdb_func_t, char *, char *, short);
extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
--- linux.orig/kernel/debug/kdb/kdb_main.c
+++ linux/kernel/debug/kdb/kdb_main.c
@@ -42,6 +42,10 @@
#include <linux/slab.h>
#include "kdb_private.h"

+#if defined(CONFIG_KEXEC)
+#include <linux/kexec.h>
+#endif
+
/*
* Kernel debugger state flags
*/
@@ -1052,6 +1056,73 @@ void kdb_set_current_task(struct task_st
}
EXPORT_SYMBOL(kdb_set_current_task);

+#if defined(CONFIG_KEXEC)
+
+static int kdb_kdump_state = KDB_KDUMP_RESET; /* KDB kdump state */
+
+static int kdb_cpu(int argc, const char **argv);
+
+/*
+ * kdb_kdump_check
+ *
+ * This is where the kdump on monarch cpu is handled.
+ *
+ */
+void kdb_kdump_check(struct pt_regs *regs)
+{
+ if (kdb_kdump_state != KDB_KDUMP_RESET) {
+ crash_kexec(regs);
+
+ /*
+ * If the call above returned then something didn't work
+ */
+ kdb_printf("kdb_kdump_check: crash_kexec failed!\n");
+ kdb_printf
+ ("Please check if the kdump kernel has been properly loaded\n");
+ kdb_kdump_state = KDB_KDUMP_RESET;
+ }
+}
+
+
+/*
+ * kdb_kdump
+ * This function implements the 'kdump' command.
+ *
+ * Returns:
+ * zero for success, a kdb diagnostic if error
+ */
+
+static int
+kdb_kdump(int argc, const char **argv)
+{
+ char cpu_id[8];
+ const char *cpu_argv[] = {NULL, cpu_id, NULL};
+ int ret = KDB_CMD_CPU;
+
+ if (!kexec_crash_image) {
+ kdb_printf("kdump error: crash kernel not loaded\n");
+ return KDB_NOTFOUND;
+ }
+
+ kdb_kdump_state = KDB_KDUMP_KDUMP;
+
+ /* Switch back to the initial cpu before process kdump command */
+ if (smp_processor_id() != kdb_initial_cpu) {
+ scnprintf(cpu_id, sizeof(cpu_id), "%d", kdb_initial_cpu);
+ ret = kdb_cpu(1, cpu_argv);
+ if (ret != KDB_CMD_CPU) {
+ kdb_printf
+ ("kdump: Failed to switch to initial cpu %d; aborted\n",
+ kdb_initial_cpu);
+ kdb_kdump_state = KDB_KDUMP_RESET;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_KEXEC */
+
/*
* kdb_local - The main code for kdb. This routine is invoked on a
* specific processor, it is not global. The main kdb() routine
@@ -1079,6 +1150,10 @@ static int kdb_local(kdb_reason_t reason
struct task_struct *kdb_current =
kdb_curr_task(raw_smp_processor_id());

+#if defined(CONFIG_KEXEC)
+ kdb_kdump_check(regs);
+#endif
+
KDB_DEBUG_STATE("kdb_local 1", reason);
kdb_go_count = 0;
if (reason == KDB_REASON_DEBUG) {
@@ -2726,6 +2801,10 @@ static void __init kdb_inittab(void)
"Display Help Message", 0, KDB_REPEAT_NONE);
kdb_register_repeat("cpu", kdb_cpu, "<cpunum>",
"Switch to new cpu", 0, KDB_REPEAT_NONE);
+#if defined(CONFIG_KEXEC)
+ kdb_register_repeat("kdump", kdb_kdump, "",
+ "Enter kdump crash kexec", 0, KDB_REPEAT_NONE);
+#endif
kdb_register_repeat("kgdb", kdb_kgdb, "",
"Enter kgdb mode", 0, KDB_REPEAT_NONE);
kdb_register_repeat("ps", kdb_ps, "[<flags>|A]",

--