Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -132,6 +132,11 @@ SYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RWTUN, &sync_on_panic, 0, "Do a sync before rebooting from a panic"); +static int stop_scheduler_on_dump = 1; +SYSCTL_INT(_kern, OID_AUTO, stop_scheduler_on_dump, CTLFLAG_RW, + &stop_scheduler_on_dump, 0, + "Stop the scheduler if a dump is requested on reboot"); + static SYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW, 0, "Shutdown environment"); @@ -332,6 +337,32 @@ return (error); } +static void +stop_scheduler(bool stop_cpus, int *bootopt) +{ +#ifdef SMP + cpuset_t other_cpus; +#endif + + spinlock_enter(); + +#ifdef SMP + if (stop_cpus) { + other_cpus = all_cpus; + CPU_CLR(PCPU_GET(cpuid), &other_cpus); + stop_cpus_hard(other_cpus); + } + + /* + * Ensure that the scheduler is stopped while panicking, even if panic + * has been entered from kdb. + */ + curthread->td_stopsched = 1; +#endif + if (!sync_on_panic) + *bootopt |= RB_NOSYNC; +} + /* * Shutdown the system cleanly to prepare for reboot, halt, or power off. */ @@ -382,8 +413,19 @@ */ EVENTHANDLER_INVOKE(shutdown_post_sync, howto); - if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) + if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) { + /* + * Dump code assumes that all other CPUs have stopped, and thus handles + * disk interrupts manually. This assumption must be enforced, as + * otherwise the real interrupt handler may race with the dumper. + * Dumping with a running scheduler may also produce inconsistent + * dumps. + */ + if (!SCHEDULER_STOPPED() && stop_scheduler_on_dump) + stop_scheduler(true, &howto); + doadump(TRUE); + } /* Now that we're going to really halt the system... */ EVENTHANDLER_INVOKE(shutdown_final, howto); @@ -713,35 +755,18 @@ void vpanic(const char *fmt, va_list ap) { -#ifdef SMP - cpuset_t other_cpus; -#endif struct thread *td = curthread; int bootopt, newpanic; static char buf[256]; - spinlock_enter(); - -#ifdef SMP - /* - * stop_cpus_hard(other_cpus) should prevent multiple CPUs from - * concurrently entering panic. Only the winner will proceed - * further. - */ - if (panicstr == NULL && !kdb_active) { - other_cpus = all_cpus; - CPU_CLR(PCPU_GET(cpuid), &other_cpus); - stop_cpus_hard(other_cpus); - } + bootopt = RB_AUTOBOOT; /* - * Ensure that the scheduler is stopped while panicking, even if panic - * has been entered from kdb. + * stop_scheduler should prevent multiple CPUs from concurrently + * entering panic. Only the winner will proceed further. */ - td->td_stopsched = 1; -#endif + stop_scheduler(panicstr == NULL && !kdb_active, &bootopt); - bootopt = RB_AUTOBOOT; newpanic = 0; if (panicstr) bootopt |= RB_NOSYNC; @@ -774,8 +799,6 @@ /*thread_lock(td); */ td->td_flags |= TDF_INPANIC; /* thread_unlock(td); */ - if (!sync_on_panic) - bootopt |= RB_NOSYNC; kern_reboot(bootopt); }