kern_shutdown.c revision 25164
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 3925164Speter * $Id: kern_shutdown.c,v 1.13 1997/02/22 09:39:10 peter Exp $ 4017658Sjulian */ 4117658Sjulian 4217658Sjulian#include "opt_ddb.h" 4317658Sjulian 4417658Sjulian#include <sys/param.h> 4517658Sjulian#include <sys/systm.h> 4617658Sjulian#include <sys/reboot.h> 4717658Sjulian#include <sys/msgbuf.h> 4817658Sjulian#include <sys/proc.h> 4917658Sjulian#include <sys/vnode.h> 5017658Sjulian#include <sys/tty.h> 5117658Sjulian#include <sys/tprintf.h> 5217658Sjulian#include <sys/syslog.h> 5317658Sjulian#include <sys/malloc.h> 5417658Sjulian#include <sys/kernel.h> 5521776Sbde#include <sys/mount.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> 6417658Sjulian 6517658Sjulian#include <sys/utsname.h> 6617658Sjulian#include <sys/signalvar.h> 6717658Sjulian 6817658Sjulian#ifndef PANIC_REBOOT_WAIT_TIME 6917658Sjulian#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 7017658Sjulian#endif 7117658Sjulian 7217658Sjulian/* 7317658Sjulian * Note that stdarg.h and the ANSI style va_start macro is used for both 7417658Sjulian * ANSI and traditional C compilers. 7517658Sjulian */ 7617658Sjulian#include <machine/stdarg.h> 7717658Sjulian 7817658Sjulian#if defined(DDB) 7917658Sjulian#ifdef DDB_UNATTENDED 8017658Sjulian static int debugger_on_panic = 0; 8117658Sjulian#else 8217658Sjulian static int debugger_on_panic = 1; 8317658Sjulian#endif 8417658Sjulian 8517658SjulianSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 8617658Sjulian &debugger_on_panic, 0, ""); 8717658Sjulian#endif 8817658Sjulian 8917658Sjulian 9017658Sjulian/* 9117658Sjulian * Variable panicstr contains argument to first call to panic; used as flag 9217658Sjulian * to indicate that the kernel has already called panic. 9317658Sjulian */ 9417658Sjulianconst char *panicstr; 9517658Sjulian 9617658Sjulian/* 9717658Sjulian * callout list for things to do a shutdown 9817658Sjulian */ 9917658Sjuliantypedef struct shutdown_list_element { 10017658Sjulian struct shutdown_list_element *next; 10117658Sjulian bootlist_fn function; 10217658Sjulian void *arg; 10317658Sjulian} *sle_p; 10417658Sjulian 10517768Sjulian/* 10617768Sjulian * there are two shutdown lists. Some things need to be shut down 10717768Sjulian * Earlier than others. 10817768Sjulian */ 10917768Sjulianstatic sle_p shutdown_list1; 11017768Sjulianstatic sle_p shutdown_list2; 11117658Sjulian 11217658Sjulian 11317658Sjulianstatic void dumpsys(void); 11417658Sjulian 11517658Sjulian#ifndef _SYS_SYSPROTO_H_ 11617658Sjulianstruct reboot_args { 11717658Sjulian int opt; 11817658Sjulian}; 11917658Sjulian#endif 12017658Sjulian/* ARGSUSED */ 12117658Sjulian 12217658Sjulian/* 12317658Sjulian * The system call that results in a reboot 12417658Sjulian */ 12517658Sjulianint 12617658Sjulianreboot(p, uap, retval) 12717658Sjulian struct proc *p; 12817658Sjulian struct reboot_args *uap; 12917658Sjulian int *retval; 13017658Sjulian{ 13117658Sjulian int error; 13217658Sjulian 13317658Sjulian if ((error = suser(p->p_ucred, &p->p_acflag))) 13417658Sjulian return (error); 13517658Sjulian 13617658Sjulian boot(uap->opt); 13717658Sjulian return (0); 13817658Sjulian} 13917658Sjulian 14017658Sjulian/* 14117658Sjulian * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 14217658Sjulian */ 14317658Sjulianvoid 14417658Sjulianshutdown_nice(void) 14517658Sjulian{ 14617658Sjulian /* Send a signal to init(8) and have it shutdown the world */ 14717658Sjulian if (initproc != NULL) { 14817658Sjulian psignal(initproc, SIGINT); 14917658Sjulian } else { 15017658Sjulian /* No init(8) running, so simply reboot */ 15117658Sjulian boot(RB_NOSYNC); 15217658Sjulian } 15317658Sjulian return; 15417658Sjulian} 15517658Sjulianstatic int waittime = -1; 15617658Sjulianstatic struct pcb dumppcb; 15717658Sjulian 15817658Sjulian/* 15917658Sjulian * Go through the rigmarole of shutting down.. 16017658Sjulian * this used to be in machdep.c but I'll be dammned if I could see 16117658Sjulian * anything machine dependant in it. 16217658Sjulian */ 16318277Sbdevoid 16417658Sjulianboot(howto) 16517658Sjulian int howto; 16617658Sjulian{ 16717768Sjulian sle_p ep; 16817658Sjulian 16925164Speter#ifdef SMP 17025164Speter int c, spins; 17125164Speter 17225164Speter /* don't accidently start it */ 17325164Speter if (smp_active) { 17425164Speter smp_active = 1; 17525164Speter 17625164Speter spins = 100; 17725164Speter 17825164Speter printf("boot() called on cpu#%d\n", cpunumber()); 17925164Speter while ((c = cpunumber()) != 0) { 18025164Speter if (spins-- < 1) { 18125164Speter printf("timeout waiting for cpu #0!\n"); 18225164Speter break; 18325164Speter } 18425164Speter printf("oops, I'm on cpu#%d, I need to be on cpu#0!\n", 18525164Speter c); 18625164Speter tsleep((caddr_t)&smp_active, PZERO, "cpu0wt", 10); 18725164Speter } 18825164Speter } 18925164Speter#endif 19017768Sjulian ep = shutdown_list1; 19117768Sjulian while (ep) { 19217768Sjulian shutdown_list1 = ep->next; 19317658Sjulian (*ep->function)(howto, ep->arg); 19417658Sjulian ep = ep->next; 19517658Sjulian } 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 20317658Sjulian sync(&proc0, NULL, NULL); 20417658Sjulian 20517658Sjulian for (iter = 0; iter < 20; iter++) { 20617658Sjulian nbusy = 0; 20717658Sjulian for (bp = &buf[nbuf]; --bp >= buf; ) { 20817658Sjulian if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 20917658Sjulian nbusy++; 21017658Sjulian } 21117658Sjulian } 21217658Sjulian if (nbusy == 0) 21317658Sjulian break; 21417658Sjulian printf("%d ", nbusy); 21517658Sjulian DELAY(40000 * iter); 21617658Sjulian } 21717658Sjulian if (nbusy) { 21817658Sjulian /* 21917658Sjulian * Failed to sync all blocks. Indicate this and don't 22017658Sjulian * unmount filesystems (thus forcing an fsck on reboot). 22117658Sjulian */ 22217658Sjulian printf("giving up\n"); 22317658Sjulian#ifdef SHOW_BUSYBUFS 22417658Sjulian nbusy = 0; 22517658Sjulian for (bp = &buf[nbuf]; --bp >= buf; ) { 22617658Sjulian if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 22717658Sjulian nbusy++; 22817658Sjulian printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno); 22917658Sjulian } 23017658Sjulian } 23117658Sjulian DELAY(5000000); /* 5 seconds */ 23217658Sjulian#endif 23317658Sjulian } else { 23417658Sjulian printf("done\n"); 23517658Sjulian /* 23617658Sjulian * Unmount filesystems 23717658Sjulian */ 23817658Sjulian if (panicstr == 0) 23917658Sjulian vfs_unmountall(); 24017658Sjulian } 24117658Sjulian DELAY(100000); /* wait for console output to finish */ 24217658Sjulian } 24317768Sjulian ep = shutdown_list2; 24417768Sjulian while (ep) { 24517768Sjulian shutdown_list2 = ep->next; 24617768Sjulian (*ep->function)(howto, ep->arg); 24717768Sjulian ep = ep->next; 24817768Sjulian } 24917658Sjulian splhigh(); 25017658Sjulian if (howto & RB_HALT) { 25117658Sjulian printf("\n"); 25217658Sjulian printf("The operating system has halted.\n"); 25317658Sjulian printf("Please press any key to reboot.\n\n"); 25419274Sjulian switch (cngetc()) { 25519274Sjulian case -1: /* No console, just die */ 25619274Sjulian cpu_halt(); 25719274Sjulian /* NOTREACHED */ 25819274Sjulian default: 25919274Sjulian break; 26019274Sjulian } 26117658Sjulian } else { 26217658Sjulian if (howto & RB_DUMP) { 26317658Sjulian if (!cold) { 26417658Sjulian savectx(&dumppcb); 26517658Sjulian dumppcb.pcb_cr3 = rcr3(); 26617658Sjulian dumpsys(); 26717658Sjulian } 26817658Sjulian 26917658Sjulian if (PANIC_REBOOT_WAIT_TIME != 0) { 27017658Sjulian if (PANIC_REBOOT_WAIT_TIME != -1) { 27117658Sjulian int loop; 27217658Sjulian printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 27317658Sjulian PANIC_REBOOT_WAIT_TIME); 27417658Sjulian for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) { 27517658Sjulian DELAY(1000 * 100); /* 1/10th second */ 27618290Sbde /* Did user type a key? */ 27718290Sbde if (cncheckc() != -1) 27817658Sjulian break; 27917658Sjulian } 28017658Sjulian if (!loop) 28117658Sjulian goto die; 28217658Sjulian } 28317658Sjulian } else { /* zero time specified - reboot NOW */ 28417658Sjulian goto die; 28517658Sjulian } 28617658Sjulian printf("--> Press a key on the console to reboot <--\n"); 28717658Sjulian cngetc(); 28817658Sjulian } 28917658Sjulian } 29017658Sjuliandie: 29117658Sjulian printf("Rebooting...\n"); 29217658Sjulian DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 29317677Sjulian /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 29417658Sjulian cpu_reset(); 29517658Sjulian for(;;) ; 29617658Sjulian /* NOTREACHED */ 29717658Sjulian} 29817658Sjulian 29917658Sjulian/* 30017658Sjulian * Magic number for savecore 30117658Sjulian * 30217658Sjulian * exported (symorder) and used at least by savecore(8) 30317658Sjulian * 30417658Sjulian */ 30517658Sjulianstatic u_long const dumpmag = 0x8fca0101UL; 30617658Sjulian 30717658Sjulianstatic int dumpsize = 0; /* also for savecore */ 30817658Sjulian 30917658Sjulianstatic int dodump = 1; 31017658SjulianSYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, ""); 31117658Sjulian 31217658Sjulian/* 31317658Sjulian * Doadump comes here after turning off memory management and 31417658Sjulian * getting on the dump stack, either when called above, or by 31517658Sjulian * the auto-restart code. 31617658Sjulian */ 31717658Sjulianstatic void 31817658Sjuliandumpsys(void) 31917658Sjulian{ 32017658Sjulian 32117658Sjulian if (!dodump) 32217658Sjulian return; 32317658Sjulian if (dumpdev == NODEV) 32417658Sjulian return; 32517658Sjulian if ((minor(dumpdev)&07) != 1) 32617658Sjulian return; 32717658Sjulian if (!(bdevsw[major(dumpdev)])) 32817658Sjulian return; 32917658Sjulian if (!(bdevsw[major(dumpdev)]->d_dump)) 33017658Sjulian return; 33117658Sjulian dumpsize = Maxmem; 33217658Sjulian printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 33317658Sjulian printf("dump "); 33417658Sjulian switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) { 33517658Sjulian 33617658Sjulian case ENXIO: 33717658Sjulian printf("device bad\n"); 33817658Sjulian break; 33917658Sjulian 34017658Sjulian case EFAULT: 34117658Sjulian printf("device not ready\n"); 34217658Sjulian break; 34317658Sjulian 34417658Sjulian case EINVAL: 34517658Sjulian printf("area improper\n"); 34617658Sjulian break; 34717658Sjulian 34817658Sjulian case EIO: 34917658Sjulian printf("i/o error\n"); 35017658Sjulian break; 35117658Sjulian 35217658Sjulian case EINTR: 35317658Sjulian printf("aborted from console\n"); 35417658Sjulian break; 35517658Sjulian 35617658Sjulian default: 35717658Sjulian printf("succeeded\n"); 35817658Sjulian break; 35917658Sjulian } 36017658Sjulian} 36117658Sjulian 36217658Sjulian/* 36317658Sjulian * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 36417658Sjulian * and then reboots. If we are called twice, then we avoid trying to sync 36517658Sjulian * the disks as this often leads to recursive panics. 36617658Sjulian */ 36717658Sjulianvoid 36817658Sjulianpanic(const char *fmt, ...) 36917658Sjulian{ 37017658Sjulian int bootopt; 37117658Sjulian va_list ap; 37217658Sjulian 37317658Sjulian bootopt = RB_AUTOBOOT | RB_DUMP; 37417658Sjulian if (panicstr) 37517658Sjulian bootopt |= RB_NOSYNC; 37617658Sjulian else 37717658Sjulian panicstr = fmt; 37817658Sjulian 37925164Speter#ifdef SMP 38025164Speter printf("panic (cpu#%d): ", cpunumber()); 38125164Speter#else 38217658Sjulian printf("panic: "); 38325164Speter#endif 38417658Sjulian va_start(ap, fmt); 38517658Sjulian vprintf(fmt, ap); 38617658Sjulian va_end(ap); 38717658Sjulian printf("\n"); 38817658Sjulian 38917658Sjulian#if defined(DDB) 39017658Sjulian if (debugger_on_panic) 39117658Sjulian Debugger ("panic"); 39217658Sjulian#endif 39317658Sjulian boot(bootopt); 39417658Sjulian} 39517658Sjulian 39617768Sjulian/* 39717768Sjulian * Two routines to handle adding/deleting items on the 39817768Sjulian * shutdown callout lists 39917768Sjulian * 40017768Sjulian * at_shutdown(): 40117658Sjulian * Take the arguments given and put them onto the shutdown callout list. 40217658Sjulian * However first make sure that it's not already there. 40317658Sjulian * returns 0 on success. 40417658Sjulian */ 40517658Sjulianint 40617768Sjulianat_shutdown(bootlist_fn function, void *arg, int position) 40717658Sjulian{ 40817768Sjulian sle_p ep, *epp; 40917768Sjulian 41017768Sjulian switch(position) { 41117768Sjulian case SHUTDOWN_PRE_SYNC: 41217768Sjulian epp = &shutdown_list1; 41317768Sjulian break; 41417768Sjulian case SHUTDOWN_POST_SYNC: 41517768Sjulian epp = &shutdown_list2; 41617768Sjulian break; 41717768Sjulian default: 41817768Sjulian printf("bad exit callout list specified\n"); 41917768Sjulian return (EINVAL); 42017768Sjulian } 42117768Sjulian if (rm_at_shutdown(function, arg)) 42217658Sjulian printf("exit callout entry already present\n"); 42317768Sjulian ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 42417768Sjulian if (ep == NULL) 42517768Sjulian return (ENOMEM); 42617768Sjulian ep->next = *epp; 42717658Sjulian ep->function = function; 42817658Sjulian ep->arg = arg; 42917768Sjulian *epp = ep; 43017768Sjulian return (0); 43117658Sjulian} 43217768Sjulian 43317658Sjulian/* 43417768Sjulian * Scan the exit callout lists for the given items and remove them. 43517658Sjulian * Returns the number of items removed. 43617658Sjulian */ 43717658Sjulianint 43817658Sjulianrm_at_shutdown(bootlist_fn function, void *arg) 43917658Sjulian{ 44017768Sjulian sle_p *epp, ep; 44117768Sjulian int count; 44217658Sjulian 44317768Sjulian count = 0; 44417768Sjulian epp = &shutdown_list1; 44517658Sjulian ep = *epp; 44617768Sjulian while (ep) { 44717834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 44817658Sjulian *epp = ep->next; 44917768Sjulian free(ep, M_TEMP); 45017658Sjulian count++; 45117658Sjulian } else { 45217658Sjulian epp = &ep->next; 45317658Sjulian } 45417658Sjulian ep = *epp; 45517658Sjulian } 45617768Sjulian epp = &shutdown_list2; 45717768Sjulian ep = *epp; 45817768Sjulian while (ep) { 45917834Sjulian if ((ep->function == function) && (ep->arg == arg)) { 46017768Sjulian *epp = ep->next; 46117768Sjulian free(ep, M_TEMP); 46217768Sjulian count++; 46317768Sjulian } else { 46417768Sjulian epp = &ep->next; 46517768Sjulian } 46617768Sjulian ep = *epp; 46717768Sjulian } 46817768Sjulian return (count); 46917658Sjulian} 47017658Sjulian 471