kern_shutdown.c revision 28976
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 3928976Sbde * $Id: kern_shutdown.c,v 1.21 1997/08/26 18:36:15 peter Exp $ 4017658Sjulian */ 4117658Sjulian 4217658Sjulian#include "opt_ddb.h" 4328976Sbde#include "opt_panic.h" 4428976Sbde#include "opt_show_busybufs.h" 4517658Sjulian 4617658Sjulian#include <sys/param.h> 4717658Sjulian#include <sys/systm.h> 4817658Sjulian#include <sys/reboot.h> 4917658Sjulian#include <sys/msgbuf.h> 5017658Sjulian#include <sys/proc.h> 5117658Sjulian#include <sys/vnode.h> 5217658Sjulian#include <sys/tty.h> 5317658Sjulian#include <sys/tprintf.h> 5417658Sjulian#include <sys/syslog.h> 5517658Sjulian#include <sys/malloc.h> 5617658Sjulian#include <sys/kernel.h> 5721776Sbde#include <sys/mount.h> 5817658Sjulian#include <sys/sysctl.h> 5917658Sjulian#include <sys/conf.h> 6017658Sjulian#include <sys/sysproto.h> 6117658Sjulian 6217658Sjulian#include <machine/pcb.h> 6317658Sjulian#include <machine/clock.h> 6417658Sjulian#include <machine/cons.h> 6517658Sjulian#include <machine/md_var.h> 6626812Speter#ifdef SMP 6726812Speter#include <machine/smp.h> /* smp_active, cpuid */ 6826812Speter#endif 6917658Sjulian 7017658Sjulian#include <sys/utsname.h> 7117658Sjulian#include <sys/signalvar.h> 7217658Sjulian 7317658Sjulian#ifndef PANIC_REBOOT_WAIT_TIME 7417658Sjulian#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 7517658Sjulian#endif 7617658Sjulian 7717658Sjulian/* 7817658Sjulian * Note that stdarg.h and the ANSI style va_start macro is used for both 7917658Sjulian * ANSI and traditional C compilers. 8017658Sjulian */ 8117658Sjulian#include <machine/stdarg.h> 8217658Sjulian 8328769Sbde#ifdef DDB 8417658Sjulian#ifdef DDB_UNATTENDED 8528769Sbdestatic int debugger_on_panic = 0; 8617658Sjulian#else 8728769Sbdestatic int debugger_on_panic = 1; 8817658Sjulian#endif 8917658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 9017658Sjulian &debugger_on_panic, 0, ""); 9117658Sjulian#endif 9217658Sjulian 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 { 11417658Sjulian struct shutdown_list_element *next; 11517658Sjulian bootlist_fn function; 11617658Sjulian void *arg; 11717658Sjulian} *sle_p; 11817658Sjulian 11917768Sjulian/* 12017768Sjulian * there are two shutdown lists. Some things need to be shut down 12117768Sjulian * Earlier than others. 12217768Sjulian */ 12317768Sjulianstatic sle_p shutdown_list1; 12417768Sjulianstatic sle_p shutdown_list2; 12517658Sjulian 12617658Sjulian 12717658Sjulianstatic void dumpsys(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 14017658Sjulianreboot(p, uap, retval) 14117658Sjulian struct proc *p; 14217658Sjulian struct reboot_args *uap; 14317658Sjulian int *retval; 14417658Sjulian{ 14517658Sjulian int error; 14617658Sjulian 14717658Sjulian if ((error = suser(p->p_ucred, &p->p_acflag))) 14817658Sjulian return (error); 14917658Sjulian 15017658Sjulian boot(uap->opt); 15117658Sjulian return (0); 15217658Sjulian} 15317658Sjulian 15417658Sjulian/* 15517658Sjulian * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 15617658Sjulian */ 15717658Sjulianvoid 15828769Sbdeshutdown_nice() 15917658Sjulian{ 16017658Sjulian /* Send a signal to init(8) and have it shutdown the world */ 16117658Sjulian if (initproc != NULL) { 16217658Sjulian psignal(initproc, SIGINT); 16317658Sjulian } else { 16417658Sjulian /* No init(8) running, so simply reboot */ 16517658Sjulian boot(RB_NOSYNC); 16617658Sjulian } 16717658Sjulian return; 16817658Sjulian} 16917658Sjulianstatic int waittime = -1; 17017658Sjulianstatic struct pcb dumppcb; 17117658Sjulian 17217658Sjulian/* 17317658Sjulian * Go through the rigmarole of shutting down.. 17417658Sjulian * this used to be in machdep.c but I'll be dammned if I could see 17517658Sjulian * anything machine dependant in it. 17617658Sjulian */ 17718277Sbdevoid 17817658Sjulianboot(howto) 17917658Sjulian int howto; 18017658Sjulian{ 18117768Sjulian sle_p ep; 18217658Sjulian 18325164Speter#ifdef SMP 18425164Speter int c, spins; 18525164Speter 18628809Speter /* The MPSPEC says that the BSP must do the shutdown */ 18725164Speter if (smp_active) { 18828809Speter smp_active = 0; 18925164Speter 19025164Speter spins = 100; 19125164Speter 19226812Speter printf("boot() called on cpu#%d\n", cpuid); 19326812Speter while ((c = cpuid) != 0) { 19425164Speter if (spins-- < 1) { 19525164Speter printf("timeout waiting for cpu #0!\n"); 19625164Speter break; 19725164Speter } 19828809Speter printf("I'm on cpu#%d, I need to be on cpu#0, sleeping..\n", c); 19925164Speter tsleep((caddr_t)&smp_active, PZERO, "cpu0wt", 10); 20025164Speter } 20125164Speter } 20225164Speter#endif 20327997Sjulian /* 20427997Sjulian * Do any callouts that should be done BEFORE syncing the filesystems. 20527997Sjulian */ 20617768Sjulian ep = shutdown_list1; 20717768Sjulian while (ep) { 20817768Sjulian shutdown_list1 = ep->next; 20917658Sjulian (*ep->function)(howto, ep->arg); 21017658Sjulian ep = ep->next; 21117658Sjulian } 21227997Sjulian 21327997Sjulian /* 21427997Sjulian * Now sync filesystems 21527997Sjulian */ 21617658Sjulian if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) { 21717658Sjulian register struct buf *bp; 21817658Sjulian int iter, nbusy; 21917658Sjulian 22017658Sjulian waittime = 0; 22117658Sjulian printf("\nsyncing disks... "); 22217658Sjulian 22317658Sjulian sync(&proc0, NULL, NULL); 22417658Sjulian 22517658Sjulian for (iter = 0; iter < 20; iter++) { 22617658Sjulian nbusy = 0; 22717658Sjulian for (bp = &buf[nbuf]; --bp >= buf; ) { 22817658Sjulian if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 22917658Sjulian nbusy++; 23017658Sjulian } 23117658Sjulian } 23217658Sjulian if (nbusy == 0) 23317658Sjulian break; 23417658Sjulian printf("%d ", nbusy); 23517658Sjulian DELAY(40000 * iter); 23617658Sjulian } 23717658Sjulian if (nbusy) { 23817658Sjulian /* 23917658Sjulian * Failed to sync all blocks. Indicate this and don't 24017658Sjulian * unmount filesystems (thus forcing an fsck on reboot). 24117658Sjulian */ 24217658Sjulian printf("giving up\n"); 24317658Sjulian#ifdef SHOW_BUSYBUFS 24417658Sjulian nbusy = 0; 24517658Sjulian for (bp = &buf[nbuf]; --bp >= buf; ) { 24617658Sjulian if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 24717658Sjulian nbusy++; 24817658Sjulian printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno); 24917658Sjulian } 25017658Sjulian } 25117658Sjulian DELAY(5000000); /* 5 seconds */ 25217658Sjulian#endif 25317658Sjulian } else { 25417658Sjulian printf("done\n"); 25517658Sjulian /* 25617658Sjulian * Unmount filesystems 25717658Sjulian */ 25817658Sjulian if (panicstr == 0) 25917658Sjulian vfs_unmountall(); 26017658Sjulian } 26117658Sjulian DELAY(100000); /* wait for console output to finish */ 26217658Sjulian } 26327997Sjulian 26427997Sjulian /* 26527997Sjulian * Ok, now do things that assume all filesystem activity has 26627997Sjulian * been completed. 26727997Sjulian */ 26817768Sjulian ep = shutdown_list2; 26917768Sjulian while (ep) { 27017768Sjulian shutdown_list2 = ep->next; 27117768Sjulian (*ep->function)(howto, ep->arg); 27217768Sjulian ep = ep->next; 27317768Sjulian } 27417658Sjulian splhigh(); 27517658Sjulian if (howto & RB_HALT) { 27626657Swollman cpu_power_down(); 27717658Sjulian printf("\n"); 27817658Sjulian printf("The operating system has halted.\n"); 27917658Sjulian printf("Please press any key to reboot.\n\n"); 28019274Sjulian switch (cngetc()) { 28119274Sjulian case -1: /* No console, just die */ 28219274Sjulian cpu_halt(); 28319274Sjulian /* NOTREACHED */ 28419274Sjulian default: 28519274Sjulian break; 28619274Sjulian } 28717658Sjulian } else { 28817658Sjulian if (howto & RB_DUMP) { 28917658Sjulian if (!cold) { 29017658Sjulian savectx(&dumppcb); 29117658Sjulian dumppcb.pcb_cr3 = rcr3(); 29217658Sjulian dumpsys(); 29317658Sjulian } 29417658Sjulian 29517658Sjulian if (PANIC_REBOOT_WAIT_TIME != 0) { 29617658Sjulian if (PANIC_REBOOT_WAIT_TIME != -1) { 29717658Sjulian int loop; 29817658Sjulian printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 29917658Sjulian PANIC_REBOOT_WAIT_TIME); 30017658Sjulian for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) { 30117658Sjulian DELAY(1000 * 100); /* 1/10th second */ 30218290Sbde /* Did user type a key? */ 30318290Sbde if (cncheckc() != -1) 30417658Sjulian break; 30517658Sjulian } 30617658Sjulian if (!loop) 30717658Sjulian goto die; 30817658Sjulian } 30917658Sjulian } else { /* zero time specified - reboot NOW */ 31017658Sjulian goto die; 31117658Sjulian } 31217658Sjulian printf("--> Press a key on the console to reboot <--\n"); 31317658Sjulian cngetc(); 31417658Sjulian } 31517658Sjulian } 31617658Sjuliandie: 31717658Sjulian printf("Rebooting...\n"); 31817658Sjulian DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 31917677Sjulian /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 32017658Sjulian cpu_reset(); 32117658Sjulian for(;;) ; 32217658Sjulian /* NOTREACHED */ 32317658Sjulian} 32417658Sjulian 32517658Sjulian/* 32617658Sjulian * Magic number for savecore 32717658Sjulian * 32817658Sjulian * exported (symorder) and used at least by savecore(8) 32917658Sjulian * 33017658Sjulian */ 33117658Sjulianstatic u_long const dumpmag = 0x8fca0101UL; 33217658Sjulian 33317658Sjulianstatic int dumpsize = 0; /* also for savecore */ 33417658Sjulian 33517658Sjulianstatic int dodump = 1; 33617658SjulianSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, ""); 33717658Sjulian 33817658Sjulian/* 33917658Sjulian * Doadump comes here after turning off memory management and 34017658Sjulian * getting on the dump stack, either when called above, or by 34117658Sjulian * the auto-restart code. 34217658Sjulian */ 34317658Sjulianstatic void 34417658Sjuliandumpsys(void) 34517658Sjulian{ 34617658Sjulian 34717658Sjulian if (!dodump) 34817658Sjulian return; 34917658Sjulian if (dumpdev == NODEV) 35017658Sjulian return; 35117658Sjulian if ((minor(dumpdev)&07) != 1) 35217658Sjulian return; 35317658Sjulian if (!(bdevsw[major(dumpdev)])) 35417658Sjulian return; 35517658Sjulian if (!(bdevsw[major(dumpdev)]->d_dump)) 35617658Sjulian return; 35717658Sjulian dumpsize = Maxmem; 35817658Sjulian printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 35917658Sjulian printf("dump "); 36017658Sjulian switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) { 36117658Sjulian 36217658Sjulian case ENXIO: 36317658Sjulian printf("device bad\n"); 36417658Sjulian break; 36517658Sjulian 36617658Sjulian case EFAULT: 36717658Sjulian printf("device not ready\n"); 36817658Sjulian break; 36917658Sjulian 37017658Sjulian case EINVAL: 37117658Sjulian printf("area improper\n"); 37217658Sjulian break; 37317658Sjulian 37417658Sjulian case EIO: 37517658Sjulian printf("i/o error\n"); 37617658Sjulian break; 37717658Sjulian 37817658Sjulian case EINTR: 37917658Sjulian printf("aborted from console\n"); 38017658Sjulian break; 38117658Sjulian 38217658Sjulian default: 38317658Sjulian printf("succeeded\n"); 38417658Sjulian break; 38517658Sjulian } 38617658Sjulian} 38717658Sjulian 38817658Sjulian/* 38917658Sjulian * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 39017658Sjulian * and then reboots. If we are called twice, then we avoid trying to sync 39117658Sjulian * the disks as this often leads to recursive panics. 39217658Sjulian */ 39317658Sjulianvoid 39417658Sjulianpanic(const char *fmt, ...) 39517658Sjulian{ 39617658Sjulian int bootopt; 39717658Sjulian va_list ap; 39817658Sjulian 39917658Sjulian bootopt = RB_AUTOBOOT | RB_DUMP; 40017658Sjulian if (panicstr) 40117658Sjulian bootopt |= RB_NOSYNC; 40217658Sjulian else 40317658Sjulian panicstr = fmt; 40417658Sjulian 40517658Sjulian printf("panic: "); 40617658Sjulian va_start(ap, fmt); 40717658Sjulian vprintf(fmt, ap); 40817658Sjulian va_end(ap); 40917658Sjulian printf("\n"); 41026100Sfsmp#ifdef SMP 41126812Speter printf(" cpuid %d\n", cpuid); 41226100Sfsmp#endif 41317658Sjulian 41417658Sjulian#if defined(DDB) 41517658Sjulian if (debugger_on_panic) 41617658Sjulian Debugger ("panic"); 41717658Sjulian#endif 41817658Sjulian boot(bootopt); 41917658Sjulian} 42017658Sjulian 42117768Sjulian/* 42217768Sjulian * Two routines to handle adding/deleting items on the 42317768Sjulian * shutdown callout lists 42417768Sjulian * 42517768Sjulian * at_shutdown(): 42617658Sjulian * Take the arguments given and put them onto the shutdown callout list. 42717658Sjulian * However first make sure that it's not already there. 42817658Sjulian * returns 0 on success. 42917658Sjulian */ 43017658Sjulianint 43117768Sjulianat_shutdown(bootlist_fn function, void *arg, int position) 43217658Sjulian{ 43317768Sjulian sle_p ep, *epp; 43417768Sjulian 43517768Sjulian switch(position) { 43617768Sjulian case SHUTDOWN_PRE_SYNC: 43717768Sjulian epp = &shutdown_list1; 43817768Sjulian break; 43917768Sjulian case SHUTDOWN_POST_SYNC: 44017768Sjulian epp = &shutdown_list2; 44117768Sjulian break; 44217768Sjulian default: 44317768Sjulian printf("bad exit callout list specified\n"); 44417768Sjulian return (EINVAL); 44517768Sjulian } 44617768Sjulian if (rm_at_shutdown(function, arg)) 44717658Sjulian printf("exit callout entry already present\n"); 44817768Sjulian ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 44917768Sjulian if (ep == NULL) 45017768Sjulian return (ENOMEM); 45117768Sjulian ep->next = *epp; 45217658Sjulian ep->function = function; 45317658Sjulian ep->arg = arg; 45417768Sjulian *epp = ep; 45517768Sjulian return (0); 45617658Sjulian} 45717768Sjulian 45817658Sjulian/* 45917768Sjulian * Scan the exit callout lists for the given items and remove them. 46017658Sjulian * Returns the number of items removed. 46117658Sjulian */ 46217658Sjulianint 46317658Sjulianrm_at_shutdown(bootlist_fn function, void *arg) 46417658Sjulian{ 46517768Sjulian sle_p *epp, ep; 46617768Sjulian int count; 46717658Sjulian 46817768Sjulian count = 0; 46917768Sjulian epp = &shutdown_list1; 47017658Sjulian ep = *epp; 47117768Sjulian while (ep) { 47217834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 47317658Sjulian *epp = ep->next; 47417768Sjulian free(ep, M_TEMP); 47517658Sjulian count++; 47617658Sjulian } else { 47717658Sjulian epp = &ep->next; 47817658Sjulian } 47917658Sjulian ep = *epp; 48017658Sjulian } 48117768Sjulian epp = &shutdown_list2; 48217768Sjulian ep = *epp; 48317768Sjulian while (ep) { 48417834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 48517768Sjulian *epp = ep->next; 48617768Sjulian free(ep, M_TEMP); 48717768Sjulian count++; 48817768Sjulian } else { 48917768Sjulian epp = &ep->next; 49017768Sjulian } 49117768Sjulian ep = *epp; 49217768Sjulian } 49317768Sjulian return (count); 49417658Sjulian} 49517658Sjulian 496