kern_shutdown.c revision 41514
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
3941514Sarchie * $Id: kern_shutdown.c,v 1.42 1998/11/13 22:40:37 msmith 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
8328769Sbdestatic int debugger_on_panic = 0;
8417658Sjulian#else
8528769Sbdestatic int debugger_on_panic = 1;
8617658Sjulian#endif
8717658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
8817658Sjulian	&debugger_on_panic, 0, "");
8917658Sjulian#endif
9017658Sjulian
9128000Sjulian#ifdef	HW_WDOG
9217658Sjulian/*
9327997Sjulian * If there is a hardware watchdog, point this at the function needed to
9427997Sjulian * hold it off.
9527997Sjulian * It's needed when the kernel needs to do some lengthy operations.
9627997Sjulian * e.g. in wd.c when dumping core.. It's most annoying to have
9727997Sjulian * your precious core-dump only half written because the wdog kicked in.
9827997Sjulian */
9927997Sjulianwatchdog_tickle_fn wdog_tickler = NULL;
10028000Sjulian#endif	/* HW_WDOG */
10127997Sjulian
10227997Sjulian/*
10317658Sjulian * Variable panicstr contains argument to first call to panic; used as flag
10417658Sjulian * to indicate that the kernel has already called panic.
10517658Sjulian */
10617658Sjulianconst char *panicstr;
10717658Sjulian
10817658Sjulian/*
10917658Sjulian * callout list for things to do a shutdown
11017658Sjulian */
11117658Sjuliantypedef struct shutdown_list_element {
11239237Sgibbs	LIST_ENTRY(shutdown_list_element) links;
11317658Sjulian	bootlist_fn function;
11417658Sjulian	void *arg;
11540751Smsmith	int priority;
11617658Sjulian} *sle_p;
11717658Sjulian
11817768Sjulian/*
11939237Sgibbs * There are three shutdown lists. Some things need to be shut down
12039237Sgibbs * earlier than others.
12117768Sjulian */
12239237SgibbsLIST_HEAD(shutdown_list, shutdown_list_element);
12317658Sjulian
12439237Sgibbsstatic struct shutdown_list shutdown_lists[SHUTDOWN_FINAL + 1];
12539237Sgibbs
12631275Sbdestatic void boot __P((int)) __dead2;
12731275Sbdestatic void dumpsys __P((void));
12817658Sjulian
12917658Sjulian#ifndef _SYS_SYSPROTO_H_
13017658Sjulianstruct reboot_args {
13117658Sjulian	int	opt;
13217658Sjulian};
13317658Sjulian#endif
13417658Sjulian/* ARGSUSED */
13517658Sjulian
13617658Sjulian/*
13717658Sjulian * The system call that results in a reboot
13817658Sjulian */
13917658Sjulianint
14030994Sphkreboot(p, uap)
14117658Sjulian	struct proc *p;
14217658Sjulian	struct reboot_args *uap;
14317658Sjulian{
14417658Sjulian	int error;
14517658Sjulian
14617658Sjulian	if ((error = suser(p->p_ucred, &p->p_acflag)))
14717658Sjulian		return (error);
14817658Sjulian
14917658Sjulian	boot(uap->opt);
15017658Sjulian	return (0);
15117658Sjulian}
15217658Sjulian
15317658Sjulian/*
15417658Sjulian * Called by events that want to shut down.. e.g  <CTL><ALT><DEL> on a PC
15517658Sjulian */
15617658Sjulianvoid
15728769Sbdeshutdown_nice()
15817658Sjulian{
15917658Sjulian	/* Send a signal to init(8) and have it shutdown the world */
16017658Sjulian	if (initproc != NULL) {
16117658Sjulian		psignal(initproc, SIGINT);
16217658Sjulian	} else {
16317658Sjulian		/* No init(8) running, so simply reboot */
16417658Sjulian		boot(RB_NOSYNC);
16517658Sjulian	}
16617658Sjulian	return;
16717658Sjulian}
16817658Sjulianstatic int	waittime = -1;
16917658Sjulianstatic struct pcb dumppcb;
17017658Sjulian
17117658Sjulian/*
17217658Sjulian *  Go through the rigmarole of shutting down..
17317658Sjulian * this used to be in machdep.c but I'll be dammned if I could see
17417658Sjulian * anything machine dependant in it.
17517658Sjulian */
17631275Sbdestatic void
17717658Sjulianboot(howto)
17817658Sjulian	int howto;
17917658Sjulian{
18017768Sjulian	sle_p ep;
18117658Sjulian
18225164Speter#ifdef SMP
18325164Speter	if (smp_active) {
18426812Speter		printf("boot() called on cpu#%d\n", cpuid);
18525164Speter	}
18625164Speter#endif
18727997Sjulian	/*
18827997Sjulian	 * Do any callouts that should be done BEFORE syncing the filesystems.
18927997Sjulian	 */
19039237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_PRE_SYNC], links)
19117658Sjulian		(*ep->function)(howto, ep->arg);
19227997Sjulian
19327997Sjulian	/*
19427997Sjulian	 * Now sync filesystems
19527997Sjulian	 */
19617658Sjulian	if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
19717658Sjulian		register struct buf *bp;
19817658Sjulian		int iter, nbusy;
19917658Sjulian
20017658Sjulian		waittime = 0;
20117658Sjulian		printf("\nsyncing disks... ");
20217658Sjulian
20330994Sphk		sync(&proc0, NULL);
20417658Sjulian
20534266Sjulian		/*
20634266Sjulian		 * With soft updates, some buffers that are
20734266Sjulian		 * written will be remarked as dirty until other
20834266Sjulian		 * buffers are written.
20934266Sjulian		 */
21017658Sjulian		for (iter = 0; iter < 20; iter++) {
21117658Sjulian			nbusy = 0;
21217658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
21339237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
21439237Sgibbs						== B_BUSY) {
21517658Sjulian					nbusy++;
21634266Sjulian				} else if ((bp->b_flags & (B_DELWRI | B_INVAL))
21734266Sjulian						== B_DELWRI) {
21834266Sjulian					/* bawrite(bp);*/
21934266Sjulian					nbusy++;
22017658Sjulian				}
22117658Sjulian			}
22217658Sjulian			if (nbusy == 0)
22317658Sjulian				break;
22417658Sjulian			printf("%d ", nbusy);
22534266Sjulian			sync(&proc0, NULL);
22634266Sjulian			DELAY(50000 * iter);
22717658Sjulian		}
22841137Smsmith		/*
22941137Smsmith		 * Count only busy local buffers to prevent forcing
23041137Smsmith		 * a fsck if we're just a client of a wedged NFS server
23141137Smsmith		 */
23241137Smsmith		nbusy = 0;
23341137Smsmith		for (bp = &buf[nbuf]; --bp >= buf; ) {
23441137Smsmith			if (((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY)
23541137Smsmith			    ||((bp->b_flags & (B_DELWRI | B_INVAL))== B_DELWRI))
23641137Smsmith				if(bp->b_dev == NODEV)
23741137Smsmith					CIRCLEQ_REMOVE(&mountlist, bp->b_vp->v_mount, mnt_list);
23841137Smsmith				else
23941137Smsmith					nbusy++;
24041137Smsmith
24141137Smsmith
24241137Smsmith		}
24317658Sjulian		if (nbusy) {
24417658Sjulian			/*
24517658Sjulian			 * Failed to sync all blocks. Indicate this and don't
24617658Sjulian			 * unmount filesystems (thus forcing an fsck on reboot).
24717658Sjulian			 */
24817658Sjulian			printf("giving up\n");
24917658Sjulian#ifdef SHOW_BUSYBUFS
25017658Sjulian			nbusy = 0;
25117658Sjulian			for (bp = &buf[nbuf]; --bp >= buf; ) {
25239237Sgibbs				if ((bp->b_flags & (B_BUSY | B_INVAL))
25339237Sgibbs						== B_BUSY) {
25417658Sjulian					nbusy++;
25537555Sbde					printf(
25637555Sbde			"%d: dev:%08lx, flags:%08lx, blkno:%ld, lblkno:%ld\n",
25737555Sbde					    nbusy, (u_long)bp->b_dev,
25837555Sbde					    bp->b_flags, (long)bp->b_blkno,
25937555Sbde					    (long)bp->b_lblkno);
26017658Sjulian				}
26117658Sjulian			}
26217658Sjulian			DELAY(5000000);	/* 5 seconds */
26317658Sjulian#endif
26417658Sjulian		} else {
26517658Sjulian			printf("done\n");
26617658Sjulian			/*
26717658Sjulian			 * Unmount filesystems
26817658Sjulian			 */
26917658Sjulian			if (panicstr == 0)
27017658Sjulian				vfs_unmountall();
27117658Sjulian		}
27239237Sgibbs		DELAY(100000);		/* wait for console output to finish */
27317658Sjulian	}
27427997Sjulian
27527997Sjulian	/*
27627997Sjulian	 * Ok, now do things that assume all filesystem activity has
27727997Sjulian	 * been completed.
27827997Sjulian	 */
27939237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_POST_SYNC], links)
28017768Sjulian		(*ep->function)(howto, ep->arg);
28139237Sgibbs	splhigh();
28239522Sdt	if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold) {
28339237Sgibbs		savectx(&dumppcb);
28439237Sgibbs#ifdef __i386__
28539237Sgibbs		dumppcb.pcb_cr3 = rcr3();
28639237Sgibbs#endif
28739237Sgibbs		dumpsys();
28817768Sjulian	}
28939237Sgibbs
29039237Sgibbs	/* Now that we're going to really halt the system... */
29139237Sgibbs	LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_FINAL], links)
29239237Sgibbs		(*ep->function)(howto, ep->arg);
29339237Sgibbs
29417658Sjulian	if (howto & RB_HALT) {
29517658Sjulian		printf("\n");
29617658Sjulian		printf("The operating system has halted.\n");
29717658Sjulian		printf("Please press any key to reboot.\n\n");
29819274Sjulian		switch (cngetc()) {
29919274Sjulian		case -1:		/* No console, just die */
30019274Sjulian			cpu_halt();
30119274Sjulian			/* NOTREACHED */
30219274Sjulian		default:
30339237Sgibbs			howto &= ~RB_HALT;
30419274Sjulian			break;
30519274Sjulian		}
30639237Sgibbs	} else if (howto & RB_DUMP) {
30739237Sgibbs		/* System Paniced */
30817658Sjulian
30939237Sgibbs		if (PANIC_REBOOT_WAIT_TIME != 0) {
31039237Sgibbs			if (PANIC_REBOOT_WAIT_TIME != -1) {
31139237Sgibbs				int loop;
31239237Sgibbs				printf("Automatic reboot in %d seconds - "
31339237Sgibbs				       "press a key on the console to abort\n",
31439237Sgibbs					PANIC_REBOOT_WAIT_TIME);
31539237Sgibbs				for (loop = PANIC_REBOOT_WAIT_TIME * 10;
31639237Sgibbs				     loop > 0; --loop) {
31739237Sgibbs					DELAY(1000 * 100); /* 1/10th second */
31839237Sgibbs					/* Did user type a key? */
31939237Sgibbs					if (cncheckc() != -1)
32039237Sgibbs						break;
32117658Sjulian				}
32239237Sgibbs				if (!loop)
32339237Sgibbs					goto die;
32417658Sjulian			}
32539237Sgibbs		} else { /* zero time specified - reboot NOW */
32639237Sgibbs			goto die;
32717658Sjulian		}
32839237Sgibbs		printf("--> Press a key on the console to reboot <--\n");
32939237Sgibbs		cngetc();
33017658Sjulian	}
33117658Sjuliandie:
33217658Sjulian	printf("Rebooting...\n");
33317658Sjulian	DELAY(1000000);	/* wait 1 sec for printf's to complete and be read */
33417677Sjulian	/* cpu_boot(howto); */ /* doesn't do anything at the moment */
33517658Sjulian	cpu_reset();
33617658Sjulian	for(;;) ;
33717658Sjulian	/* NOTREACHED */
33817658Sjulian}
33917658Sjulian
34017658Sjulian/*
34117658Sjulian * Magic number for savecore
34217658Sjulian *
34317658Sjulian * exported (symorder) and used at least by savecore(8)
34417658Sjulian *
34517658Sjulian */
34617658Sjulianstatic u_long const	dumpmag = 0x8fca0101UL;
34717658Sjulian
34817658Sjulianstatic int	dumpsize = 0;		/* also for savecore */
34917658Sjulian
35017658Sjulianstatic int	dodump = 1;
35117658SjulianSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, "");
35217658Sjulian
35331403Sjulian/* ARGSUSED */
35431403Sjulianstatic void dump_conf __P((void *dummy));
35531403Sjulianstatic void
35631403Sjuliandump_conf(dummy)
35731403Sjulian	void *dummy;
35831403Sjulian{
35931403Sjulian	cpu_dumpconf();
36031403Sjulian}
36131403SjulianSYSINIT(dump_conf, SI_SUB_DUMP_CONF, SI_ORDER_FIRST, dump_conf, NULL)
36231403Sjulian
36317658Sjulian/*
36417658Sjulian * Doadump comes here after turning off memory management and
36517658Sjulian * getting on the dump stack, either when called above, or by
36617658Sjulian * the auto-restart code.
36717658Sjulian */
36817658Sjulianstatic void
36917658Sjuliandumpsys(void)
37017658Sjulian{
37117658Sjulian
37217658Sjulian	if (!dodump)
37317658Sjulian		return;
37417658Sjulian	if (dumpdev == NODEV)
37517658Sjulian		return;
37617658Sjulian	if (!(bdevsw[major(dumpdev)]))
37717658Sjulian		return;
37817658Sjulian	if (!(bdevsw[major(dumpdev)]->d_dump))
37917658Sjulian		return;
38017658Sjulian	dumpsize = Maxmem;
38137555Sbde	printf("\ndumping to dev %lx, offset %ld\n", (u_long)dumpdev, dumplo);
38217658Sjulian	printf("dump ");
38317658Sjulian	switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) {
38417658Sjulian
38517658Sjulian	case ENXIO:
38617658Sjulian		printf("device bad\n");
38717658Sjulian		break;
38817658Sjulian
38917658Sjulian	case EFAULT:
39017658Sjulian		printf("device not ready\n");
39117658Sjulian		break;
39217658Sjulian
39317658Sjulian	case EINVAL:
39417658Sjulian		printf("area improper\n");
39517658Sjulian		break;
39617658Sjulian
39717658Sjulian	case EIO:
39817658Sjulian		printf("i/o error\n");
39917658Sjulian		break;
40017658Sjulian
40117658Sjulian	case EINTR:
40217658Sjulian		printf("aborted from console\n");
40317658Sjulian		break;
40417658Sjulian
40517658Sjulian	default:
40617658Sjulian		printf("succeeded\n");
40717658Sjulian		break;
40817658Sjulian	}
40917658Sjulian}
41017658Sjulian
41117658Sjulian/*
41217658Sjulian * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
41317658Sjulian * and then reboots.  If we are called twice, then we avoid trying to sync
41417658Sjulian * the disks as this often leads to recursive panics.
41517658Sjulian */
41617658Sjulianvoid
41717658Sjulianpanic(const char *fmt, ...)
41817658Sjulian{
41917658Sjulian	int bootopt;
42017658Sjulian	va_list ap;
42138874Sache	static char buf[256];
42217658Sjulian
42317658Sjulian	bootopt = RB_AUTOBOOT | RB_DUMP;
42417658Sjulian	if (panicstr)
42517658Sjulian		bootopt |= RB_NOSYNC;
42617658Sjulian	else
42717658Sjulian		panicstr = fmt;
42817658Sjulian
42917658Sjulian	va_start(ap, fmt);
43041514Sarchie	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
43138874Sache	if (panicstr == fmt)
43238874Sache		panicstr = buf;
43317658Sjulian	va_end(ap);
43438874Sache	printf("panic: %s\n", buf);
43526100Sfsmp#ifdef SMP
43629128Speter	/* three seperate prints in case of an unmapped page and trap */
43729128Speter	printf("mp_lock = %08x; ", mp_lock);
43829128Speter	printf("cpuid = %d; ", cpuid);
43929128Speter	printf("lapic.id = %08x\n", lapic.id);
44026100Sfsmp#endif
44117658Sjulian
44217658Sjulian#if defined(DDB)
44317658Sjulian	if (debugger_on_panic)
44417658Sjulian		Debugger ("panic");
44517658Sjulian#endif
44617658Sjulian	boot(bootopt);
44717658Sjulian}
44817658Sjulian
44917768Sjulian/*
45040751Smsmith * Three routines to handle adding/deleting items on the
45117768Sjulian * shutdown callout lists
45217768Sjulian *
45317768Sjulian * at_shutdown():
45417658Sjulian * Take the arguments given and put them onto the shutdown callout list.
45517658Sjulian * However first make sure that it's not already there.
45617658Sjulian * returns 0 on success.
45717658Sjulian */
45817658Sjulianint
45939237Sgibbsat_shutdown(bootlist_fn function, void *arg, int queue)
46017658Sjulian{
46140751Smsmith	return(at_shutdown_pri(function, arg, queue, SHUTDOWN_PRI_DEFAULT));
46240751Smsmith}
46317768Sjulian
46440751Smsmith/*
46540751Smsmith * at_shutdown_pri():
46640751Smsmith * Take the arguments given and put them onto the shutdown callout list
46740751Smsmith * with the given execution priority.
46840751Smsmith * returns 0 on success.
46940751Smsmith */
47040751Smsmithint
47140751Smsmithat_shutdown_pri(bootlist_fn function, void *arg, int queue, int pri)
47240751Smsmith{
47340751Smsmith	sle_p ep, ip;
47440751Smsmith
47539237Sgibbs	if (queue < SHUTDOWN_PRE_SYNC
47639237Sgibbs	 || queue > SHUTDOWN_FINAL) {
47739237Sgibbs		printf("at_shutdown: bad exit callout queue %d specified\n",
47839237Sgibbs		       queue);
47917768Sjulian		return (EINVAL);
48017768Sjulian	}
48117768Sjulian	if (rm_at_shutdown(function, arg))
48239237Sgibbs		printf("at_shutdown: exit callout entry was already present\n");
48317768Sjulian	ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT);
48417768Sjulian	if (ep == NULL)
48517768Sjulian		return (ENOMEM);
48617658Sjulian	ep->function = function;
48717658Sjulian	ep->arg = arg;
48840751Smsmith	ep->priority = pri;
48940751Smsmith
49040751Smsmith	/* Sort into list of items on this queue */
49140751Smsmith	ip = LIST_FIRST(&shutdown_lists[queue]);
49240751Smsmith	if (ip == NULL) {
49340751Smsmith		LIST_INSERT_HEAD(&shutdown_lists[queue], ep, links);
49440751Smsmith	} else {
49540751Smsmith		for (; LIST_NEXT(ip, links) != NULL; ip = LIST_NEXT(ip, links)) {
49640751Smsmith			if (ep->priority < ip->priority) {
49740751Smsmith				LIST_INSERT_BEFORE(ip, ep, links);
49840751Smsmith				ep = NULL;
49940751Smsmith				break;
50040751Smsmith			}
50140751Smsmith		}
50240751Smsmith		if (ep != NULL)
50340751Smsmith			LIST_INSERT_AFTER(ip, ep, links);
50440751Smsmith	}
50517768Sjulian	return (0);
50617658Sjulian}
50717768Sjulian
50817658Sjulian/*
50917768Sjulian * Scan the exit callout lists for the given items and remove them.
51017658Sjulian * Returns the number of items removed.
51117658Sjulian */
51217658Sjulianint
51317658Sjulianrm_at_shutdown(bootlist_fn function, void *arg)
51417658Sjulian{
51539237Sgibbs	sle_p ep;
51639237Sgibbs	int   count;
51739237Sgibbs	int   queue;
51817658Sjulian
51917768Sjulian	count = 0;
52039237Sgibbs	for (queue = SHUTDOWN_PRE_SYNC; queue < SHUTDOWN_FINAL; queue++) {
52139237Sgibbs		LIST_FOREACH(ep, &shutdown_lists[queue], links) {
52239237Sgibbs			if ((ep->function == function) && (ep->arg == arg)) {
52339237Sgibbs				LIST_REMOVE(ep, links);
52439237Sgibbs				free(ep, M_TEMP);
52539237Sgibbs				count++;
52639237Sgibbs			}
52717658Sjulian		}
52817658Sjulian	}
52917768Sjulian	return (count);
53017658Sjulian}
531