The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_shutdown.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD$
   40  */
   41 
   42 #include "opt_ddb.h"
   43 #include "opt_hw_wdog.h"
   44 #include "opt_panic.h"
   45 #include "opt_show_busybufs.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/buf.h>
   50 #include <sys/reboot.h>
   51 #include <sys/proc.h>
   52 #include <sys/vnode.h>
   53 #include <sys/malloc.h>
   54 #include <sys/kernel.h>
   55 #include <sys/mount.h>
   56 #include <sys/queue.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/conf.h>
   59 #include <sys/sysproto.h>
   60 
   61 #include <machine/pcb.h>
   62 #include <machine/clock.h>
   63 #include <machine/cons.h>
   64 #include <machine/md_var.h>
   65 #ifdef SMP
   66 #include <machine/smp.h>                /* smp_active, cpuid */
   67 #endif
   68 
   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 #ifdef DDB
   82 #ifdef DDB_UNATTENDED
   83 int debugger_on_panic = 0;
   84 #else
   85 int debugger_on_panic = 1;
   86 #endif
   87 SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
   88         &debugger_on_panic, 0, "");
   89 #endif
   90 
   91 #ifdef  HW_WDOG
   92 /*
   93  * If there is a hardware watchdog, point this at the function needed to
   94  * hold it off.
   95  * It's needed when the kernel needs to do some lengthy operations.
   96  * e.g. in wd.c when dumping core.. It's most annoying to have
   97  * your precious core-dump only half written because the wdog kicked in.
   98  */
   99 watchdog_tickle_fn wdog_tickler = NULL;
  100 #endif  /* HW_WDOG */
  101 
  102 /*
  103  * Variable panicstr contains argument to first call to panic; used as flag
  104  * to indicate that the kernel has already called panic.
  105  */
  106 const char *panicstr;
  107 
  108 /*
  109  * callout list for things to do a shutdown
  110  */
  111 typedef struct shutdown_list_element {
  112         LIST_ENTRY(shutdown_list_element) links;
  113         bootlist_fn function;
  114         void *arg;
  115         int priority;
  116 } *sle_p;
  117 
  118 /*
  119  * There are three shutdown lists. Some things need to be shut down
  120  * earlier than others.
  121  */
  122 LIST_HEAD(shutdown_list, shutdown_list_element);
  123 
  124 static struct shutdown_list shutdown_lists[SHUTDOWN_FINAL + 1];
  125 
  126 static void boot __P((int)) __dead2;
  127 static void dumpsys __P((void));
  128 static void print_uptime __P((void));
  129 
  130 #ifndef _SYS_SYSPROTO_H_
  131 struct reboot_args {
  132         int     opt;
  133 };
  134 #endif
  135 /* ARGSUSED */
  136 
  137 /*
  138  * The system call that results in a reboot
  139  */
  140 int
  141 reboot(p, uap)
  142         struct proc *p;
  143         struct reboot_args *uap;
  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  */
  157 void
  158 shutdown_nice()
  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 }
  169 static int      waittime = -1;
  170 static struct pcb dumppcb;
  171 
  172 static void
  173 print_uptime()
  174 {
  175         int f;
  176         struct timespec ts;
  177 
  178         getnanouptime(&ts);
  179         printf("Uptime: ");
  180         f = 0;
  181         if (ts.tv_sec >= 86400) {
  182                 printf("%ldd", ts.tv_sec / 86400);
  183                 ts.tv_sec %= 86400;
  184                 f = 1;
  185         }
  186         if (f || ts.tv_sec >= 3600) {
  187                 printf("%ldh", ts.tv_sec / 3600);
  188                 ts.tv_sec %= 3600;
  189                 f = 1;
  190         }
  191         if (f || ts.tv_sec >= 60) {
  192                 printf("%ldm", ts.tv_sec / 60);
  193                 ts.tv_sec %= 60;
  194                 f = 1;
  195         }
  196         printf("%lds\n", ts.tv_sec);
  197 }
  198 
  199 /*
  200  *  Go through the rigmarole of shutting down..
  201  * this used to be in machdep.c but I'll be dammned if I could see
  202  * anything machine dependant in it.
  203  */
  204 static void
  205 boot(howto)
  206         int howto;
  207 {
  208         sle_p ep;
  209 
  210 #ifdef SMP
  211         if (smp_active) {
  212                 printf("boot() called on cpu#%d\n", cpuid);
  213         }
  214 #endif
  215         /*
  216          * Do any callouts that should be done BEFORE syncing the filesystems.
  217          */
  218         LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_PRE_SYNC], links)
  219                 (*ep->function)(howto, ep->arg);
  220 
  221         /* 
  222          * Now sync filesystems
  223          */
  224         if (!cold && (howto & RB_NOSYNC) == 0 && waittime < 0) {
  225                 register struct buf *bp;
  226                 int iter, nbusy;
  227 
  228                 waittime = 0;
  229                 printf("\nsyncing disks... ");
  230 
  231                 sync(&proc0, NULL);
  232 
  233                 /*
  234                  * With soft updates, some buffers that are
  235                  * written will be remarked as dirty until other
  236                  * buffers are written.
  237                  */
  238                 for (iter = 0; iter < 20; iter++) {
  239                         nbusy = 0;
  240                         for (bp = &buf[nbuf]; --bp >= buf; ) {
  241                                 if ((bp->b_flags & (B_BUSY | B_INVAL))
  242                                                 == B_BUSY) {
  243                                         nbusy++;
  244                                 } else if ((bp->b_flags & (B_DELWRI | B_INVAL))
  245                                                 == B_DELWRI) {
  246                                         /* bawrite(bp);*/
  247                                         nbusy++;
  248                                 }
  249                         }
  250                         if (nbusy == 0)
  251                                 break;
  252                         printf("%d ", nbusy);
  253                         sync(&proc0, NULL);
  254                         DELAY(50000 * iter);
  255                 }
  256                 /*
  257                  * Count only busy local buffers to prevent forcing 
  258                  * a fsck if we're just a client of a wedged NFS server
  259                  */
  260                 nbusy = 0;
  261                 for (bp = &buf[nbuf]; --bp >= buf; ) {
  262                         if (((bp->b_flags & (B_BUSY | B_INVAL)) == B_BUSY) 
  263                             ||((bp->b_flags & (B_DELWRI | B_INVAL))== B_DELWRI))
  264                                 if(bp->b_dev == NODEV)
  265                                         CIRCLEQ_REMOVE(&mountlist, bp->b_vp->v_mount, mnt_list);
  266                                 else
  267                                         nbusy++;
  268 
  269 
  270                 }
  271                 if (nbusy) {
  272                         /*
  273                          * Failed to sync all blocks. Indicate this and don't
  274                          * unmount filesystems (thus forcing an fsck on reboot).
  275                          */
  276                         printf("giving up\n");
  277 #ifdef SHOW_BUSYBUFS
  278                         nbusy = 0;
  279                         for (bp = &buf[nbuf]; --bp >= buf; ) {
  280                                 if ((bp->b_flags & (B_BUSY | B_INVAL))
  281                                                 == B_BUSY) {
  282                                         nbusy++;
  283                                         printf(
  284                         "%d: dev:%08lx, flags:%08lx, blkno:%ld, lblkno:%ld\n",
  285                                             nbusy, (u_long)bp->b_dev,
  286                                             bp->b_flags, (long)bp->b_blkno,
  287                                             (long)bp->b_lblkno);
  288                                 }
  289                         }
  290                         DELAY(5000000); /* 5 seconds */
  291 #endif
  292                 } else {
  293                         printf("done\n");
  294                         /*
  295                          * Unmount filesystems
  296                          */
  297                         if (panicstr == 0)
  298                                 vfs_unmountall();
  299                 }
  300                 DELAY(100000);          /* wait for console output to finish */
  301         }
  302 
  303         print_uptime();
  304 
  305         /*
  306          * Ok, now do things that assume all filesystem activity has
  307          * been completed.
  308          */
  309         LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_POST_SYNC], links)
  310                 (*ep->function)(howto, ep->arg);
  311         splhigh();
  312         if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold) {
  313                 savectx(&dumppcb);
  314 #ifdef __i386__
  315                 dumppcb.pcb_cr3 = rcr3();
  316 #endif
  317                 dumpsys();
  318         }
  319 
  320         /* Now that we're going to really halt the system... */
  321         LIST_FOREACH(ep, &shutdown_lists[SHUTDOWN_FINAL], links)
  322                 (*ep->function)(howto, ep->arg);
  323 
  324         if (howto & RB_HALT) {
  325                 printf("\n");
  326                 printf("The operating system has halted.\n");
  327                 printf("Please press any key to reboot.\n\n");
  328                 switch (cngetc()) {
  329                 case -1:                /* No console, just die */
  330                         cpu_halt();
  331                         /* NOTREACHED */
  332                 default:
  333                         howto &= ~RB_HALT;
  334                         break;
  335                 }
  336         } else if (howto & RB_DUMP) {
  337                 /* System Paniced */
  338 
  339                 if (PANIC_REBOOT_WAIT_TIME != 0) {
  340                         if (PANIC_REBOOT_WAIT_TIME != -1) {
  341                                 int loop;
  342                                 printf("Automatic reboot in %d seconds - "
  343                                        "press a key on the console to abort\n",
  344                                         PANIC_REBOOT_WAIT_TIME);
  345                                 for (loop = PANIC_REBOOT_WAIT_TIME * 10;
  346                                      loop > 0; --loop) {
  347                                         DELAY(1000 * 100); /* 1/10th second */
  348                                         /* Did user type a key? */
  349                                         if (cncheckc() != -1)
  350                                                 break;
  351                                 }
  352                                 if (!loop)
  353                                         goto die;
  354                         }
  355                 } else { /* zero time specified - reboot NOW */
  356                         goto die;
  357                 }
  358                 printf("--> Press a key on the console to reboot <--\n");
  359                 cngetc();
  360         }
  361 die:
  362         printf("Rebooting...\n");
  363         DELAY(1000000); /* wait 1 sec for printf's to complete and be read */
  364         /* cpu_boot(howto); */ /* doesn't do anything at the moment */
  365         cpu_reset();
  366         for(;;) ;
  367         /* NOTREACHED */
  368 }
  369 
  370 /*
  371  * Magic number for savecore
  372  *
  373  * exported (symorder) and used at least by savecore(8)
  374  *
  375  */
  376 static u_long const     dumpmag = 0x8fca0101UL; 
  377 
  378 static int      dumpsize = 0;           /* also for savecore */
  379 
  380 static int      dodump = 1;
  381 SYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0, "");
  382 
  383 /* ARGSUSED */
  384 static void dump_conf __P((void *dummy));
  385 static void
  386 dump_conf(dummy)
  387         void *dummy;
  388 {
  389         cpu_dumpconf();
  390 }
  391 SYSINIT(dump_conf, SI_SUB_DUMP_CONF, SI_ORDER_FIRST, dump_conf, NULL)
  392 
  393 /*
  394  * Doadump comes here after turning off memory management and
  395  * getting on the dump stack, either when called above, or by
  396  * the auto-restart code.
  397  */
  398 static void
  399 dumpsys(void)
  400 {
  401 
  402         if (!dodump)
  403                 return;
  404         if (dumpdev == NODEV)
  405                 return;
  406         if (!(bdevsw[major(dumpdev)]))
  407                 return;
  408         if (!(bdevsw[major(dumpdev)]->d_dump))
  409                 return;
  410         dumpsize = Maxmem;
  411         printf("\ndumping to dev %lx, offset %ld\n", (u_long)dumpdev, dumplo);
  412         printf("dump ");
  413         switch ((*bdevsw[major(dumpdev)]->d_dump)(dumpdev)) {
  414 
  415         case ENXIO:
  416                 printf("device bad\n");
  417                 break;
  418 
  419         case EFAULT:
  420                 printf("device not ready\n");
  421                 break;
  422 
  423         case EINVAL:
  424                 printf("area improper\n");
  425                 break;
  426 
  427         case EIO:
  428                 printf("i/o error\n");
  429                 break;
  430 
  431         case EINTR:
  432                 printf("aborted from console\n");
  433                 break;
  434 
  435         default:
  436                 printf("succeeded\n");
  437                 break;
  438         }
  439 }
  440 
  441 /*
  442  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
  443  * and then reboots.  If we are called twice, then we avoid trying to sync
  444  * the disks as this often leads to recursive panics.
  445  */
  446 void
  447 panic(const char *fmt, ...)
  448 {
  449         int bootopt;
  450         va_list ap;
  451         static char buf[256];
  452 
  453         bootopt = RB_AUTOBOOT | RB_DUMP;
  454         if (panicstr)
  455                 bootopt |= RB_NOSYNC;
  456         else
  457                 panicstr = fmt;
  458 
  459         va_start(ap, fmt);
  460         (void)vsnprintf(buf, sizeof(buf), fmt, ap);
  461         if (panicstr == fmt)
  462                 panicstr = buf;
  463         va_end(ap);
  464         printf("panic: %s\n", buf);
  465 #ifdef SMP
  466         /* three seperate prints in case of an unmapped page and trap */
  467         printf("mp_lock = %08x; ", mp_lock);
  468         printf("cpuid = %d; ", cpuid);
  469         printf("lapic.id = %08x\n", lapic.id);
  470 #endif
  471 
  472 #if defined(DDB)
  473         if (debugger_on_panic)
  474                 Debugger ("panic");
  475 #endif
  476         boot(bootopt);
  477 }
  478 
  479 /*
  480  * Three routines to handle adding/deleting items on the
  481  * shutdown callout lists
  482  *
  483  * at_shutdown():
  484  * Take the arguments given and put them onto the shutdown callout list.
  485  * However first make sure that it's not already there.
  486  * returns 0 on success.
  487  */
  488 int
  489 at_shutdown(bootlist_fn function, void *arg, int queue)
  490 {
  491         return(at_shutdown_pri(function, arg, queue, SHUTDOWN_PRI_DEFAULT));
  492 }
  493 
  494 /*
  495  * at_shutdown_pri():
  496  * Take the arguments given and put them onto the shutdown callout list
  497  * with the given execution priority.
  498  * returns 0 on success.
  499  */
  500 int
  501 at_shutdown_pri(bootlist_fn function, void *arg, int queue, int pri)
  502 {
  503         sle_p ep, ip;
  504 
  505         if (queue < SHUTDOWN_PRE_SYNC
  506          || queue > SHUTDOWN_FINAL) {
  507                 printf("at_shutdown: bad exit callout queue %d specified\n",
  508                        queue);
  509                 return (EINVAL);
  510         }
  511         if (rm_at_shutdown(function, arg))
  512                 printf("at_shutdown: exit callout entry was already present\n");
  513         ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT);
  514         if (ep == NULL)
  515                 return (ENOMEM);
  516         ep->function = function;
  517         ep->arg = arg;
  518         ep->priority = pri;
  519 
  520         /* Sort into list of items on this queue */
  521         ip = LIST_FIRST(&shutdown_lists[queue]);
  522         if (ip == NULL) {
  523                 LIST_INSERT_HEAD(&shutdown_lists[queue], ep, links);
  524         } else {
  525                 for (; LIST_NEXT(ip, links) != NULL; ip = LIST_NEXT(ip, links)) {
  526                         if (ep->priority < ip->priority) {
  527                                 LIST_INSERT_BEFORE(ip, ep, links);
  528                                 ep = NULL;
  529                                 break;
  530                         }
  531                 }
  532                 if (ep != NULL)
  533                         LIST_INSERT_AFTER(ip, ep, links);
  534         }
  535         return (0);
  536 }
  537 
  538 /*
  539  * Scan the exit callout lists for the given items and remove them.
  540  * Returns the number of items removed.
  541  */
  542 int
  543 rm_at_shutdown(bootlist_fn function, void *arg)
  544 {
  545         sle_p ep;
  546         int   count;
  547         int   queue;
  548 
  549         count = 0;
  550         for (queue = SHUTDOWN_PRE_SYNC; queue < SHUTDOWN_FINAL; queue++) {
  551                 LIST_FOREACH(ep, &shutdown_lists[queue], links) {
  552                         if ((ep->function == function) && (ep->arg == arg)) {
  553                                 LIST_REMOVE(ep, links);
  554                                 free(ep, M_TEMP);
  555                                 count++;
  556                         }
  557                 }
  558         }
  559         return (count);
  560 }

Cache object: 1f27576b6be01f142143cb86e1c49fa8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.