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]",
--