kern_shutdown.c revision 150472
119304Speter/*-
219304Speter * Copyright (c) 1986, 1988, 1991, 1993
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * (c) UNIX System Laboratories, Inc.
519304Speter * All or some portions of this file are derived from material licensed
619304Speter * to the University of California by American Telephone and Telegraph
719304Speter * Co. or Unix System Laboratories, Inc. and are reproduced herein with
819304Speter * the permission of UNIX System Laboratories, Inc.
919304Speter *
1019304Speter * Redistribution and use in source and binary forms, with or without
1119304Speter * modification, are permitted provided that the following conditions
1219304Speter * are met:
13254225Speter * 1. Redistributions of source code must retain the above copyright
1419304Speter *    notice, this list of conditions and the following disclaimer.
1519304Speter * 2. Redistributions in binary form must reproduce the above copyright
1619304Speter *    notice, this list of conditions and the following disclaimer in the
1719304Speter *    documentation and/or other materials provided with the distribution.
1819304Speter * 4. Neither the name of the University nor the names of its contributors
1919304Speter *    may be used to endorse or promote products derived from this software
2019304Speter *    without specific prior written permission.
2119304Speter *
2219304Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2319304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2419304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2519304Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2619304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2719304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2819304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2919304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3019304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3119304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3219304Speter * SUCH DAMAGE.
3319304Speter *
3419304Speter *	@(#)kern_shutdown.c	8.3 (Berkeley) 1/21/94
3519304Speter */
3619304Speter
3719304Speter#include <sys/cdefs.h>
3819304Speter__FBSDID("$FreeBSD: head/sys/kern/kern_shutdown.c 150472 2005-09-22 15:34:15Z ups $");
3919304Speter
4019304Speter#include "opt_kdb.h"
4119304Speter#include "opt_mac.h"
4219304Speter#include "opt_panic.h"
4319304Speter#include "opt_show_busybufs.h"
4419304Speter#include "opt_sched.h"
4519304Speter
4619304Speter#include <sys/param.h>
4719304Speter#include <sys/systm.h>
4819304Speter#include <sys/bio.h>
4919304Speter#include <sys/buf.h>
5019304Speter#include <sys/conf.h>
5119304Speter#include <sys/cons.h>
5219304Speter#include <sys/eventhandler.h>
5319304Speter#include <sys/kdb.h>
5419304Speter#include <sys/kernel.h>
5519304Speter#include <sys/kthread.h>
5619304Speter#include <sys/mac.h>
5719304Speter#include <sys/malloc.h>
5819304Speter#include <sys/mount.h>
5919304Speter#include <sys/proc.h>
6019304Speter#include <sys/reboot.h>
6119304Speter#include <sys/resourcevar.h>
6219304Speter#include <sys/sched.h>
6319304Speter#include <sys/smp.h>		/* smp_active */
6419304Speter#include <sys/sysctl.h>
6519304Speter#include <sys/sysproto.h>
6619304Speter
6719304Speter#include <machine/cpu.h>
6819304Speter#include <machine/pcb.h>
6919304Speter#include <machine/smp.h>
7019304Speter
7119304Speter#include <sys/signalvar.h>
7219304Speter
7319304Speter#ifndef PANIC_REBOOT_WAIT_TIME
7419304Speter#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
7519304Speter#endif
7619304Speter
7719304Speter/*
7819304Speter * Note that stdarg.h and the ANSI style va_start macro is used for both
7919304Speter * ANSI and traditional C compilers.
80254225Speter */
8119304Speter#include <machine/stdarg.h>
8219304Speter
8319304Speter#ifdef KDB
8419304Speter#ifdef KDB_UNATTENDED
8519304Speterint debugger_on_panic = 0;
8619304Speter#else
8719304Speterint debugger_on_panic = 1;
8819304Speter#endif
8919304SpeterSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
9019304Speter	&debugger_on_panic, 0, "Run debugger on kernel panic");
9119304Speter
92254225Speter#ifdef KDB_TRACE
9319304Speterint trace_on_panic = 1;
9419304Speter#else
9519304Speterint trace_on_panic = 0;
9619304Speter#endif
9719304SpeterSYSCTL_INT(_debug, OID_AUTO, trace_on_panic, CTLFLAG_RW,
9819304Speter	&trace_on_panic, 0, "Print stack trace on kernel panic");
9919304Speter#endif /* KDB */
10019304Speter
10119304Speterint sync_on_panic = 0;
102254225SpeterSYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RW,
10319304Speter	&sync_on_panic, 0, "Do a sync before rebooting from a panic");
10419304Speter
10519304SpeterSYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW, 0, "Shutdown environment");
10619304Speter
10719304Speter/*
10819304Speter * Variable panicstr contains argument to first call to panic; used as flag
10919304Speter * to indicate that the kernel has already called panic.
11019304Speter */
11119304Speterconst char *panicstr;
11219304Speter
11319304Speterint dumping;				/* system is dumping */
11419304Speterstatic struct dumperinfo dumper;	/* our selected dumper */
11519304Speter
11619304Speter/* Context information for dump-debuggers. */
11719304Speterstatic struct pcb dumppcb;		/* Registers. */
11819304Speterstatic lwpid_t dumptid;			/* Thread ID. */
11919304Speter
12019304Speterstatic void boot(int) __dead2;
121254225Speterstatic void poweroff_wait(void *, int);
12219304Speterstatic void shutdown_halt(void *junk, int howto);
12319304Speterstatic void shutdown_panic(void *junk, int howto);
12419304Speterstatic void shutdown_reset(void *junk, int howto);
12519304Speter
12619304Speter/* register various local shutdown events */
12719304Speterstatic void
12819304Spetershutdown_conf(void *unused)
12919304Speter{
13019304Speter
13119304Speter	EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL,
13219304Speter	    SHUTDOWN_PRI_FIRST);
13319304Speter	EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL,
13419304Speter	    SHUTDOWN_PRI_LAST + 100);
13519304Speter	EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL,
13619304Speter	    SHUTDOWN_PRI_LAST + 100);
13719304Speter	EVENTHANDLER_REGISTER(shutdown_final, shutdown_reset, NULL,
13819304Speter	    SHUTDOWN_PRI_LAST + 200);
13919304Speter}
14019304Speter
14119304SpeterSYSINIT(shutdown_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, shutdown_conf, NULL)
14219304Speter
14319304Speter/*
14419304Speter * The system call that results in a reboot
14519304Speter *
14619304Speter * MPSAFE
14719304Speter */
14819304Speter/* ARGSUSED */
149254225Speterint
15019304Speterreboot(struct thread *td, struct reboot_args *uap)
15119304Speter{
15219304Speter	int error;
15319304Speter
15419304Speter	error = 0;
15519304Speter#ifdef MAC
15619304Speter	error = mac_check_system_reboot(td->td_ucred, uap->opt);
15719304Speter#endif
15819304Speter	if (error == 0)
15919304Speter		error = suser(td);
16019304Speter	if (error == 0) {
16119304Speter		mtx_lock(&Giant);
16219304Speter		boot(uap->opt);
16319304Speter		mtx_unlock(&Giant);
16419304Speter	}
16519304Speter	return (error);
16619304Speter}
16719304Speter
16819304Speter/*
16919304Speter * Called by events that want to shut down.. e.g  <CTL><ALT><DEL> on a PC
17019304Speter */
17119304Speterstatic int shutdown_howto = 0;
17219304Speter
17319304Spetervoid
17419304Spetershutdown_nice(int howto)
17519304Speter{
17619304Speter
17719304Speter	shutdown_howto = howto;
17819304Speter
17919304Speter	/* Send a signal to init(8) and have it shutdown the world */
18019304Speter	if (initproc != NULL) {
181254225Speter		PROC_LOCK(initproc);
18219304Speter		psignal(initproc, SIGINT);
18319304Speter		PROC_UNLOCK(initproc);
18419304Speter	} else {
18519304Speter		/* No init(8) running, so simply reboot */
18619304Speter		boot(RB_NOSYNC);
18719304Speter	}
18819304Speter	return;
18919304Speter}
19019304Speterstatic int	waittime = -1;
19119304Speter
19219304Speterstatic void
19319304Speterprint_uptime(void)
19419304Speter{
19519304Speter	int f;
19619304Speter	struct timespec ts;
19719304Speter
19819304Speter	getnanouptime(&ts);
19919304Speter	printf("Uptime: ");
200254225Speter	f = 0;
20119304Speter	if (ts.tv_sec >= 86400) {
20219304Speter		printf("%ldd", (long)ts.tv_sec / 86400);
20319304Speter		ts.tv_sec %= 86400;
20419304Speter		f = 1;
20519304Speter	}
20619304Speter	if (f || ts.tv_sec >= 3600) {
20719304Speter		printf("%ldh", (long)ts.tv_sec / 3600);
20819304Speter		ts.tv_sec %= 3600;
20919304Speter		f = 1;
21019304Speter	}
21119304Speter	if (f || ts.tv_sec >= 60) {
21219304Speter		printf("%ldm", (long)ts.tv_sec / 60);
21319304Speter		ts.tv_sec %= 60;
21419304Speter		f = 1;
21519304Speter	}
21619304Speter	printf("%lds\n", (long)ts.tv_sec);
21719304Speter}
21819304Speter
21919304Speterstatic void
22019304Speterdoadump(void)
22119304Speter{
22219304Speter
22319304Speter	/*
22419304Speter	 * Sometimes people have to call this from the kernel debugger.
22519304Speter	 * (if 'panic' can not dump)
22619304Speter	 * Give them a clue as to why they can't dump.
22719304Speter	 */
22819304Speter	if (dumper.dumper == NULL) {
22919304Speter		printf("Cannot dump. No dump device defined.\n");
23019304Speter		return;
23119304Speter	}
23219304Speter
23319304Speter	savectx(&dumppcb);
23419304Speter	dumptid = curthread->td_tid;
23519304Speter	dumping++;
23619304Speter	dumpsys(&dumper);
23719304Speter}
23819304Speter
23919304Speterstatic int
240254225Speterisbufbusy(struct buf *bp)
24119304Speter{
24219304Speter	if (((bp->b_flags & (B_INVAL | B_PERSISTENT)) == 0 &&
24319304Speter	    BUF_REFCNT(bp) > 0) ||
24419304Speter	    ((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI))
24519304Speter		return (1);
24619304Speter	return (0);
24719304Speter}
24819304Speter
24919304Speter/*
25019304Speter * Shutdown the system cleanly to prepare for reboot, halt, or power off.
25119304Speter */
252254225Speterstatic void
25319304Speterboot(int howto)
25419304Speter{
25519304Speter	static int first_buf_printf = 1;
25619304Speter
25719304Speter#if defined(SMP)
25819304Speter	/*
25919304Speter	 * Bind us to CPU 0 so that all shutdown code runs there.  Some
26019304Speter	 * systems don't shutdown properly (i.e., ACPI power off) if we
26119304Speter	 * run on another processor.
262254225Speter	 */
26319304Speter	mtx_lock_spin(&sched_lock);
26419304Speter	sched_bind(curthread, 0);
26519304Speter	mtx_unlock_spin(&sched_lock);
26619304Speter	KASSERT(PCPU_GET(cpuid) == 0, ("boot: not running on cpu 0"));
26719304Speter#endif
26819304Speter
26919304Speter	/* collect extra flags that shutdown_nice might have set */
27019304Speter	howto |= shutdown_howto;
27119304Speter
27219304Speter	/* We are out of the debugger now. */
27319304Speter	kdb_active = 0;
27419304Speter
27519304Speter	/*
27619304Speter	 * Do any callouts that should be done BEFORE syncing the filesystems.
27719304Speter	 */
27819304Speter	EVENTHANDLER_INVOKE(shutdown_pre_sync, howto);
27919304Speter
280254225Speter	/*
28119304Speter	 * Now sync filesystems
28219304Speter	 */
283254225Speter	if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
28419304Speter		register struct buf *bp;
28519304Speter		int iter, nbusy, pbusy;
28619304Speter#ifndef PREEMPTION
28719304Speter		int subiter;
28819304Speter#endif
28919304Speter
29019304Speter		waittime = 0;
29119304Speter
29219304Speter		sync(curthread, NULL);
29319304Speter
29419304Speter		/*
29519304Speter		 * With soft updates, some buffers that are
29619304Speter		 * written will be remarked as dirty until other
29719304Speter		 * buffers are written.
29819304Speter		 */
29919304Speter		for (iter = pbusy = 0; iter < 20; iter++) {
30019304Speter			nbusy = 0;
30119304Speter			for (bp = &buf[nbuf]; --bp >= buf; )
302254225Speter				if (isbufbusy(bp))
30319304Speter					nbusy++;
30419304Speter			if (nbusy == 0) {
30519304Speter				if (first_buf_printf)
30619304Speter					printf("All buffers synced.");
30719304Speter				break;
30819304Speter			}
30919304Speter			if (first_buf_printf) {
31019304Speter				printf("Syncing disks, buffers remaining... ");
31119304Speter				first_buf_printf = 0;
31219304Speter			}
31319304Speter			printf("%d ", nbusy);
31419304Speter			if (nbusy < pbusy)
31519304Speter				iter = 0;
31619304Speter			pbusy = nbusy;
31719304Speter			sync(curthread, NULL);
31819304Speter
31919304Speter#ifdef PREEMPTION
32019304Speter			/*
32119304Speter			 * Drop Giant and spin for a while to allow
32219304Speter			 * interrupt threads to run.
32319304Speter			 */
32419304Speter			DROP_GIANT();
32519304Speter			DELAY(50000 * iter);
32619304Speter			PICKUP_GIANT();
32719304Speter#else
32819304Speter			/*
32919304Speter			 * Drop Giant and context switch several times to
33019304Speter			 * allow interrupt threads to run.
331254225Speter			 */
33219304Speter			DROP_GIANT();
33319304Speter			for (subiter = 0; subiter < 50 * iter; subiter++) {
33419304Speter				mtx_lock_spin(&sched_lock);
33519304Speter				mi_switch(SW_VOL, NULL);
33619304Speter				mtx_unlock_spin(&sched_lock);
33719304Speter				DELAY(1000);
33819304Speter			}
33919304Speter			PICKUP_GIANT();
34019304Speter#endif
34119304Speter		}
34219304Speter		printf("\n");
34319304Speter		/*
34419304Speter		 * Count only busy local buffers to prevent forcing
34519304Speter		 * a fsck if we're just a client of a wedged NFS server
34619304Speter		 */
34719304Speter		nbusy = 0;
348254225Speter		for (bp = &buf[nbuf]; --bp >= buf; ) {
34919304Speter			if (isbufbusy(bp)) {
35019304Speter#if 0
35119304Speter/* XXX: This is bogus.  We should probably have a BO_REMOTE flag instead */
35219304Speter				if (bp->b_dev == NULL) {
35319304Speter					TAILQ_REMOVE(&mountlist,
35419304Speter					    bp->b_vp->v_mount, mnt_list);
35519304Speter					continue;
35619304Speter				}
35719304Speter#endif
35819304Speter				nbusy++;
35919304Speter#if defined(SHOW_BUSYBUFS) || defined(DIAGNOSTIC)
36019304Speter				printf(
36119304Speter			    "%d: bufobj:%p, flags:%0x, blkno:%ld, lblkno:%ld\n",
36219304Speter				    nbusy, bp->b_bufobj,
36319304Speter				    bp->b_flags, (long)bp->b_blkno,
36419304Speter				    (long)bp->b_lblkno);
36519304Speter#endif
36619304Speter			}
36719304Speter		}
36819304Speter		if (nbusy) {
36919304Speter			/*
37019304Speter			 * Failed to sync all blocks. Indicate this and don't
37119304Speter			 * unmount filesystems (thus forcing an fsck on reboot).
37219304Speter			 */
37319304Speter			printf("Giving up on %d buffers\n", nbusy);
37419304Speter			DELAY(5000000);	/* 5 seconds */
37519304Speter		} else {
37619304Speter			if (!first_buf_printf)
37719304Speter				printf("Final sync complete\n");
37819304Speter			/*
37919304Speter			 * Unmount filesystems
38019304Speter			 */
38119304Speter			if (panicstr == 0)
38219304Speter				vfs_unmountall();
38319304Speter		}
38419304Speter		DELAY(100000);		/* wait for console output to finish */
38519304Speter	}
386254225Speter
38719304Speter	print_uptime();
38819304Speter
38919304Speter	/*
39019304Speter	 * Ok, now do things that assume all filesystem activity has
39119304Speter	 * been completed.
39219304Speter	 */
39319304Speter	EVENTHANDLER_INVOKE(shutdown_post_sync, howto);
39419304Speter
39519304Speter	/* XXX This doesn't disable interrupts any more.  Reconsider? */
39619304Speter	splhigh();
39719304Speter
398254225Speter	if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping)
39919304Speter		doadump();
40019304Speter
40119304Speter	/* Now that we're going to really halt the system... */
40219304Speter	EVENTHANDLER_INVOKE(shutdown_final, howto);
40319304Speter
40419304Speter	for(;;) ;	/* safety against shutdown_reset not working */
40519304Speter	/* NOTREACHED */
40619304Speter}
40719304Speter
408254225Speter/*
40919304Speter * If the shutdown was a clean halt, behave accordingly.
41019304Speter */
41119304Speterstatic void
41219304Spetershutdown_halt(void *junk, int howto)
41319304Speter{
41419304Speter
41519304Speter	if (howto & RB_HALT) {
41619304Speter		printf("\n");
41719304Speter		printf("The operating system has halted.\n");
41819304Speter		printf("Please press any key to reboot.\n\n");
41919304Speter		switch (cngetc()) {
42019304Speter		case -1:		/* No console, just die */
42119304Speter			cpu_halt();
42219304Speter			/* NOTREACHED */
42319304Speter		default:
42419304Speter			howto &= ~RB_HALT;
42519304Speter			break;
42619304Speter		}
427254225Speter	}
42819304Speter}
42919304Speter
430254225Speter/*
43119304Speter * Check to see if the system paniced, pause and then reboot
43219304Speter * according to the specified delay.
43319304Speter */
43419304Speterstatic void
43519304Spetershutdown_panic(void *junk, int howto)
43619304Speter{
43719304Speter	int loop;
43819304Speter
43919304Speter	if (howto & RB_DUMP) {
44019304Speter		if (PANIC_REBOOT_WAIT_TIME != 0) {
44119304Speter			if (PANIC_REBOOT_WAIT_TIME != -1) {
44219304Speter				printf("Automatic reboot in %d seconds - "
44319304Speter				       "press a key on the console to abort\n",
44419304Speter					PANIC_REBOOT_WAIT_TIME);
44519304Speter				for (loop = PANIC_REBOOT_WAIT_TIME * 10;
44619304Speter				     loop > 0; --loop) {
44719304Speter					DELAY(1000 * 100); /* 1/10th second */
44819304Speter					/* Did user type a key? */
449254225Speter					if (cncheckc() != -1)
45019304Speter						break;
45119304Speter				}
45219304Speter				if (!loop)
45319304Speter					return;
45419304Speter			}
45519304Speter		} else { /* zero time specified - reboot NOW */
45619304Speter			return;
45719304Speter		}
45819304Speter		printf("--> Press a key on the console to reboot,\n");
45919304Speter		printf("--> or switch off the system now.\n");
46019304Speter		cngetc();
46119304Speter	}
46219304Speter}
46319304Speter
46419304Speter/*
46519304Speter * Everything done, now reset
46619304Speter */
46719304Speterstatic void
46819304Spetershutdown_reset(void *junk, int howto)
46919304Speter{
47019304Speter
47119304Speter	printf("Rebooting...\n");
47219304Speter	DELAY(1000000);	/* wait 1 sec for printf's to complete and be read */
47319304Speter	/* cpu_boot(howto); */ /* doesn't do anything at the moment */
47419304Speter	cpu_reset();
47519304Speter	/* NOTREACHED */ /* assuming reset worked */
47619304Speter}
47719304Speter
478254225Speter#ifdef SMP
47919304Speterstatic u_int panic_cpu = NOCPU;
48019304Speter#endif
48119304Speter
48219304Speter/*
48319304Speter * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
48419304Speter * and then reboots.  If we are called twice, then we avoid trying to sync
48519304Speter * the disks as this often leads to recursive panics.
48619304Speter *
48719304Speter * MPSAFE
48819304Speter */
48919304Spetervoid
49019304Speterpanic(const char *fmt, ...)
49119304Speter{
49219304Speter	struct thread *td = curthread;
49319304Speter	int bootopt, newpanic;
49419304Speter	va_list ap;
495254225Speter	static char buf[256];
49619304Speter
49719304Speter#ifdef SMP
49819304Speter	/*
49919304Speter	 * We don't want multiple CPU's to panic at the same time, so we
50019304Speter	 * use panic_cpu as a simple spinlock.  We have to keep checking
50119304Speter	 * panic_cpu if we are spinning in case the panic on the first
50219304Speter	 * CPU is canceled.
50319304Speter	 */
50419304Speter	if (panic_cpu != PCPU_GET(cpuid))
50519304Speter		while (atomic_cmpset_int(&panic_cpu, NOCPU,
50619304Speter		    PCPU_GET(cpuid)) == 0)
50719304Speter			while (panic_cpu != NOCPU)
50819304Speter				; /* nothing */
50919304Speter#endif
51019304Speter
51119304Speter	bootopt = RB_AUTOBOOT | RB_DUMP;
51219304Speter	newpanic = 0;
51319304Speter	if (panicstr)
51419304Speter		bootopt |= RB_NOSYNC;
51519304Speter	else {
51619304Speter		panicstr = fmt;
51719304Speter		newpanic = 1;
51819304Speter	}
51919304Speter
52019304Speter	va_start(ap, fmt);
52119304Speter	if (newpanic) {
52219304Speter		(void)vsnprintf(buf, sizeof(buf), fmt, ap);
52319304Speter		panicstr = buf;
52419304Speter		printf("panic: %s\n", buf);
52519304Speter	} else {
52619304Speter		printf("panic: ");
527		vprintf(fmt, ap);
528		printf("\n");
529	}
530	va_end(ap);
531#ifdef SMP
532	printf("cpuid = %d\n", PCPU_GET(cpuid));
533#endif
534
535#ifdef KDB
536	if (newpanic && trace_on_panic)
537		kdb_backtrace();
538	if (debugger_on_panic)
539		kdb_enter("panic");
540#ifdef RESTARTABLE_PANICS
541	/* See if the user aborted the panic, in which case we continue. */
542	if (panicstr == NULL) {
543#ifdef SMP
544		atomic_store_rel_int(&panic_cpu, NOCPU);
545#endif
546		return;
547	}
548#endif
549#endif
550	mtx_lock_spin(&sched_lock);
551	td->td_flags |= TDF_INPANIC;
552	mtx_unlock_spin(&sched_lock);
553	if (!sync_on_panic)
554		bootopt |= RB_NOSYNC;
555	boot(bootopt);
556}
557
558/*
559 * Support for poweroff delay.
560 */
561#ifndef POWEROFF_DELAY
562# define POWEROFF_DELAY 5000
563#endif
564static int poweroff_delay = POWEROFF_DELAY;
565
566SYSCTL_INT(_kern_shutdown, OID_AUTO, poweroff_delay, CTLFLAG_RW,
567	&poweroff_delay, 0, "");
568
569static void
570poweroff_wait(void *junk, int howto)
571{
572
573	if (!(howto & RB_POWEROFF) || poweroff_delay <= 0)
574		return;
575	DELAY(poweroff_delay * 1000);
576}
577
578/*
579 * Some system processes (e.g. syncer) need to be stopped at appropriate
580 * points in their main loops prior to a system shutdown, so that they
581 * won't interfere with the shutdown process (e.g. by holding a disk buf
582 * to cause sync to fail).  For each of these system processes, register
583 * shutdown_kproc() as a handler for one of shutdown events.
584 */
585static int kproc_shutdown_wait = 60;
586SYSCTL_INT(_kern_shutdown, OID_AUTO, kproc_shutdown_wait, CTLFLAG_RW,
587    &kproc_shutdown_wait, 0, "");
588
589void
590kproc_shutdown(void *arg, int howto)
591{
592	struct proc *p;
593	char procname[MAXCOMLEN + 1];
594	int error;
595
596	if (panicstr)
597		return;
598
599	p = (struct proc *)arg;
600	strlcpy(procname, p->p_comm, sizeof(procname));
601	printf("Waiting (max %d seconds) for system process `%s' to stop...",
602	    kproc_shutdown_wait, procname);
603	error = kthread_suspend(p, kproc_shutdown_wait * hz);
604
605	if (error == EWOULDBLOCK)
606		printf("timed out\n");
607	else
608		printf("done\n");
609}
610
611/* Registration of dumpers */
612int
613set_dumper(struct dumperinfo *di)
614{
615
616	if (di == NULL) {
617		bzero(&dumper, sizeof dumper);
618		return (0);
619	}
620	if (dumper.dumper != NULL)
621		return (EBUSY);
622	dumper = *di;
623	return (0);
624}
625
626#if defined(__powerpc__)
627void
628dumpsys(struct dumperinfo *di __unused)
629{
630
631	printf("Kernel dumps not implemented on this architecture\n");
632}
633#endif
634