kern_shutdown.c revision 35974
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 3935974Sbde * $Id: kern_shutdown.c,v 1.30 1998/05/06 22:14:48 julian 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> 5517658Sjulian#include <sys/sysctl.h> 5617658Sjulian#include <sys/conf.h> 5717658Sjulian#include <sys/sysproto.h> 5817658Sjulian 5917658Sjulian#include <machine/pcb.h> 6017658Sjulian#include <machine/clock.h> 6117658Sjulian#include <machine/cons.h> 6217658Sjulian#include <machine/md_var.h> 6326812Speter#ifdef SMP 6426812Speter#include <machine/smp.h> /* smp_active, cpuid */ 6526812Speter#endif 6617658Sjulian 6717658Sjulian#include <sys/signalvar.h> 6817658Sjulian 6917658Sjulian#ifndef PANIC_REBOOT_WAIT_TIME 7017658Sjulian#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 7117658Sjulian#endif 7217658Sjulian 7317658Sjulian/* 7417658Sjulian * Note that stdarg.h and the ANSI style va_start macro is used for both 7517658Sjulian * ANSI and traditional C compilers. 7617658Sjulian */ 7717658Sjulian#include <machine/stdarg.h> 7817658Sjulian 7928769Sbde#ifdef DDB 8017658Sjulian#ifdef DDB_UNATTENDED 8128769Sbdestatic int debugger_on_panic = 0; 8217658Sjulian#else 8328769Sbdestatic int debugger_on_panic = 1; 8417658Sjulian#endif 8517658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 8617658Sjulian &debugger_on_panic, 0, ""); 8717658Sjulian#endif 8817658Sjulian 8928000Sjulian#ifdef HW_WDOG 9017658Sjulian/* 9127997Sjulian * If there is a hardware watchdog, point this at the function needed to 9227997Sjulian * hold it off. 9327997Sjulian * It's needed when the kernel needs to do some lengthy operations. 9427997Sjulian * e.g. in wd.c when dumping core.. It's most annoying to have 9527997Sjulian * your precious core-dump only half written because the wdog kicked in. 9627997Sjulian */ 9727997Sjulianwatchdog_tickle_fn wdog_tickler = NULL; 9828000Sjulian#endif /* HW_WDOG */ 9927997Sjulian 10027997Sjulian/* 10117658Sjulian * Variable panicstr contains argument to first call to panic; used as flag 10217658Sjulian * to indicate that the kernel has already called panic. 10317658Sjulian */ 10417658Sjulianconst char *panicstr; 10517658Sjulian 10617658Sjulian/* 10717658Sjulian * callout list for things to do a shutdown 10817658Sjulian */ 10917658Sjuliantypedef struct shutdown_list_element { 11017658Sjulian struct shutdown_list_element *next; 11117658Sjulian bootlist_fn function; 11217658Sjulian void *arg; 11317658Sjulian} *sle_p; 11417658Sjulian 11517768Sjulian/* 11617768Sjulian * there are two shutdown lists. Some things need to be shut down 11717768Sjulian * Earlier than others. 11817768Sjulian */ 11917768Sjulianstatic sle_p shutdown_list1; 12017768Sjulianstatic sle_p shutdown_list2; 12117658Sjulian 12231275Sbdestatic void boot __P((int)) __dead2; 12331275Sbdestatic void dumpsys __P((void)); 12417658Sjulian 12517658Sjulian#ifndef _SYS_SYSPROTO_H_ 12617658Sjulianstruct reboot_args { 12717658Sjulian int opt; 12817658Sjulian}; 12917658Sjulian#endif 13017658Sjulian/* ARGSUSED */ 13117658Sjulian 13217658Sjulian/* 13317658Sjulian * The system call that results in a reboot 13417658Sjulian */ 13517658Sjulianint 13630994Sphkreboot(p, uap) 13717658Sjulian struct proc *p; 13817658Sjulian struct reboot_args *uap; 13917658Sjulian{ 14017658Sjulian int error; 14117658Sjulian 14217658Sjulian if ((error = suser(p->p_ucred, &p->p_acflag))) 14317658Sjulian return (error); 14417658Sjulian 14517658Sjulian boot(uap->opt); 14617658Sjulian return (0); 14717658Sjulian} 14817658Sjulian 14917658Sjulian/* 15017658Sjulian * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 15117658Sjulian */ 15217658Sjulianvoid 15328769Sbdeshutdown_nice() 15417658Sjulian{ 15517658Sjulian /* Send a signal to init(8) and have it shutdown the world */ 15617658Sjulian if (initproc != NULL) { 15717658Sjulian psignal(initproc, SIGINT); 15817658Sjulian } else { 15917658Sjulian /* No init(8) running, so simply reboot */ 16017658Sjulian boot(RB_NOSYNC); 16117658Sjulian } 16217658Sjulian return; 16317658Sjulian} 16417658Sjulianstatic int waittime = -1; 16517658Sjulianstatic struct pcb dumppcb; 16617658Sjulian 16717658Sjulian/* 16817658Sjulian * Go through the rigmarole of shutting down.. 16917658Sjulian * this used to be in machdep.c but I'll be dammned if I could see 17017658Sjulian * anything machine dependant in it. 17117658Sjulian */ 17231275Sbdestatic void 17317658Sjulianboot(howto) 17417658Sjulian int howto; 17517658Sjulian{ 17617768Sjulian sle_p ep; 17717658Sjulian 17825164Speter#ifdef SMP 17925164Speter int c, spins; 18025164Speter 18128809Speter /* The MPSPEC says that the BSP must do the shutdown */ 18225164Speter if (smp_active) { 18328809Speter smp_active = 0; 18425164Speter 18525164Speter spins = 100; 18625164Speter 18726812Speter printf("boot() called on cpu#%d\n", cpuid); 18826812Speter while ((c = cpuid) != 0) { 18925164Speter if (spins-- < 1) { 19025164Speter printf("timeout waiting for cpu #0!\n"); 19125164Speter break; 19225164Speter } 19328809Speter printf("I'm on cpu#%d, I need to be on cpu#0, sleeping..\n", c); 19425164Speter tsleep((caddr_t)&smp_active, PZERO, "cpu0wt", 10); 19525164Speter } 19625164Speter } 19725164Speter#endif 19827997Sjulian /* 19927997Sjulian * Do any callouts that should be done BEFORE syncing the filesystems. 20027997Sjulian */ 20117768Sjulian ep = shutdown_list1; 20217768Sjulian while (ep) { 20317768Sjulian shutdown_list1 = ep->next; 20417658Sjulian (*ep->function)(howto, ep->arg); 20517658Sjulian ep = ep->next; 20617658Sjulian } 20727997Sjulian 20827997Sjulian /* 20927997Sjulian * Now sync filesystems 21027997Sjulian */ 21117658Sjulian if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) { 21217658Sjulian register struct buf *bp; 21317658Sjulian int iter, nbusy; 21417658Sjulian 21517658Sjulian waittime = 0; 21617658Sjulian printf("\nsyncing disks... "); 21717658Sjulian 21830994Sphk sync(&proc0, NULL); 21917658Sjulian 22034266Sjulian /* 22134266Sjulian * With soft updates, some buffers that are 22234266Sjulian * written will be remarked as dirty until other 22334266Sjulian * buffers are written. 22434266Sjulian */ 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++; 23034266Sjulian } else if ((bp->b_flags & (B_DELWRI | B_INVAL)) 23134266Sjulian == B_DELWRI) { 23234266Sjulian /* bawrite(bp);*/ 23334266Sjulian nbusy++; 23417658Sjulian } 23517658Sjulian } 23617658Sjulian if (nbusy == 0) 23717658Sjulian break; 23817658Sjulian printf("%d ", nbusy); 23934266Sjulian sync(&proc0, NULL); 24034266Sjulian DELAY(50000 * iter); 24117658Sjulian } 24217658Sjulian if (nbusy) { 24317658Sjulian /* 24417658Sjulian * Failed to sync all blocks. Indicate this and don't 24517658Sjulian * unmount filesystems (thus forcing an fsck on reboot). 24617658Sjulian */ 24717658Sjulian printf("giving up\n"); 24817658Sjulian#ifdef SHOW_BUSYBUFS 24917658Sjulian nbusy = 0; 25017658Sjulian for (bp = &buf[nbuf]; --bp >= buf; ) { 25117658Sjulian if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 25217658Sjulian nbusy++; 25317658Sjulian printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno); 25417658Sjulian } 25517658Sjulian } 25617658Sjulian DELAY(5000000); /* 5 seconds */ 25717658Sjulian#endif 25817658Sjulian } else { 25917658Sjulian printf("done\n"); 26017658Sjulian /* 26117658Sjulian * Unmount filesystems 26217658Sjulian */ 26317658Sjulian if (panicstr == 0) 26417658Sjulian vfs_unmountall(); 26517658Sjulian } 26617658Sjulian DELAY(100000); /* wait for console output to finish */ 26717658Sjulian } 26827997Sjulian 26927997Sjulian /* 27027997Sjulian * Ok, now do things that assume all filesystem activity has 27127997Sjulian * been completed. 27227997Sjulian */ 27317768Sjulian ep = shutdown_list2; 27417768Sjulian while (ep) { 27517768Sjulian shutdown_list2 = ep->next; 27617768Sjulian (*ep->function)(howto, ep->arg); 27717768Sjulian ep = ep->next; 27817768Sjulian } 27917658Sjulian splhigh(); 28017658Sjulian if (howto & RB_HALT) { 28126657Swollman cpu_power_down(); 28217658Sjulian printf("\n"); 28317658Sjulian printf("The operating system has halted.\n"); 28417658Sjulian printf("Please press any key to reboot.\n\n"); 28519274Sjulian switch (cngetc()) { 28619274Sjulian case -1: /* No console, just die */ 28719274Sjulian cpu_halt(); 28819274Sjulian /* NOTREACHED */ 28919274Sjulian default: 29019274Sjulian break; 29119274Sjulian } 29217658Sjulian } else { 29317658Sjulian if (howto & RB_DUMP) { 29417658Sjulian if (!cold) { 29517658Sjulian savectx(&dumppcb); 29617658Sjulian dumppcb.pcb_cr3 = rcr3(); 29717658Sjulian dumpsys(); 29817658Sjulian } 29917658Sjulian 30017658Sjulian if (PANIC_REBOOT_WAIT_TIME != 0) { 30117658Sjulian if (PANIC_REBOOT_WAIT_TIME != -1) { 30217658Sjulian int loop; 30317658Sjulian printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 30417658Sjulian PANIC_REBOOT_WAIT_TIME); 30517658Sjulian for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) { 30617658Sjulian DELAY(1000 * 100); /* 1/10th second */ 30718290Sbde /* Did user type a key? */ 30818290Sbde if (cncheckc() != -1) 30917658Sjulian break; 31017658Sjulian } 31117658Sjulian if (!loop) 31217658Sjulian goto die; 31317658Sjulian } 31417658Sjulian } else { /* zero time specified - reboot NOW */ 31517658Sjulian goto die; 31617658Sjulian } 31717658Sjulian printf("--> Press a key on the console to reboot <--\n"); 31817658Sjulian cngetc(); 31917658Sjulian } 32017658Sjulian } 32117658Sjuliandie: 32217658Sjulian printf("Rebooting...\n"); 32317658Sjulian DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 32417677Sjulian /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 32517658Sjulian cpu_reset(); 32617658Sjulian for(;;) ; 32717658Sjulian /* NOTREACHED */ 32817658Sjulian} 32917658Sjulian 33017658Sjulian/* 33117658Sjulian * Magic number for savecore 33217658Sjulian * 33317658Sjulian * exported (symorder) and used at least by savecore(8) 33417658Sjulian * 33517658Sjulian */ 33617658Sjulianstatic u_long const dumpmag = 0x8fca0101UL; 33717658Sjulian 33817658Sjulianstatic int dumpsize = 0; /* also for savecore */ 33917658Sjulian 34017658Sjulianstatic int dodump = 1; 34117658SjulianSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, ""); 34217658Sjulian 34331403Sjulian/* ARGSUSED */ 34431403Sjulianstatic void dump_conf __P((void *dummy)); 34531403Sjulianstatic void 34631403Sjuliandump_conf(dummy) 34731403Sjulian void *dummy; 34831403Sjulian{ 34931403Sjulian cpu_dumpconf(); 35031403Sjulian} 35131403SjulianSYSINIT(dump_conf, SI_SUB_DUMP_CONF, SI_ORDER_FIRST, dump_conf, NULL) 35231403Sjulian 35317658Sjulian/* 35417658Sjulian * Doadump comes here after turning off memory management and 35517658Sjulian * getting on the dump stack, either when called above, or by 35617658Sjulian * the auto-restart code. 35717658Sjulian */ 35817658Sjulianstatic void 35917658Sjuliandumpsys(void) 36017658Sjulian{ 36117658Sjulian 36217658Sjulian if (!dodump) 36317658Sjulian return; 36417658Sjulian if (dumpdev == NODEV) 36517658Sjulian return; 36635974Sbde if ((minor(dumpdev)&07) != 1) 36735974Sbde return; 36817658Sjulian if (!(bdevsw[major(dumpdev)])) 36917658Sjulian return; 37017658Sjulian if (!(bdevsw[major(dumpdev)]->d_dump)) 37117658Sjulian return; 37217658Sjulian dumpsize = Maxmem; 37317658Sjulian printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 37417658Sjulian printf("dump "); 37517658Sjulian switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) { 37617658Sjulian 37717658Sjulian case ENXIO: 37817658Sjulian printf("device bad\n"); 37917658Sjulian break; 38017658Sjulian 38117658Sjulian case EFAULT: 38217658Sjulian printf("device not ready\n"); 38317658Sjulian break; 38417658Sjulian 38517658Sjulian case EINVAL: 38617658Sjulian printf("area improper\n"); 38717658Sjulian break; 38817658Sjulian 38917658Sjulian case EIO: 39017658Sjulian printf("i/o error\n"); 39117658Sjulian break; 39217658Sjulian 39317658Sjulian case EINTR: 39417658Sjulian printf("aborted from console\n"); 39517658Sjulian break; 39617658Sjulian 39717658Sjulian default: 39817658Sjulian printf("succeeded\n"); 39917658Sjulian break; 40017658Sjulian } 40117658Sjulian} 40217658Sjulian 40317658Sjulian/* 40417658Sjulian * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 40517658Sjulian * and then reboots. If we are called twice, then we avoid trying to sync 40617658Sjulian * the disks as this often leads to recursive panics. 40717658Sjulian */ 40817658Sjulianvoid 40917658Sjulianpanic(const char *fmt, ...) 41017658Sjulian{ 41117658Sjulian int bootopt; 41217658Sjulian va_list ap; 41317658Sjulian 41417658Sjulian bootopt = RB_AUTOBOOT | RB_DUMP; 41517658Sjulian if (panicstr) 41617658Sjulian bootopt |= RB_NOSYNC; 41717658Sjulian else 41817658Sjulian panicstr = fmt; 41917658Sjulian 42017658Sjulian printf("panic: "); 42117658Sjulian va_start(ap, fmt); 42217658Sjulian vprintf(fmt, ap); 42317658Sjulian va_end(ap); 42417658Sjulian printf("\n"); 42526100Sfsmp#ifdef SMP 42629128Speter /* three seperate prints in case of an unmapped page and trap */ 42729128Speter printf("mp_lock = %08x; ", mp_lock); 42829128Speter printf("cpuid = %d; ", cpuid); 42929128Speter printf("lapic.id = %08x\n", lapic.id); 43026100Sfsmp#endif 43117658Sjulian 43217658Sjulian#if defined(DDB) 43317658Sjulian if (debugger_on_panic) 43417658Sjulian Debugger ("panic"); 43517658Sjulian#endif 43617658Sjulian boot(bootopt); 43717658Sjulian} 43817658Sjulian 43917768Sjulian/* 44017768Sjulian * Two routines to handle adding/deleting items on the 44117768Sjulian * shutdown callout lists 44217768Sjulian * 44317768Sjulian * at_shutdown(): 44417658Sjulian * Take the arguments given and put them onto the shutdown callout list. 44517658Sjulian * However first make sure that it's not already there. 44617658Sjulian * returns 0 on success. 44717658Sjulian */ 44817658Sjulianint 44917768Sjulianat_shutdown(bootlist_fn function, void *arg, int position) 45017658Sjulian{ 45117768Sjulian sle_p ep, *epp; 45217768Sjulian 45317768Sjulian switch(position) { 45417768Sjulian case SHUTDOWN_PRE_SYNC: 45517768Sjulian epp = &shutdown_list1; 45617768Sjulian break; 45717768Sjulian case SHUTDOWN_POST_SYNC: 45817768Sjulian epp = &shutdown_list2; 45917768Sjulian break; 46017768Sjulian default: 46117768Sjulian printf("bad exit callout list specified\n"); 46217768Sjulian return (EINVAL); 46317768Sjulian } 46417768Sjulian if (rm_at_shutdown(function, arg)) 46517658Sjulian printf("exit callout entry already present\n"); 46617768Sjulian ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 46717768Sjulian if (ep == NULL) 46817768Sjulian return (ENOMEM); 46917768Sjulian ep->next = *epp; 47017658Sjulian ep->function = function; 47117658Sjulian ep->arg = arg; 47217768Sjulian *epp = ep; 47317768Sjulian return (0); 47417658Sjulian} 47517768Sjulian 47617658Sjulian/* 47717768Sjulian * Scan the exit callout lists for the given items and remove them. 47817658Sjulian * Returns the number of items removed. 47917658Sjulian */ 48017658Sjulianint 48117658Sjulianrm_at_shutdown(bootlist_fn function, void *arg) 48217658Sjulian{ 48317768Sjulian sle_p *epp, ep; 48417768Sjulian int count; 48517658Sjulian 48617768Sjulian count = 0; 48717768Sjulian epp = &shutdown_list1; 48817658Sjulian ep = *epp; 48917768Sjulian while (ep) { 49017834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 49117658Sjulian *epp = ep->next; 49217768Sjulian free(ep, M_TEMP); 49317658Sjulian count++; 49417658Sjulian } else { 49517658Sjulian epp = &ep->next; 49617658Sjulian } 49717658Sjulian ep = *epp; 49817658Sjulian } 49917768Sjulian epp = &shutdown_list2; 50017768Sjulian ep = *epp; 50117768Sjulian while (ep) { 50217834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 50317768Sjulian *epp = ep->next; 50417768Sjulian free(ep, M_TEMP); 50517768Sjulian count++; 50617768Sjulian } else { 50717768Sjulian epp = &ep->next; 50817768Sjulian } 50917768Sjulian ep = *epp; 51017768Sjulian } 51117768Sjulian return (count); 51217658Sjulian} 51317658Sjulian 514