kern_shutdown.c revision 39237
117658Sjulian/*-
217658Sjulian * Copyright (c) 1986, 1988, 1991, 1993
317658Sjulian *	The Regents of the University of California.  All rights reserved.
417658Sjulian * (c) UNIX System Laboratories, Inc.
517658Sjulian * All or some portions of this file are derived from material licensed
617658Sjulian * to the University of California by American Telephone and Telegraph
717658Sjulian * Co. or Unix System Laboratories, Inc. and are reproduced herein with
817658Sjulian * the permission of UNIX System Laboratories, Inc.
917658Sjulian *
1017658Sjulian * Redistribution and use in source and binary forms, with or without
1117658Sjulian * modification, are permitted provided that the following conditions
1217658Sjulian * are met:
1317658Sjulian * 1. Redistributions of source code must retain the above copyright
1417658Sjulian *    notice, this list of conditions and the following disclaimer.
1517658Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1617658Sjulian *    notice, this list of conditions and the following disclaimer in the
1717658Sjulian *    documentation and/or other materials provided with the distribution.
1817658Sjulian * 3. All advertising materials mentioning features or use of this software
1917658Sjulian *    must display the following acknowledgement:
2017658Sjulian *	This product includes software developed by the University of
2117658Sjulian *	California, Berkeley and its contributors.
2217658Sjulian * 4. Neither the name of the University nor the names of its contributors
2317658Sjulian *    may be used to endorse or promote products derived from this software
2417658Sjulian *    without specific prior written permission.
2517658Sjulian *
2617658Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2717658Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2817658Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2917658Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3017658Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3117658Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3217658Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3317658Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3417658Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3517658Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3617658Sjulian * SUCH DAMAGE.
3717658Sjulian *
3817658Sjulian *	@(#)kern_shutdown.c	8.3 (Berkeley) 1/21/94
3939237Sgibbs * $Id: kern_shutdown.c,v 1.38 1998/09/06 06:25:04 ache Exp $
4017658Sjulian */
4117658Sjulian
4217658Sjulian#include "opt_ddb.h"
4333445Seivind#include "opt_hw_wdog.h"
4428976Sbde#include "opt_panic.h"
4528976Sbde#include "opt_show_busybufs.h"
4617658Sjulian
4717658Sjulian#include <sys/param.h>
4817658Sjulian#include <sys/systm.h>
4931275Sbde#include <sys/buf.h>
5017658Sjulian#include <sys/reboot.h>
5117658Sjulian#include <sys/proc.h>
5217658Sjulian#include <sys/malloc.h>
5317658Sjulian#include <sys/kernel.h>
5421776Sbde#include <sys/mount.h>
5539237Sgibbs#include <sys/queue.h>
5617658Sjulian#include <sys/sysctl.h>
5717658Sjulian#include <sys/conf.h>
5817658Sjulian#include <sys/sysproto.h>
5917658Sjulian
6017658Sjulian#include <machine/pcb.h>
6117658Sjulian#include <machine/clock.h>
6217658Sjulian#include <machine/cons.h>
6317658Sjulian#include <machine/md_var.h>
6426812Speter#ifdef SMP
6526812Speter#include <machine/smp.h>		/* smp_active, cpuid */
6626812Speter#endif
6717658Sjulian
6817658Sjulian#include <sys/signalvar.h>
6917658Sjulian
7017658Sjulian#ifndef PANIC_REBOOT_WAIT_TIME
7117658Sjulian#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
7217658Sjulian#endif
7317658Sjulian
7417658Sjulian/*
7517658Sjulian * Note that stdarg.h and the ANSI style va_start macro is used for both
7617658Sjulian * ANSI and traditional C compilers.
7717658Sjulian */
7817658Sjulian#include <machine/stdarg.h>
7917658Sjulian
8028769Sbde#ifdef DDB
8117658Sjulian#ifdef DDB_UNATTENDED
8228769Sbdestatic int debugger_on_panic = 0;
8317658Sjulian#else
8428769Sbdestatic int debugger_on_panic = 1;
8517658Sjulian#endif
8617658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
8717658Sjulian	&debugger_on_panic, 0, "");
8817658Sjulian#endif
8917658Sjulian
9028000Sjulian#ifdef	HW_WDOG
9117658Sjulian/*
9227997Sjulian * If there is a hardware watchdog, point this at the function needed to
9327997Sjulian * hold it off.
9427997Sjulian * It's needed when the kernel needs to do some lengthy operations.
9527997Sjulian * e.g. in wd.c when dumping core.. It's most annoying to have
9627997Sjulian * your precious core-dump only half written because the wdog kicked in.
9727997Sjulian */
9827997Sjulianwatchdog_tickle_fn wdog_tickler = NULL;
9928000Sjulian#endif	/* HW_WDOG */
10027997Sjulian
10127997Sjulian/*
10217658Sjulian * Variable panicstr contains argument to first call to panic; used as flag
10317658Sjulian * to indicate that the kernel has already called panic.
10417658Sjulian */
10517658Sjulianconst char *panicstr;
10617658Sjulian
10717658Sjulian/*
10817658Sjulian * callout list for things to do a shutdown
10917658Sjulian */
11017658Sjuliantypedef struct shutdown_list_element {
11139237Sgibbs	LIST_ENTRY(shutdown_list_element) links;
11217658Sjulian	bootlist_fn function;
11317658Sjulian	void *arg;
11417658Sjulian} *sle_p;
11517658Sjulian
11617768Sjulian/*
11739237Sgibbs * There are three shutdown lists. Some things need to be shut down
11839237Sgibbs * earlier than others.
11917768Sjulian */
12039237SgibbsLIST_HEAD(shutdown_list, shutdown_list_element);
12117658Sjulian
12239237Sgibbsstatic struct shutdown_list shutdown_lists[SHUTDOWN_FINAL + 1];
12339237Sgibbs
12431275Sbdestatic void boot __P((int)) __dead2;
12531275Sbdestatic void dumpsys __P((void));
12617658Sjulian
12717658Sjulian#ifndef _SYS_SYSPROTO_H_
12817658Sjulianstruct reboot_args {
12917658Sjulian	int	opt;
13017658Sjulian};
13117658Sjulian#endif
13217658Sjulian/* ARGSUSED */
13317658Sjulian
13417658Sjulian/*
13517658Sjulian * The system call that results in a reboot
13617658Sjulian */
13717658Sjulianint
13830994Sphkreboot(p, uap)
13917658Sjulian	struct proc *p;
14017658Sjulian	struct reboot_args *uap;
14117658Sjulian{
14217658Sjulian	int error;
14317658Sjulian
14417658Sjulian	if ((error = suser(p->p_ucred, &p->p_acflag)))
14517658Sjulian		return (error);
14617658Sjulian
14717658Sjulian	boot(uap->opt);
14817658Sjulian	return (0);
14917658Sjulian}
15017658Sjulian
15117658Sjulian/*
15217658Sjulian * Called by events that want to shut down.. e.g  <CTL><ALT><DEL> on a PC
15317658Sjulian */
15417658Sjulianvoid
15528769Sbdeshutdown_nice()
15617658Sjulian{
15717658Sjulian	/* Send a signal to init(8) and have it shutdown the world */
15817658Sjulian	if (initproc != NULL) {
15917658Sjulian		psignal(initproc, SIGINT);
16017658Sjulian	} else {
16117658Sjulian		/* No init(8) running, so simply reboot */
16217658Sjulian		boot(RB_NOSYNC);
16317658Sjulian	}
16417658Sjulian	return;
16517658Sjulian}
16617658Sjulianstatic int	waittime = -1;
16717658Sjulianstatic struct pcb dumppcb;
16817658Sjulian
16917658Sjulian/*
17017658Sjulian *  Go through the rigmarole of shutting down..
17117658Sjulian * this used to be in machdep.c but I'll be dammned if I could see
17217658Sjulian * anything machine dependant in it.
17317658Sjulian */
17431275Sbdestatic void
17517658Sjulianboot(howto)
17617658Sjulian	int howto;
17717658Sjulian{
17817768Sjulian	sle_p ep;
17917658Sjulian
18025164Speter#ifdef SMP
18125164Speter	if (smp_active) {
18226812Speter		printf("boot() called on cpu#%d\n", cpuid);
18325164Speter	}
18425164Speter#endif
18527997Sjulian	/*
18627997Sjulian	 * Do any callouts that should be done BEFORE syncing the filesystems.
18727997Sjulian	 */
18839237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_PRE_SYNC], links)
18917658Sjulian		(*ep->function)(howto, ep->arg);
19027997Sjulian
19127997Sjulian	/*
19227997Sjulian	 * Now sync filesystems
19327997Sjulian	 */
19417658Sjulian	if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
19517658Sjulian		register struct buf *bp;
19617658Sjulian		int iter, nbusy;
19717658Sjulian
19817658Sjulian		waittime = 0;
19917658Sjulian		printf("\nsyncing disks... ");
20017658Sjulian
20130994Sphk		sync(&proc0, NULL);
20217658Sjulian
20334266Sjulian		/*
20434266Sjulian		 * With soft updates, some buffers that are
20534266Sjulian		 * written will be remarked as dirty until other
20634266Sjulian		 * buffers are written.
20734266Sjulian		 */
20817658Sjulian		for (iter = 0; iter < 20; iter++) {
20917658Sjulian			nbusy = 0;
21017658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
21139237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
21239237Sgibbs						== B_BUSY) {
21317658Sjulian					nbusy++;
21434266Sjulian				} else if ((bp->b_flags & (B_DELWRI | B_INVAL))
21534266Sjulian						== B_DELWRI) {
21634266Sjulian					/* bawrite(bp);*/
21734266Sjulian					nbusy++;
21817658Sjulian				}
21917658Sjulian			}
22017658Sjulian			if (nbusy == 0)
22117658Sjulian				break;
22217658Sjulian			printf("%d ", nbusy);
22334266Sjulian			sync(&proc0, NULL);
22434266Sjulian			DELAY(50000 * iter);
22517658Sjulian		}
22617658Sjulian		if (nbusy) {
22717658Sjulian			/*
22817658Sjulian			 * Failed to sync all blocks. Indicate this and don't
22917658Sjulian			 * unmount filesystems (thus forcing an fsck on reboot).
23017658Sjulian			 */
23117658Sjulian			printf("giving up\n");
23217658Sjulian#ifdef SHOW_BUSYBUFS
23317658Sjulian			nbusy = 0;
23417658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
23539237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
23639237Sgibbs						== B_BUSY) {
23717658Sjulian					nbusy++;
23837555Sbde					printf(
23937555Sbde			"%d: dev:%08lx, flags:%08lx, blkno:%ld, lblkno:%ld\n",
24037555Sbde					    nbusy, (u_long)bp->b_dev,
24137555Sbde					    bp->b_flags, (long)bp->b_blkno,
24237555Sbde					    (long)bp->b_lblkno);
24317658Sjulian				}
24417658Sjulian			}
24517658Sjulian			DELAY(5000000);	/* 5 seconds */
24617658Sjulian#endif
24717658Sjulian		} else {
24817658Sjulian			printf("done\n");
24917658Sjulian			/*
25017658Sjulian			 * Unmount filesystems
25117658Sjulian			 */
25217658Sjulian			if (panicstr == 0)
25317658Sjulian				vfs_unmountall();
25417658Sjulian		}
25539237Sgibbs		DELAY(100000);		/* wait for console output to finish */
25617658Sjulian	}
25727997Sjulian
25827997Sjulian	/*
25927997Sjulian	 * Ok, now do things that assume all filesystem activity has
26027997Sjulian	 * been completed.
26127997Sjulian	 */
26239237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_POST_SYNC], links)
26317768Sjulian		(*ep->function)(howto, ep->arg);
26439237Sgibbs	splhigh();
26539237Sgibbs	if ((howto & (RB_HALT|RB_DUMP) == RB_DUMP) && !cold) {
26639237Sgibbs		savectx(&dumppcb);
26739237Sgibbs#ifdef __i386__
26839237Sgibbs		dumppcb.pcb_cr3 = rcr3();
26939237Sgibbs#endif
27039237Sgibbs		dumpsys();
27117768Sjulian	}
27239237Sgibbs
27339237Sgibbs	/* Now that we're going to really halt the system... */
27439237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_FINAL], links)
27539237Sgibbs		(*ep->function)(howto, ep->arg);
27639237Sgibbs
27717658Sjulian	if (howto & RB_HALT) {
27826657Swollman		cpu_power_down();
27917658Sjulian		printf("\n");
28017658Sjulian		printf("The operating system has halted.\n");
28117658Sjulian		printf("Please press any key to reboot.\n\n");
28219274Sjulian		switch (cngetc()) {
28319274Sjulian		case -1:		/* No console, just die */
28419274Sjulian			cpu_halt();
28519274Sjulian			/* NOTREACHED */
28619274Sjulian		default:
28739237Sgibbs			howto &= ~RB_HALT;
28819274Sjulian			break;
28919274Sjulian		}
29039237Sgibbs	} else if (howto & RB_DUMP) {
29139237Sgibbs		/* System Paniced */
29217658Sjulian
29339237Sgibbs		if (PANIC_REBOOT_WAIT_TIME != 0) {
29439237Sgibbs			if (PANIC_REBOOT_WAIT_TIME != -1) {
29539237Sgibbs				int loop;
29639237Sgibbs				printf("Automatic reboot in %d seconds - "
29739237Sgibbs				       "press a key on the console to abort\n",
29839237Sgibbs					PANIC_REBOOT_WAIT_TIME);
29939237Sgibbs				for (loop = PANIC_REBOOT_WAIT_TIME * 10;
30039237Sgibbs				     loop > 0; --loop) {
30139237Sgibbs					DELAY(1000 * 100); /* 1/10th second */
30239237Sgibbs					/* Did user type a key? */
30339237Sgibbs					if (cncheckc() != -1)
30439237Sgibbs						break;
30517658Sjulian				}
30639237Sgibbs				if (!loop)
30739237Sgibbs					goto die;
30817658Sjulian			}
30939237Sgibbs		} else { /* zero time specified - reboot NOW */
31039237Sgibbs			goto die;
31117658Sjulian		}
31239237Sgibbs		printf("--> Press a key on the console to reboot <--\n");
31339237Sgibbs		cngetc();
31417658Sjulian	}
31517658Sjuliandie:
31617658Sjulian	printf("Rebooting...\n");
31717658Sjulian	DELAY(1000000);	/* wait 1 sec for printf's to complete and be read */
31817677Sjulian	/* cpu_boot(howto); */ /* doesn't do anything at the moment */
31917658Sjulian	cpu_reset();
32017658Sjulian	for(;;) ;
32117658Sjulian	/* NOTREACHED */
32217658Sjulian}
32317658Sjulian
32417658Sjulian/*
32517658Sjulian * Magic number for savecore
32617658Sjulian *
32717658Sjulian * exported (symorder) and used at least by savecore(8)
32817658Sjulian *
32917658Sjulian */
33017658Sjulianstatic u_long const	dumpmag = 0x8fca0101UL;
33117658Sjulian
33217658Sjulianstatic int	dumpsize = 0;		/* also for savecore */
33317658Sjulian
33417658Sjulianstatic int	dodump = 1;
33517658SjulianSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, "");
33617658Sjulian
33731403Sjulian/* ARGSUSED */
33831403Sjulianstatic void dump_conf __P((void *dummy));
33931403Sjulianstatic void
34031403Sjuliandump_conf(dummy)
34131403Sjulian	void *dummy;
34231403Sjulian{
34331403Sjulian	cpu_dumpconf();
34431403Sjulian}
34531403SjulianSYSINIT(dump_conf, SI_SUB_DUMP_CONF, SI_ORDER_FIRST, dump_conf, NULL)
34631403Sjulian
34717658Sjulian/*
34817658Sjulian * Doadump comes here after turning off memory management and
34917658Sjulian * getting on the dump stack, either when called above, or by
35017658Sjulian * the auto-restart code.
35117658Sjulian */
35217658Sjulianstatic void
35317658Sjuliandumpsys(void)
35417658Sjulian{
35517658Sjulian
35617658Sjulian	if (!dodump)
35717658Sjulian		return;
35817658Sjulian	if (dumpdev == NODEV)
35917658Sjulian		return;
36017658Sjulian	if (!(bdevsw[major(dumpdev)]))
36117658Sjulian		return;
36217658Sjulian	if (!(bdevsw[major(dumpdev)]->d_dump))
36317658Sjulian		return;
36417658Sjulian	dumpsize = Maxmem;
36537555Sbde	printf("\ndumping to dev %lx, offset %ld\n", (u_long)dumpdev, dumplo);
36617658Sjulian	printf("dump ");
36717658Sjulian	switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) {
36817658Sjulian
36917658Sjulian	case ENXIO:
37017658Sjulian		printf("device bad\n");
37117658Sjulian		break;
37217658Sjulian
37317658Sjulian	case EFAULT:
37417658Sjulian		printf("device not ready\n");
37517658Sjulian		break;
37617658Sjulian
37717658Sjulian	case EINVAL:
37817658Sjulian		printf("area improper\n");
37917658Sjulian		break;
38017658Sjulian
38117658Sjulian	case EIO:
38217658Sjulian		printf("i/o error\n");
38317658Sjulian		break;
38417658Sjulian
38517658Sjulian	case EINTR:
38617658Sjulian		printf("aborted from console\n");
38717658Sjulian		break;
38817658Sjulian
38917658Sjulian	default:
39017658Sjulian		printf("succeeded\n");
39117658Sjulian		break;
39217658Sjulian	}
39317658Sjulian}
39417658Sjulian
39517658Sjulian/*
39617658Sjulian * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
39717658Sjulian * and then reboots.  If we are called twice, then we avoid trying to sync
39817658Sjulian * the disks as this often leads to recursive panics.
39917658Sjulian */
40017658Sjulianvoid
40117658Sjulianpanic(const char *fmt, ...)
40217658Sjulian{
40317658Sjulian	int bootopt;
40417658Sjulian	va_list ap;
40538874Sache	static char buf[256];
40617658Sjulian
40717658Sjulian	bootopt = RB_AUTOBOOT | RB_DUMP;
40817658Sjulian	if (panicstr)
40917658Sjulian		bootopt |= RB_NOSYNC;
41017658Sjulian	else
41117658Sjulian		panicstr = fmt;
41217658Sjulian
41317658Sjulian	va_start(ap, fmt);
41438874Sache	(void)vsprintf(buf, fmt, ap);
41538874Sache	if (panicstr == fmt)
41638874Sache		panicstr = buf;
41717658Sjulian	va_end(ap);
41838874Sache	printf("panic: %s\n", buf);
41926100Sfsmp#ifdef SMP
42029128Speter	/* three seperate prints in case of an unmapped page and trap */
42129128Speter	printf("mp_lock = %08x; ", mp_lock);
42229128Speter	printf("cpuid = %d; ", cpuid);
42329128Speter	printf("lapic.id = %08x\n", lapic.id);
42426100Sfsmp#endif
42517658Sjulian
42617658Sjulian#if defined(DDB)
42717658Sjulian	if (debugger_on_panic)
42817658Sjulian		Debugger ("panic");
42917658Sjulian#endif
43017658Sjulian	boot(bootopt);
43117658Sjulian}
43217658Sjulian
43317768Sjulian/*
43417768Sjulian * Two routines to handle adding/deleting items on the
43517768Sjulian * shutdown callout lists
43617768Sjulian *
43717768Sjulian * at_shutdown():
43817658Sjulian * Take the arguments given and put them onto the shutdown callout list.
43917658Sjulian * However first make sure that it's not already there.
44017658Sjulian * returns 0 on success.
44117658Sjulian */
44217658Sjulianint
44339237Sgibbsat_shutdown(bootlist_fn function, void *arg, int queue)
44417658Sjulian{
44539237Sgibbs	sle_p ep;
44617768Sjulian
44739237Sgibbs	if (queue < SHUTDOWN_PRE_SYNC
44839237Sgibbs	 || queue > SHUTDOWN_FINAL) {
44939237Sgibbs		printf("at_shutdown: bad exit callout queue %d specified\n",
45039237Sgibbs		       queue);
45117768Sjulian		return (EINVAL);
45217768Sjulian	}
45317768Sjulian	if (rm_at_shutdown(function, arg))
45439237Sgibbs		printf("at_shutdown: exit callout entry was already present\n");
45517768Sjulian	ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT);
45617768Sjulian	if (ep == NULL)
45717768Sjulian		return (ENOMEM);
45817658Sjulian	ep->function = function;
45917658Sjulian	ep->arg = arg;
46039237Sgibbs	LIST_INSERT_HEAD(&shutdown_lists[queue], ep, links);
46117768Sjulian	return (0);
46217658Sjulian}
46317768Sjulian
46417658Sjulian/*
46517768Sjulian * Scan the exit callout lists for the given items and remove them.
46617658Sjulian * Returns the number of items removed.
46717658Sjulian */
46817658Sjulianint
46917658Sjulianrm_at_shutdown(bootlist_fn function, void *arg)
47017658Sjulian{
47139237Sgibbs	sle_p ep;
47239237Sgibbs	int   count;
47339237Sgibbs	int   queue;
47417658Sjulian
47517768Sjulian	count = 0;
47639237Sgibbs	for (queue = SHUTDOWN_PRE_SYNC; queue < SHUTDOWN_FINAL; queue++) {
47739237Sgibbs		LIST_FOREACH(ep, &shutdown_lists[queue], links) {
47839237Sgibbs			if ((ep->function == function) && (ep->arg == arg)) {
47939237Sgibbs				LIST_REMOVE(ep, links);
48039237Sgibbs				free(ep, M_TEMP);
48139237Sgibbs				count++;
48239237Sgibbs			}
48317658Sjulian		}
48417658Sjulian	}
48517768Sjulian	return (count);
48617658Sjulian}
487