kern_shutdown.c revision 28000
1/*- 2 * Copyright (c) 1986, 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 39 * $Id: kern_shutdown.c,v 1.18 1997/08/09 01:25:53 julian Exp $ 40 */ 41 42#include "opt_ddb.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/reboot.h> 47#include <sys/msgbuf.h> 48#include <sys/proc.h> 49#include <sys/vnode.h> 50#include <sys/tty.h> 51#include <sys/tprintf.h> 52#include <sys/syslog.h> 53#include <sys/malloc.h> 54#include <sys/kernel.h> 55#include <sys/mount.h> 56#include <sys/sysctl.h> 57#include <sys/conf.h> 58#include <sys/sysproto.h> 59 60#include <machine/pcb.h> 61#include <machine/clock.h> 62#include <machine/cons.h> 63#include <machine/md_var.h> 64#ifdef SMP 65#include <machine/smp.h> /* smp_active, cpuid */ 66#endif 67 68#include <sys/utsname.h> 69#include <sys/signalvar.h> 70 71#ifndef PANIC_REBOOT_WAIT_TIME 72#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 73#endif 74 75/* 76 * Note that stdarg.h and the ANSI style va_start macro is used for both 77 * ANSI and traditional C compilers. 78 */ 79#include <machine/stdarg.h> 80 81#if defined(DDB) 82#ifdef DDB_UNATTENDED 83 static int debugger_on_panic = 0; 84#else 85 static int debugger_on_panic = 1; 86#endif 87 88SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, 89 &debugger_on_panic, 0, ""); 90#endif 91 92 93#ifdef HW_WDOG 94/* 95 * If there is a hardware watchdog, point this at the function needed to 96 * hold it off. 97 * It's needed when the kernel needs to do some lengthy operations. 98 * e.g. in wd.c when dumping core.. It's most annoying to have 99 * your precious core-dump only half written because the wdog kicked in. 100 */ 101watchdog_tickle_fn wdog_tickler = NULL; 102#endif /* HW_WDOG */ 103 104/* 105 * Variable panicstr contains argument to first call to panic; used as flag 106 * to indicate that the kernel has already called panic. 107 */ 108const char *panicstr; 109 110/* 111 * callout list for things to do a shutdown 112 */ 113typedef struct shutdown_list_element { 114 struct shutdown_list_element *next; 115 bootlist_fn function; 116 void *arg; 117} *sle_p; 118 119/* 120 * there are two shutdown lists. Some things need to be shut down 121 * Earlier than others. 122 */ 123static sle_p shutdown_list1; 124static sle_p shutdown_list2; 125 126 127static void dumpsys(void); 128 129#ifndef _SYS_SYSPROTO_H_ 130struct reboot_args { 131 int opt; 132}; 133#endif 134/* ARGSUSED */ 135 136/* 137 * The system call that results in a reboot 138 */ 139int 140reboot(p, uap, retval) 141 struct proc *p; 142 struct reboot_args *uap; 143 int *retval; 144{ 145 int error; 146 147 if ((error = suser(p->p_ucred, &p->p_acflag))) 148 return (error); 149 150 boot(uap->opt); 151 return (0); 152} 153 154/* 155 * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 156 */ 157void 158shutdown_nice(void) 159{ 160 /* Send a signal to init(8) and have it shutdown the world */ 161 if (initproc != NULL) { 162 psignal(initproc, SIGINT); 163 } else { 164 /* No init(8) running, so simply reboot */ 165 boot(RB_NOSYNC); 166 } 167 return; 168} 169static int waittime = -1; 170static struct pcb dumppcb; 171 172/* 173 * Go through the rigmarole of shutting down.. 174 * this used to be in machdep.c but I'll be dammned if I could see 175 * anything machine dependant in it. 176 */ 177void 178boot(howto) 179 int howto; 180{ 181 sle_p ep; 182 183#ifdef SMP 184 int c, spins; 185 186 /* don't accidently start it */ 187 if (smp_active) { 188 smp_active = 1; 189 190 spins = 100; 191 192 printf("boot() called on cpu#%d\n", cpuid); 193 while ((c = cpuid) != 0) { 194 if (spins-- < 1) { 195 printf("timeout waiting for cpu #0!\n"); 196 break; 197 } 198 printf("oops, I'm on cpu#%d, I need to be on cpu#0!\n", 199 c); 200 tsleep((caddr_t)&smp_active, PZERO, "cpu0wt", 10); 201 } 202 } 203#endif 204 /* 205 * Do any callouts that should be done BEFORE syncing the filesystems. 206 */ 207 ep = shutdown_list1; 208 while (ep) { 209 shutdown_list1 = ep->next; 210 (*ep->function)(howto, ep->arg); 211 ep = ep->next; 212 } 213 214 /* 215 * Now sync filesystems 216 */ 217 if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) { 218 register struct buf *bp; 219 int iter, nbusy; 220 221 waittime = 0; 222 printf("\nsyncing disks... "); 223 224 sync(&proc0, NULL, NULL); 225 226 for (iter = 0; iter < 20; iter++) { 227 nbusy = 0; 228 for (bp = &buf[nbuf]; --bp >= buf; ) { 229 if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 230 nbusy++; 231 } 232 } 233 if (nbusy == 0) 234 break; 235 printf("%d ", nbusy); 236 DELAY(40000 * iter); 237 } 238 if (nbusy) { 239 /* 240 * Failed to sync all blocks. Indicate this and don't 241 * unmount filesystems (thus forcing an fsck on reboot). 242 */ 243 printf("giving up\n"); 244#ifdef SHOW_BUSYBUFS 245 nbusy = 0; 246 for (bp = &buf[nbuf]; --bp >= buf; ) { 247 if ((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) { 248 nbusy++; 249 printf("%d: dev:%08x, flags:%08x, blkno:%d, lblkno:%d\n", nbusy, bp->b_dev, bp->b_flags, bp->b_blkno, bp->b_lblkno); 250 } 251 } 252 DELAY(5000000); /* 5 seconds */ 253#endif 254 } else { 255 printf("done\n"); 256 /* 257 * Unmount filesystems 258 */ 259 if (panicstr == 0) 260 vfs_unmountall(); 261 } 262 DELAY(100000); /* wait for console output to finish */ 263 } 264 265 /* 266 * Ok, now do things that assume all filesystem activity has 267 * been completed. 268 */ 269 ep = shutdown_list2; 270 while (ep) { 271 shutdown_list2 = ep->next; 272 (*ep->function)(howto, ep->arg); 273 ep = ep->next; 274 } 275 splhigh(); 276 if (howto & RB_HALT) { 277 cpu_power_down(); 278 printf("\n"); 279 printf("The operating system has halted.\n"); 280 printf("Please press any key to reboot.\n\n"); 281 switch (cngetc()) { 282 case -1: /* No console, just die */ 283 cpu_halt(); 284 /* NOTREACHED */ 285 default: 286 break; 287 } 288 } else { 289 if (howto & RB_DUMP) { 290 if (!cold) { 291 savectx(&dumppcb); 292 dumppcb.pcb_cr3 = rcr3(); 293 dumpsys(); 294 } 295 296 if (PANIC_REBOOT_WAIT_TIME != 0) { 297 if (PANIC_REBOOT_WAIT_TIME != -1) { 298 int loop; 299 printf("Automatic reboot in %d seconds - press a key on the console to abort\n", 300 PANIC_REBOOT_WAIT_TIME); 301 for (loop = PANIC_REBOOT_WAIT_TIME * 10; loop > 0; --loop) { 302 DELAY(1000 * 100); /* 1/10th second */ 303 /* Did user type a key? */ 304 if (cncheckc() != -1) 305 break; 306 } 307 if (!loop) 308 goto die; 309 } 310 } else { /* zero time specified - reboot NOW */ 311 goto die; 312 } 313 printf("--> Press a key on the console to reboot <--\n"); 314 cngetc(); 315 } 316 } 317die: 318 printf("Rebooting...\n"); 319 DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 320 /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 321 cpu_reset(); 322 for(;;) ; 323 /* NOTREACHED */ 324} 325 326/* 327 * Magic number for savecore 328 * 329 * exported (symorder) and used at least by savecore(8) 330 * 331 */ 332static u_long const dumpmag = 0x8fca0101UL; 333 334static int dumpsize = 0; /* also for savecore */ 335 336static int dodump = 1; 337SYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, ""); 338 339/* 340 * Doadump comes here after turning off memory management and 341 * getting on the dump stack, either when called above, or by 342 * the auto-restart code. 343 */ 344static void 345dumpsys(void) 346{ 347 348 if (!dodump) 349 return; 350 if (dumpdev == NODEV) 351 return; 352 if ((minor(dumpdev)&07) != 1) 353 return; 354 if (!(bdevsw[major(dumpdev)])) 355 return; 356 if (!(bdevsw[major(dumpdev)]->d_dump)) 357 return; 358 dumpsize = Maxmem; 359 printf("\ndumping to dev %lx, offset %ld\n", dumpdev, dumplo); 360 printf("dump "); 361 switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) { 362 363 case ENXIO: 364 printf("device bad\n"); 365 break; 366 367 case EFAULT: 368 printf("device not ready\n"); 369 break; 370 371 case EINVAL: 372 printf("area improper\n"); 373 break; 374 375 case EIO: 376 printf("i/o error\n"); 377 break; 378 379 case EINTR: 380 printf("aborted from console\n"); 381 break; 382 383 default: 384 printf("succeeded\n"); 385 break; 386 } 387} 388 389/* 390 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 391 * and then reboots. If we are called twice, then we avoid trying to sync 392 * the disks as this often leads to recursive panics. 393 */ 394void 395panic(const char *fmt, ...) 396{ 397 int bootopt; 398 va_list ap; 399 400 bootopt = RB_AUTOBOOT | RB_DUMP; 401 if (panicstr) 402 bootopt |= RB_NOSYNC; 403 else 404 panicstr = fmt; 405 406 printf("panic: "); 407 va_start(ap, fmt); 408 vprintf(fmt, ap); 409 va_end(ap); 410 printf("\n"); 411#ifdef SMP 412 printf(" cpuid %d\n", cpuid); 413#endif 414 415#if defined(DDB) 416 if (debugger_on_panic) 417 Debugger ("panic"); 418#endif 419 boot(bootopt); 420} 421 422/* 423 * Two routines to handle adding/deleting items on the 424 * shutdown callout lists 425 * 426 * at_shutdown(): 427 * Take the arguments given and put them onto the shutdown callout list. 428 * However first make sure that it's not already there. 429 * returns 0 on success. 430 */ 431int 432at_shutdown(bootlist_fn function, void *arg, int position) 433{ 434 sle_p ep, *epp; 435 436 switch(position) { 437 case SHUTDOWN_PRE_SYNC: 438 epp = &shutdown_list1; 439 break; 440 case SHUTDOWN_POST_SYNC: 441 epp = &shutdown_list2; 442 break; 443 default: 444 printf("bad exit callout list specified\n"); 445 return (EINVAL); 446 } 447 if (rm_at_shutdown(function, arg)) 448 printf("exit callout entry already present\n"); 449 ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 450 if (ep == NULL) 451 return (ENOMEM); 452 ep->next = *epp; 453 ep->function = function; 454 ep->arg = arg; 455 *epp = ep; 456 return (0); 457} 458 459/* 460 * Scan the exit callout lists for the given items and remove them. 461 * Returns the number of items removed. 462 */ 463int 464rm_at_shutdown(bootlist_fn function, void *arg) 465{ 466 sle_p *epp, ep; 467 int count; 468 469 count = 0; 470 epp = &shutdown_list1; 471 ep = *epp; 472 while (ep) { 473 if ((ep->function == function) && (ep->arg == arg)) { 474 *epp = ep->next; 475 free(ep, M_TEMP); 476 count++; 477 } else { 478 epp = &ep->next; 479 } 480 ep = *epp; 481 } 482 epp = &shutdown_list2; 483 ep = *epp; 484 while (ep) { 485 if ((ep->function == function) && (ep->arg == arg)) { 486 *epp = ep->next; 487 free(ep, M_TEMP); 488 count++; 489 } else { 490 epp = &ep->next; 491 } 492 ep = *epp; 493 } 494 return (count); 495} 496 497