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 Cc: Sasha Levin Cc: Rusty Russell Cc: Greg Kroah-Hartman Reviewed-by: Dimitri Sivanich Signed-off-by: Mike Travis --- 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 #include "kdb_private.h" +#if defined(CONFIG_KEXEC) +#include +#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, "", "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, "[|A]", -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/