kern_shutdown.c revision 47084
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
3947084Speter * $Id: kern_shutdown.c,v 1.51 1999/05/08 06:39:38 phk 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>
5241137Smsmith#include <sys/vnode.h>
5317658Sjulian#include <sys/malloc.h>
5417658Sjulian#include <sys/kernel.h>
5521776Sbde#include <sys/mount.h>
5639237Sgibbs#include <sys/queue.h>
5717658Sjulian#include <sys/sysctl.h>
5817658Sjulian#include <sys/conf.h>
5917658Sjulian#include <sys/sysproto.h>
6017658Sjulian
6117658Sjulian#include <machine/pcb.h>
6217658Sjulian#include <machine/clock.h>
6317658Sjulian#include <machine/cons.h>
6417658Sjulian#include <machine/md_var.h>
6526812Speter#ifdef SMP
6626812Speter#include <machine/smp.h>		/* smp_active, cpuid */
6726812Speter#endif
6817658Sjulian
6917658Sjulian#include <sys/signalvar.h>
7017658Sjulian
7117658Sjulian#ifndef PANIC_REBOOT_WAIT_TIME
7217658Sjulian#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
7317658Sjulian#endif
7417658Sjulian
7517658Sjulian/*
7617658Sjulian * Note that stdarg.h and the ANSI style va_start macro is used for both
7717658Sjulian * ANSI and traditional C compilers.
7817658Sjulian */
7917658Sjulian#include <machine/stdarg.h>
8017658Sjulian
8128769Sbde#ifdef DDB
8217658Sjulian#ifdef DDB_UNATTENDED
8342135Smsmithint debugger_on_panic = 0;
8417658Sjulian#else
8542135Smsmithint debugger_on_panic = 1;
8617658Sjulian#endif
8717658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
8846381Sbillf	&debugger_on_panic, 0, "Run debugger on kernel panic");
8917658Sjulian#endif
9017658Sjulian
9143436SmsmithSYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW, 0, "Shutdown environment");
9243436Smsmith
9328000Sjulian#ifdef	HW_WDOG
9417658Sjulian/*
9527997Sjulian * If there is a hardware watchdog, point this at the function needed to
9627997Sjulian * hold it off.
9727997Sjulian * It's needed when the kernel needs to do some lengthy operations.
9827997Sjulian * e.g. in wd.c when dumping core.. It's most annoying to have
9927997Sjulian * your precious core-dump only half written because the wdog kicked in.
10027997Sjulian */
10127997Sjulianwatchdog_tickle_fn wdog_tickler = NULL;
10228000Sjulian#endif	/* HW_WDOG */
10327997Sjulian
10427997Sjulian/*
10517658Sjulian * Variable panicstr contains argument to first call to panic; used as flag
10617658Sjulian * to indicate that the kernel has already called panic.
10717658Sjulian */
10817658Sjulianconst char *panicstr;
10917658Sjulian
11017658Sjulian/*
11117658Sjulian * callout list for things to do a shutdown
11217658Sjulian */
11317658Sjuliantypedef struct shutdown_list_element {
11439237Sgibbs	LIST_ENTRY(shutdown_list_element) links;
11517658Sjulian	bootlist_fn function;
11617658Sjulian	void *arg;
11740751Smsmith	int priority;
11817658Sjulian} *sle_p;
11917658Sjulian
12017768Sjulian/*
12139237Sgibbs * There are three shutdown lists. Some things need to be shut down
12239237Sgibbs * earlier than others.
12317768Sjulian */
12439237SgibbsLIST_HEAD(shutdown_list, shutdown_list_element);
12517658Sjulian
12639237Sgibbsstatic struct shutdown_list shutdown_lists[SHUTDOWN_FINAL + 1];
12739237Sgibbs
12831275Sbdestatic void boot __P((int)) __dead2;
12931275Sbdestatic void dumpsys __P((void));
13017658Sjulian
13117658Sjulian#ifndef _SYS_SYSPROTO_H_
13217658Sjulianstruct reboot_args {
13317658Sjulian	int	opt;
13417658Sjulian};
13517658Sjulian#endif
13617658Sjulian/* ARGSUSED */
13717658Sjulian
13817658Sjulian/*
13917658Sjulian * The system call that results in a reboot
14017658Sjulian */
14117658Sjulianint
14230994Sphkreboot(p, uap)
14317658Sjulian	struct proc *p;
14417658Sjulian	struct reboot_args *uap;
14517658Sjulian{
14617658Sjulian	int error;
14717658Sjulian
14846112Sphk	if ((error = suser(p)))
14917658Sjulian		return (error);
15017658Sjulian
15117658Sjulian	boot(uap->opt);
15217658Sjulian	return (0);
15317658Sjulian}
15417658Sjulian
15517658Sjulian/*
15617658Sjulian * Called by events that want to shut down.. e.g  <CTL><ALT><DEL> on a PC
15717658Sjulian */
15817658Sjulianvoid
15928769Sbdeshutdown_nice()
16017658Sjulian{
16117658Sjulian	/* Send a signal to init(8) and have it shutdown the world */
16217658Sjulian	if (initproc != NULL) {
16317658Sjulian		psignal(initproc, SIGINT);
16417658Sjulian	} else {
16517658Sjulian		/* No init(8) running, so simply reboot */
16617658Sjulian		boot(RB_NOSYNC);
16717658Sjulian	}
16817658Sjulian	return;
16917658Sjulian}
17017658Sjulianstatic int	waittime = -1;
17117658Sjulianstatic struct pcb dumppcb;
17217658Sjulian
17317658Sjulian/*
17417658Sjulian *  Go through the rigmarole of shutting down..
17517658Sjulian * this used to be in machdep.c but I'll be dammned if I could see
17617658Sjulian * anything machine dependant in it.
17717658Sjulian */
17831275Sbdestatic void
17917658Sjulianboot(howto)
18017658Sjulian	int howto;
18117658Sjulian{
18217768Sjulian	sle_p ep;
18317658Sjulian
18425164Speter#ifdef SMP
18525164Speter	if (smp_active) {
18626812Speter		printf("boot() called on cpu#%d\n", cpuid);
18725164Speter	}
18825164Speter#endif
18927997Sjulian	/*
19027997Sjulian	 * Do any callouts that should be done BEFORE syncing the filesystems.
19127997Sjulian	 */
19239237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_PRE_SYNC], links)
19317658Sjulian		(*ep->function)(howto, ep->arg);
19427997Sjulian
19527997Sjulian	/*
19627997Sjulian	 * Now sync filesystems
19727997Sjulian	 */
19817658Sjulian	if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
19917658Sjulian		register struct buf *bp;
20017658Sjulian		int iter, nbusy;
20117658Sjulian
20217658Sjulian		waittime = 0;
20317658Sjulian		printf("\nsyncing disks... ");
20417658Sjulian
20530994Sphk		sync(&proc0, NULL);
20617658Sjulian
20734266Sjulian		/*
20834266Sjulian		 * With soft updates, some buffers that are
20934266Sjulian		 * written will be remarked as dirty until other
21034266Sjulian		 * buffers are written.
21134266Sjulian		 */
21217658Sjulian		for (iter = 0; iter < 20; iter++) {
21317658Sjulian			nbusy = 0;
21417658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
21539237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
21639237Sgibbs						== B_BUSY) {
21717658Sjulian					nbusy++;
21834266Sjulian				} else if ((bp->b_flags & (B_DELWRI | B_INVAL))
21934266Sjulian						== B_DELWRI) {
22034266Sjulian					/* bawrite(bp);*/
22134266Sjulian					nbusy++;
22217658Sjulian				}
22317658Sjulian			}
22417658Sjulian			if (nbusy == 0)
22517658Sjulian				break;
22617658Sjulian			printf("%d ", nbusy);
22734266Sjulian			sync(&proc0, NULL);
22834266Sjulian			DELAY(50000 * iter);
22917658Sjulian		}
23041137Smsmith		/*
23141137Smsmith		 * Count only busy local buffers to prevent forcing
23241137Smsmith		 * a fsck if we're just a client of a wedged NFS server
23341137Smsmith		 */
23441137Smsmith		nbusy = 0;
23541137Smsmith		for (bp = &buf[nbuf]; --bp >= buf; ) {
23646568Speter			if (((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) ||
23746568Speter			    ((bp->b_flags & (B_DELWRI | B_INVAL))== B_DELWRI)) {
23841137Smsmith				if(bp->b_dev == NODEV)
23941137Smsmith					CIRCLEQ_REMOVE(&mountlist, bp->b_vp->v_mount, mnt_list);
24041137Smsmith				else
24141137Smsmith					nbusy++;
24246568Speter			}
24341137Smsmith
24441137Smsmith
24541137Smsmith		}
24617658Sjulian		if (nbusy) {
24717658Sjulian			/*
24817658Sjulian			 * Failed to sync all blocks. Indicate this and don't
24917658Sjulian			 * unmount filesystems (thus forcing an fsck on reboot).
25017658Sjulian			 */
25117658Sjulian			printf("giving up\n");
25217658Sjulian#ifdef SHOW_BUSYBUFS
25317658Sjulian			nbusy = 0;
25417658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
25539237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
25639237Sgibbs						== B_BUSY) {
25717658Sjulian					nbusy++;
25837555Sbde					printf(
25937555Sbde			"%d: dev:%08lx, flags:%08lx, blkno:%ld, lblkno:%ld\n",
26037555Sbde					    nbusy, (u_long)bp->b_dev,
26137555Sbde					    bp->b_flags, (long)bp->b_blkno,
26237555Sbde					    (long)bp->b_lblkno);
26317658Sjulian				}
26417658Sjulian			}
26517658Sjulian			DELAY(5000000);	/* 5 seconds */
26617658Sjulian#endif
26717658Sjulian		} else {
26817658Sjulian			printf("done\n");
26917658Sjulian			/*
27017658Sjulian			 * Unmount filesystems
27117658Sjulian			 */
27217658Sjulian			if (panicstr == 0)
27317658Sjulian				vfs_unmountall();
27417658Sjulian		}
27539237Sgibbs		DELAY(100000);		/* wait for console output to finish */
27617658Sjulian	}
27727997Sjulian
27827997Sjulian	/*
27927997Sjulian	 * Ok, now do things that assume all filesystem activity has
28027997Sjulian	 * been completed.
28127997Sjulian	 */
28239237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_POST_SYNC], links)
28317768Sjulian		(*ep->function)(howto, ep->arg);
28439237Sgibbs	splhigh();
28539522Sdt	if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold) {
28639237Sgibbs		savectx(&dumppcb);
28739237Sgibbs#ifdef __i386__
28839237Sgibbs		dumppcb.pcb_cr3 = rcr3();
28939237Sgibbs#endif
29039237Sgibbs		dumpsys();
29117768Sjulian	}
29239237Sgibbs
29339237Sgibbs	/* Now that we're going to really halt the system... */
29439237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_FINAL], links)
29539237Sgibbs		(*ep->function)(howto, ep->arg);
29639237Sgibbs
29717658Sjulian	if (howto & RB_HALT) {
29817658Sjulian		printf("\n");
29917658Sjulian		printf("The operating system has halted.\n");
30017658Sjulian		printf("Please press any key to reboot.\n\n");
30119274Sjulian		switch (cngetc()) {
30219274Sjulian		case -1:		/* No console, just die */
30319274Sjulian			cpu_halt();
30419274Sjulian			/* NOTREACHED */
30519274Sjulian		default:
30639237Sgibbs			howto &= ~RB_HALT;
30719274Sjulian			break;
30819274Sjulian		}
30939237Sgibbs	} else if (howto & RB_DUMP) {
31039237Sgibbs		/* System Paniced */
31117658Sjulian
31239237Sgibbs		if (PANIC_REBOOT_WAIT_TIME != 0) {
31339237Sgibbs			if (PANIC_REBOOT_WAIT_TIME != -1) {
31439237Sgibbs				int loop;
31539237Sgibbs				printf("Automatic reboot in %d seconds - "
31639237Sgibbs				       "press a key on the console to abort\n",
31739237Sgibbs					PANIC_REBOOT_WAIT_TIME);
31839237Sgibbs				for (loop = PANIC_REBOOT_WAIT_TIME * 10;
31939237Sgibbs				     loop > 0; --loop) {
32039237Sgibbs					DELAY(1000 * 100); /* 1/10th second */
32139237Sgibbs					/* Did user type a key? */
32239237Sgibbs					if (cncheckc() != -1)
32339237Sgibbs						break;
32417658Sjulian				}
32539237Sgibbs				if (!loop)
32639237Sgibbs					goto die;
32717658Sjulian			}
32839237Sgibbs		} else { /* zero time specified - reboot NOW */
32939237Sgibbs			goto die;
33017658Sjulian		}
33139237Sgibbs		printf("--> Press a key on the console to reboot <--\n");
33239237Sgibbs		cngetc();
33317658Sjulian	}
33417658Sjuliandie:
33517658Sjulian	printf("Rebooting...\n");
33617658Sjulian	DELAY(1000000);	/* wait 1 sec for printf's to complete and be read */
33717677Sjulian	/* cpu_boot(howto); */ /* doesn't do anything at the moment */
33817658Sjulian	cpu_reset();
33917658Sjulian	for(;;) ;
34017658Sjulian	/* NOTREACHED */
34117658Sjulian}
34217658Sjulian
34317658Sjulian/*
34417658Sjulian * Magic number for savecore
34517658Sjulian *
34617658Sjulian * exported (symorder) and used at least by savecore(8)
34717658Sjulian *
34817658Sjulian */
34917658Sjulianstatic u_long const	dumpmag = 0x8fca0101UL;
35017658Sjulian
35117658Sjulianstatic int	dumpsize = 0;		/* also for savecore */
35217658Sjulian
35317658Sjulianstatic int	dodump = 1;
35446381SbillfSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW,
35546381Sbillf    &dodump, 0, "Do coredump on kernel panic");
35617658Sjulian
35731403Sjulian/* ARGSUSED */
35831403Sjulianstatic void dump_conf __P((void *dummy));
35931403Sjulianstatic void
36031403Sjuliandump_conf(dummy)
36131403Sjulian	void *dummy;
36231403Sjulian{
36331403Sjulian	cpu_dumpconf();
36431403Sjulian}
36531403SjulianSYSINIT(dump_conf, SI_SUB_DUMP_CONF, SI_ORDER_FIRST, dump_conf, NULL)
36631403Sjulian
36717658Sjulian/*
36817658Sjulian * Doadump comes here after turning off memory management and
36917658Sjulian * getting on the dump stack, either when called above, or by
37017658Sjulian * the auto-restart code.
37117658Sjulian */
37217658Sjulianstatic void
37317658Sjuliandumpsys(void)
37417658Sjulian{
37517658Sjulian
37617658Sjulian	if (!dodump)
37717658Sjulian		return;
37817658Sjulian	if (dumpdev == NODEV)
37917658Sjulian		return;
38046676Sphk	if (!(bdevsw(dumpdev)))
38117658Sjulian		return;
38246676Sphk	if (!(bdevsw(dumpdev)->d_dump))
38317658Sjulian		return;
38417658Sjulian	dumpsize = Maxmem;
38547084Speter	printf("\ndumping to dev (%d,%d), offset %ld\n",
38647084Speter		major(dumpdev), minor(dumpdev), dumplo);
38717658Sjulian	printf("dump ");
38846676Sphk	switch ((*bdevsw(dumpdev)->d_dump)(dumpdev)) {
38917658Sjulian
39017658Sjulian	case ENXIO:
39117658Sjulian		printf("device bad\n");
39217658Sjulian		break;
39317658Sjulian
39417658Sjulian	case EFAULT:
39517658Sjulian		printf("device not ready\n");
39617658Sjulian		break;
39717658Sjulian
39817658Sjulian	case EINVAL:
39917658Sjulian		printf("area improper\n");
40017658Sjulian		break;
40117658Sjulian
40217658Sjulian	case EIO:
40317658Sjulian		printf("i/o error\n");
40417658Sjulian		break;
40517658Sjulian
40617658Sjulian	case EINTR:
40717658Sjulian		printf("aborted from console\n");
40817658Sjulian		break;
40917658Sjulian
41017658Sjulian	default:
41117658Sjulian		printf("succeeded\n");
41217658Sjulian		break;
41317658Sjulian	}
41417658Sjulian}
41517658Sjulian
41617658Sjulian/*
41717658Sjulian * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
41817658Sjulian * and then reboots.  If we are called twice, then we avoid trying to sync
41917658Sjulian * the disks as this often leads to recursive panics.
42017658Sjulian */
42117658Sjulianvoid
42217658Sjulianpanic(const char *fmt, ...)
42317658Sjulian{
42417658Sjulian	int bootopt;
42517658Sjulian	va_list ap;
42638874Sache	static char buf[256];
42717658Sjulian
42817658Sjulian	bootopt = RB_AUTOBOOT | RB_DUMP;
42917658Sjulian	if (panicstr)
43017658Sjulian		bootopt |= RB_NOSYNC;
43117658Sjulian	else
43217658Sjulian		panicstr = fmt;
43317658Sjulian
43417658Sjulian	va_start(ap, fmt);
43541514Sarchie	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
43638874Sache	if (panicstr == fmt)
43738874Sache		panicstr = buf;
43817658Sjulian	va_end(ap);
43938874Sache	printf("panic: %s\n", buf);
44026100Sfsmp#ifdef SMP
44129128Speter	/* three seperate prints in case of an unmapped page and trap */
44229128Speter	printf("mp_lock = %08x; ", mp_lock);
44329128Speter	printf("cpuid = %d; ", cpuid);
44429128Speter	printf("lapic.id = %08x\n", lapic.id);
44526100Sfsmp#endif
44617658Sjulian
44717658Sjulian#if defined(DDB)
44817658Sjulian	if (debugger_on_panic)
44917658Sjulian		Debugger ("panic");
45017658Sjulian#endif
45117658Sjulian	boot(bootopt);
45217658Sjulian}
45317658Sjulian
45417768Sjulian/*
45540751Smsmith * Three routines to handle adding/deleting items on the
45617768Sjulian * shutdown callout lists
45717768Sjulian *
45817768Sjulian * at_shutdown():
45917658Sjulian * Take the arguments given and put them onto the shutdown callout list.
46017658Sjulian * However first make sure that it's not already there.
46117658Sjulian * returns 0 on success.
46217658Sjulian */
46317658Sjulianint
46439237Sgibbsat_shutdown(bootlist_fn function, void *arg, int queue)
46517658Sjulian{
46640751Smsmith	return(at_shutdown_pri(function, arg, queue, SHUTDOWN_PRI_DEFAULT));
46740751Smsmith}
46817768Sjulian
46940751Smsmith/*
47040751Smsmith * at_shutdown_pri():
47140751Smsmith * Take the arguments given and put them onto the shutdown callout list
47240751Smsmith * with the given execution priority.
47340751Smsmith * returns 0 on success.
47440751Smsmith */
47540751Smsmithint
47640751Smsmithat_shutdown_pri(bootlist_fn function, void *arg, int queue, int pri)
47740751Smsmith{
47843436Smsmith	sle_p op, ep, ip;
47940751Smsmith
48039237Sgibbs	if (queue < SHUTDOWN_PRE_SYNC
48139237Sgibbs	 || queue > SHUTDOWN_FINAL) {
48239237Sgibbs		printf("at_shutdown: bad exit callout queue %d specified\n",
48339237Sgibbs		       queue);
48417768Sjulian		return (EINVAL);
48517768Sjulian	}
48617768Sjulian	if (rm_at_shutdown(function, arg))
48739237Sgibbs		printf("at_shutdown: exit callout entry was already present\n");
48817768Sjulian	ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT);
48917768Sjulian	if (ep == NULL)
49017768Sjulian		return (ENOMEM);
49117658Sjulian	ep->function = function;
49217658Sjulian	ep->arg = arg;
49340751Smsmith	ep->priority = pri;
49440751Smsmith
49540751Smsmith	/* Sort into list of items on this queue */
49640751Smsmith	ip = LIST_FIRST(&shutdown_lists[queue]);
49740751Smsmith	if (ip == NULL) {
49840751Smsmith		LIST_INSERT_HEAD(&shutdown_lists[queue], ep, links);
49940751Smsmith	} else {
50043436Smsmith		for (; ip != NULL; op = ip, ip = LIST_NEXT(ip, links)) {
50140751Smsmith			if (ep->priority < ip->priority) {
50240751Smsmith				LIST_INSERT_BEFORE(ip, ep, links);
50340751Smsmith				ep = NULL;
50440751Smsmith				break;
50540751Smsmith			}
50640751Smsmith		}
50740751Smsmith		if (ep != NULL)
50843436Smsmith			LIST_INSERT_AFTER(op, ep, links);
50940751Smsmith	}
51017768Sjulian	return (0);
51117658Sjulian}
51217768Sjulian
51317658Sjulian/*
51417768Sjulian * Scan the exit callout lists for the given items and remove them.
51517658Sjulian * Returns the number of items removed.
51617658Sjulian */
51717658Sjulianint
51817658Sjulianrm_at_shutdown(bootlist_fn function, void *arg)
51917658Sjulian{
52039237Sgibbs	sle_p ep;
52139237Sgibbs	int   count;
52239237Sgibbs	int   queue;
52317658Sjulian
52417768Sjulian	count = 0;
52539237Sgibbs	for (queue = SHUTDOWN_PRE_SYNC; queue < SHUTDOWN_FINAL; queue++) {
52639237Sgibbs		LIST_FOREACH(ep, &shutdown_lists[queue], links) {
52739237Sgibbs			if ((ep->function == function) && (ep->arg == arg)) {
52839237Sgibbs				LIST_REMOVE(ep, links);
52939237Sgibbs				free(ep, M_TEMP);
53039237Sgibbs				count++;
53139237Sgibbs			}
53217658Sjulian		}
53317658Sjulian	}
53417768Sjulian	return (count);
53517658Sjulian}
53643436Smsmith
53743436Smsmith/*
53843436Smsmith * Support for poweroff delay.
53943436Smsmith */
54043436Smsmithstatic int poweroff_delay = 0;
54143436SmsmithSYSCTL_INT(_kern_shutdown, OID_AUTO, poweroff_delay, CTLFLAG_RW,
54243436Smsmith	&poweroff_delay, 0, "");
54343436Smsmith
54443436Smsmithstatic void poweroff_wait(int howto, void *unused)
54543436Smsmith{
54643436Smsmith	if(!(howto & RB_POWEROFF) || poweroff_delay <= 0)
54743436Smsmith		return;
54843436Smsmith	DELAY(poweroff_delay * 1000);
54943436Smsmith}
55043436Smsmith
55143436Smsmith/*
55243436Smsmith * XXX OK? This implies I know SHUTDOWN_PRI_LAST > SHUTDOWN_PRI_FIRST
55343436Smsmith */
55443436Smsmithstatic void poweroff_conf(void *unused)
55543436Smsmith{
55643436Smsmith	at_shutdown_pri(poweroff_wait, NULL, SHUTDOWN_FINAL, SHUTDOWN_PRI_FIRST);
55743436Smsmith}
55843436Smsmith
55943436SmsmithSYSINIT(poweroff_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, poweroff_conf, NULL)
560