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_subr.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 /*      $NetBSD: kern_subr.c,v 1.109 2004/03/23 13:22:33 junyoung Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center, and by Luke Mewburn.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Copyright (c) 1982, 1986, 1991, 1993
   42  *      The Regents of the University of California.  All rights reserved.
   43  * (c) UNIX System Laboratories, Inc.
   44  * All or some portions of this file are derived from material licensed
   45  * to the University of California by American Telephone and Telegraph
   46  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   47  * the permission of UNIX System Laboratories, Inc.
   48  *
   49  * Copyright (c) 1992, 1993
   50  *      The Regents of the University of California.  All rights reserved.
   51  *
   52  * This software was developed by the Computer Systems Engineering group
   53  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   54  * contributed to Berkeley.
   55  *
   56  * All advertising materials mentioning features or use of this software
   57  * must display the following acknowledgement:
   58  *      This product includes software developed by the University of
   59  *      California, Lawrence Berkeley Laboratory.
   60  *
   61  * Redistribution and use in source and binary forms, with or without
   62  * modification, are permitted provided that the following conditions
   63  * are met:
   64  * 1. Redistributions of source code must retain the above copyright
   65  *    notice, this list of conditions and the following disclaimer.
   66  * 2. Redistributions in binary form must reproduce the above copyright
   67  *    notice, this list of conditions and the following disclaimer in the
   68  *    documentation and/or other materials provided with the distribution.
   69  * 3. Neither the name of the University nor the names of its contributors
   70  *    may be used to endorse or promote products derived from this software
   71  *    without specific prior written permission.
   72  *
   73  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   74  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   75  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   76  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   77  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   78  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   79  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   80  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   81  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   82  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   83  * SUCH DAMAGE.
   84  *
   85  *      @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
   86  */
   87 
   88 #include <sys/cdefs.h>
   89 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.109 2004/03/23 13:22:33 junyoung Exp $");
   90 
   91 #include "opt_ddb.h"
   92 #include "opt_md.h"
   93 #include "opt_syscall_debug.h"
   94 #include "opt_ktrace.h"
   95 #include "opt_systrace.h"
   96 
   97 #include <sys/param.h>
   98 #include <sys/systm.h>
   99 #include <sys/proc.h>
  100 #include <sys/malloc.h>
  101 #include <sys/mount.h>
  102 #include <sys/device.h>
  103 #include <sys/reboot.h>
  104 #include <sys/conf.h>
  105 #include <sys/disklabel.h>
  106 #include <sys/queue.h>
  107 #include <sys/systrace.h>
  108 #include <sys/ktrace.h>
  109 
  110 #include <uvm/uvm_extern.h>
  111 
  112 #include <dev/cons.h>
  113 
  114 #include <net/if.h>
  115 
  116 /* XXX these should eventually move to subr_autoconf.c */
  117 static struct device *finddevice(const char *);
  118 static struct device *getdisk(char *, int, int, dev_t *, int);
  119 static struct device *parsedisk(char *, int, int, dev_t *);
  120 
  121 /*
  122  * A generic linear hook.
  123  */
  124 struct hook_desc {
  125         LIST_ENTRY(hook_desc) hk_list;
  126         void    (*hk_fn)(void *);
  127         void    *hk_arg;
  128 };
  129 typedef LIST_HEAD(, hook_desc) hook_list_t;
  130 
  131 static void *hook_establish(hook_list_t *, void (*)(void *), void *);
  132 static void hook_disestablish(hook_list_t *, void *);
  133 static void hook_destroy(hook_list_t *);
  134 static void hook_proc_run(hook_list_t *, struct proc *);
  135 
  136 MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  137 
  138 int
  139 uiomove(buf, n, uio)
  140         void *buf;
  141         size_t n;
  142         struct uio *uio;
  143 {
  144         struct iovec *iov;
  145         u_int cnt;
  146         int error = 0;
  147         char *cp = buf;
  148         struct proc *p = uio->uio_procp;
  149 
  150 #ifdef DIAGNOSTIC
  151         if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
  152                 panic("uiomove: mode");
  153 #endif
  154         while (n > 0 && uio->uio_resid) {
  155                 iov = uio->uio_iov;
  156                 cnt = iov->iov_len;
  157                 if (cnt == 0) {
  158                         KASSERT(uio->uio_iovcnt > 0);
  159                         uio->uio_iov++;
  160                         uio->uio_iovcnt--;
  161                         continue;
  162                 }
  163                 if (cnt > n)
  164                         cnt = n;
  165                 switch (uio->uio_segflg) {
  166 
  167                 case UIO_USERSPACE:
  168                         if (curcpu()->ci_schedstate.spc_flags &
  169                             SPCF_SHOULDYIELD)
  170                                 preempt(1);
  171                         if (__predict_true(p == curproc)) {
  172                                 if (uio->uio_rw == UIO_READ)
  173                                         error = copyout(cp, iov->iov_base, cnt);
  174                                 else
  175                                         error = copyin(iov->iov_base, cp, cnt);
  176                         } else {
  177                                 if (uio->uio_rw == UIO_READ)
  178                                         error = copyout_proc(p, cp,
  179                                             iov->iov_base, cnt);
  180                                 else
  181                                         error = copyin_proc(p, iov->iov_base,
  182                                             cp, cnt);
  183                         }
  184                         if (error)
  185                                 return (error);
  186                         break;
  187 
  188                 case UIO_SYSSPACE:
  189                         if (uio->uio_rw == UIO_READ)
  190                                 error = kcopy(cp, iov->iov_base, cnt);
  191                         else
  192                                 error = kcopy(iov->iov_base, cp, cnt);
  193                         if (error)
  194                                 return (error);
  195                         break;
  196                 }
  197                 iov->iov_base = (caddr_t)iov->iov_base + cnt;
  198                 iov->iov_len -= cnt;
  199                 uio->uio_resid -= cnt;
  200                 uio->uio_offset += cnt;
  201                 cp += cnt;
  202                 KDASSERT(cnt <= n);
  203                 n -= cnt;
  204         }
  205         return (error);
  206 }
  207 
  208 /*
  209  * Give next character to user as result of read.
  210  */
  211 int
  212 ureadc(c, uio)
  213         int c;
  214         struct uio *uio;
  215 {
  216         struct iovec *iov;
  217 
  218         if (uio->uio_resid <= 0)
  219                 panic("ureadc: non-positive resid");
  220 again:
  221         if (uio->uio_iovcnt <= 0)
  222                 panic("ureadc: non-positive iovcnt");
  223         iov = uio->uio_iov;
  224         if (iov->iov_len <= 0) {
  225                 uio->uio_iovcnt--;
  226                 uio->uio_iov++;
  227                 goto again;
  228         }
  229         switch (uio->uio_segflg) {
  230 
  231         case UIO_USERSPACE:
  232                 if (subyte(iov->iov_base, c) < 0)
  233                         return (EFAULT);
  234                 break;
  235 
  236         case UIO_SYSSPACE:
  237                 *(char *)iov->iov_base = c;
  238                 break;
  239         }
  240         iov->iov_base = (caddr_t)iov->iov_base + 1;
  241         iov->iov_len--;
  242         uio->uio_resid--;
  243         uio->uio_offset++;
  244         return (0);
  245 }
  246 
  247 /*
  248  * Like copyin(), but operates on an arbitrary process.
  249  */
  250 int
  251 copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len)
  252 {
  253         struct iovec iov;
  254         struct uio uio;
  255         int error;
  256 
  257         if (len == 0)
  258                 return (0);
  259 
  260         iov.iov_base = kaddr;
  261         iov.iov_len = len;
  262         uio.uio_iov = &iov;
  263         uio.uio_iovcnt = 1;
  264         uio.uio_offset = (off_t)(intptr_t)uaddr;
  265         uio.uio_resid = len;
  266         uio.uio_segflg = UIO_SYSSPACE;
  267         uio.uio_rw = UIO_READ;
  268         uio.uio_procp = NULL;
  269 
  270         /* XXXCDC: how should locking work here? */
  271         if ((p->p_flag & P_WEXIT) || (p->p_vmspace->vm_refcnt < 1))
  272                 return (EFAULT);
  273         p->p_vmspace->vm_refcnt++;      /* XXX */
  274         error = uvm_io(&p->p_vmspace->vm_map, &uio);
  275         uvmspace_free(p->p_vmspace);
  276 
  277         return (error);
  278 }
  279 
  280 /*
  281  * Like copyout(), but operates on an arbitrary process.
  282  */
  283 int
  284 copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len)
  285 {
  286         struct iovec iov;
  287         struct uio uio;
  288         int error;
  289 
  290         if (len == 0)
  291                 return (0);
  292 
  293         iov.iov_base = (void *) kaddr;  /* XXX cast away const */
  294         iov.iov_len = len;
  295         uio.uio_iov = &iov;
  296         uio.uio_iovcnt = 1;
  297         uio.uio_offset = (off_t)(intptr_t)uaddr;
  298         uio.uio_resid = len;
  299         uio.uio_segflg = UIO_SYSSPACE;
  300         uio.uio_rw = UIO_WRITE;
  301         uio.uio_procp = NULL;
  302 
  303         /* XXXCDC: how should locking work here? */
  304         if ((p->p_flag & P_WEXIT) || (p->p_vmspace->vm_refcnt < 1))
  305                 return (EFAULT);
  306         p->p_vmspace->vm_refcnt++;      /* XXX */
  307         error = uvm_io(&p->p_vmspace->vm_map, &uio);
  308         uvmspace_free(p->p_vmspace);
  309 
  310         return (error);
  311 }
  312 
  313 /*
  314  * General routine to allocate a hash table.
  315  * Allocate enough memory to hold at least `elements' list-head pointers.
  316  * Return a pointer to the allocated space and set *hashmask to a pattern
  317  * suitable for masking a value to use as an index into the returned array.
  318  */
  319 void *
  320 hashinit(elements, htype, mtype, mflags, hashmask)
  321         u_int elements;
  322         enum hashtype htype;
  323         struct malloc_type *mtype;
  324         int mflags;
  325         u_long *hashmask;
  326 {
  327         u_long hashsize, i;
  328         LIST_HEAD(, generic) *hashtbl_list;
  329         TAILQ_HEAD(, generic) *hashtbl_tailq;
  330         size_t esize;
  331         void *p;
  332 
  333         if (elements == 0)
  334                 panic("hashinit: bad cnt");
  335         for (hashsize = 1; hashsize < elements; hashsize <<= 1)
  336                 continue;
  337 
  338         switch (htype) {
  339         case HASH_LIST:
  340                 esize = sizeof(*hashtbl_list);
  341                 break;
  342         case HASH_TAILQ:
  343                 esize = sizeof(*hashtbl_tailq);
  344                 break;
  345         default:
  346 #ifdef DIAGNOSTIC
  347                 panic("hashinit: invalid table type");
  348 #else
  349                 return NULL;
  350 #endif
  351         }
  352 
  353         if ((p = malloc(hashsize * esize, mtype, mflags)) == NULL)
  354                 return (NULL);
  355 
  356         switch (htype) {
  357         case HASH_LIST:
  358                 hashtbl_list = p;
  359                 for (i = 0; i < hashsize; i++)
  360                         LIST_INIT(&hashtbl_list[i]);
  361                 break;
  362         case HASH_TAILQ:
  363                 hashtbl_tailq = p;
  364                 for (i = 0; i < hashsize; i++)
  365                         TAILQ_INIT(&hashtbl_tailq[i]);
  366                 break;
  367         }
  368         *hashmask = hashsize - 1;
  369         return (p);
  370 }
  371 
  372 /*
  373  * Free memory from hash table previosly allocated via hashinit().
  374  */
  375 void
  376 hashdone(hashtbl, mtype)
  377         void *hashtbl;
  378         struct malloc_type *mtype;
  379 {
  380 
  381         free(hashtbl, mtype);
  382 }
  383 
  384 
  385 static void *
  386 hook_establish(list, fn, arg)
  387         hook_list_t *list;
  388         void (*fn)(void *);
  389         void *arg;
  390 {
  391         struct hook_desc *hd;
  392 
  393         hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
  394         if (hd == NULL)
  395                 return (NULL);
  396 
  397         hd->hk_fn = fn;
  398         hd->hk_arg = arg;
  399         LIST_INSERT_HEAD(list, hd, hk_list);
  400 
  401         return (hd);
  402 }
  403 
  404 static void
  405 hook_disestablish(list, vhook)
  406         hook_list_t *list;
  407         void *vhook;
  408 {
  409 #ifdef DIAGNOSTIC
  410         struct hook_desc *hd;
  411 
  412         LIST_FOREACH(hd, list, hk_list) {
  413                 if (hd == vhook)
  414                         break;
  415         }
  416 
  417         if (hd == NULL)
  418                 panic("hook_disestablish: hook %p not established", vhook);
  419 #endif
  420         LIST_REMOVE((struct hook_desc *)vhook, hk_list);
  421         free(vhook, M_DEVBUF);
  422 }
  423 
  424 static void
  425 hook_destroy(list)
  426         hook_list_t *list;
  427 {
  428         struct hook_desc *hd;
  429 
  430         while ((hd = LIST_FIRST(list)) != NULL) {
  431                 LIST_REMOVE(hd, hk_list);
  432                 free(hd, M_DEVBUF);
  433         }
  434 }
  435 
  436 static void
  437 hook_proc_run(list, p)
  438         hook_list_t *list;
  439         struct proc *p;
  440 {
  441         struct hook_desc *hd;
  442 
  443         for (hd = LIST_FIRST(list); hd != NULL; hd = LIST_NEXT(hd, hk_list)) {
  444                 ((void (*)(struct proc *, void *))*hd->hk_fn)(p,
  445                     hd->hk_arg);
  446         }
  447 }
  448 
  449 /*
  450  * "Shutdown hook" types, functions, and variables.
  451  *
  452  * Should be invoked immediately before the
  453  * system is halted or rebooted, i.e. after file systems unmounted,
  454  * after crash dump done, etc.
  455  *
  456  * Each shutdown hook is removed from the list before it's run, so that
  457  * it won't be run again.
  458  */
  459 
  460 hook_list_t shutdownhook_list;
  461 
  462 void *
  463 shutdownhook_establish(fn, arg)
  464         void (*fn)(void *);
  465         void *arg;
  466 {
  467         return hook_establish(&shutdownhook_list, fn, arg);
  468 }
  469 
  470 void
  471 shutdownhook_disestablish(vhook)
  472         void *vhook;
  473 {
  474         hook_disestablish(&shutdownhook_list, vhook);
  475 }
  476 
  477 /*
  478  * Run shutdown hooks.  Should be invoked immediately before the
  479  * system is halted or rebooted, i.e. after file systems unmounted,
  480  * after crash dump done, etc.
  481  *
  482  * Each shutdown hook is removed from the list before it's run, so that
  483  * it won't be run again.
  484  */
  485 void
  486 doshutdownhooks()
  487 {
  488         struct hook_desc *dp;
  489 
  490         while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
  491                 LIST_REMOVE(dp, hk_list);
  492                 (*dp->hk_fn)(dp->hk_arg);
  493 #if 0
  494                 /*
  495                  * Don't bother freeing the hook structure,, since we may
  496                  * be rebooting because of a memory corruption problem,
  497                  * and this might only make things worse.  It doesn't
  498                  * matter, anyway, since the system is just about to
  499                  * reboot.
  500                  */
  501                 free(dp, M_DEVBUF);
  502 #endif
  503         }
  504 }
  505 
  506 /*
  507  * "Mountroot hook" types, functions, and variables.
  508  */
  509 
  510 hook_list_t mountroothook_list;
  511 
  512 void *
  513 mountroothook_establish(fn, dev)
  514         void (*fn)(struct device *);
  515         struct device *dev;
  516 {
  517         return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev);
  518 }
  519 
  520 void
  521 mountroothook_disestablish(vhook)
  522         void *vhook;
  523 {
  524         hook_disestablish(&mountroothook_list, vhook);
  525 }
  526 
  527 void
  528 mountroothook_destroy()
  529 {
  530         hook_destroy(&mountroothook_list);
  531 }
  532 
  533 void
  534 domountroothook()
  535 {
  536         struct hook_desc *hd;
  537 
  538         LIST_FOREACH(hd, &mountroothook_list, hk_list) {
  539                 if (hd->hk_arg == (void *)root_device) {
  540                         (*hd->hk_fn)(hd->hk_arg);
  541                         return;
  542                 }
  543         }
  544 }
  545 
  546 hook_list_t exechook_list;
  547 
  548 void *
  549 exechook_establish(fn, arg)
  550         void (*fn)(struct proc *, void *);
  551         void *arg;
  552 {
  553         return hook_establish(&exechook_list, (void (*)(void *))fn, arg);
  554 }
  555 
  556 void
  557 exechook_disestablish(vhook)
  558         void *vhook;
  559 {
  560         hook_disestablish(&exechook_list, vhook);
  561 }
  562 
  563 /*
  564  * Run exec hooks.
  565  */
  566 void
  567 doexechooks(p)
  568         struct proc *p;
  569 {
  570         hook_proc_run(&exechook_list, p);
  571 }
  572 
  573 hook_list_t exithook_list;
  574 
  575 void *
  576 exithook_establish(fn, arg)
  577         void (*fn)(struct proc *, void *);
  578         void *arg;
  579 {
  580         return hook_establish(&exithook_list, (void (*)(void *))fn, arg);
  581 }
  582 
  583 void
  584 exithook_disestablish(vhook)
  585         void *vhook;
  586 {
  587         hook_disestablish(&exithook_list, vhook);
  588 }
  589 
  590 /*
  591  * Run exit hooks.
  592  */
  593 void
  594 doexithooks(p)
  595         struct proc *p;
  596 {
  597         hook_proc_run(&exithook_list, p);
  598 }
  599 
  600 hook_list_t forkhook_list;
  601 
  602 void *
  603 forkhook_establish(fn)
  604         void (*fn)(struct proc *, struct proc *);
  605 {
  606         return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL);
  607 }
  608 
  609 void
  610 forkhook_disestablish(vhook)
  611         void *vhook;
  612 {
  613         hook_disestablish(&forkhook_list, vhook);
  614 }
  615 
  616 /*
  617  * Run fork hooks.
  618  */
  619 void
  620 doforkhooks(p2, p1)
  621         struct proc *p2, *p1;
  622 {
  623         struct hook_desc *hd;
  624 
  625         LIST_FOREACH(hd, &forkhook_list, hk_list) {
  626                 ((void (*)(struct proc *, struct proc *))*hd->hk_fn)
  627                     (p2, p1);
  628         }
  629 }
  630 
  631 /*
  632  * "Power hook" types, functions, and variables.
  633  * The list of power hooks is kept ordered with the last registered hook
  634  * first.
  635  * When running the hooks on power down the hooks are called in reverse
  636  * registration order, when powering up in registration order.
  637  */
  638 struct powerhook_desc {
  639         CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
  640         void    (*sfd_fn)(int, void *);
  641         void    *sfd_arg;
  642 };
  643 
  644 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
  645         CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
  646 
  647 void *
  648 powerhook_establish(fn, arg)
  649         void (*fn)(int, void *);
  650         void *arg;
  651 {
  652         struct powerhook_desc *ndp;
  653 
  654         ndp = (struct powerhook_desc *)
  655             malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
  656         if (ndp == NULL)
  657                 return (NULL);
  658 
  659         ndp->sfd_fn = fn;
  660         ndp->sfd_arg = arg;
  661         CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
  662 
  663         return (ndp);
  664 }
  665 
  666 void
  667 powerhook_disestablish(vhook)
  668         void *vhook;
  669 {
  670 #ifdef DIAGNOSTIC
  671         struct powerhook_desc *dp;
  672 
  673         CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
  674                 if (dp == vhook)
  675                         goto found;
  676         panic("powerhook_disestablish: hook %p not established", vhook);
  677  found:
  678 #endif
  679 
  680         CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
  681             sfd_list);
  682         free(vhook, M_DEVBUF);
  683 }
  684 
  685 /*
  686  * Run power hooks.
  687  */
  688 void
  689 dopowerhooks(why)
  690         int why;
  691 {
  692         struct powerhook_desc *dp;
  693 
  694         if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
  695                 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
  696                         (*dp->sfd_fn)(why, dp->sfd_arg);
  697                 }
  698         } else {
  699                 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
  700                         (*dp->sfd_fn)(why, dp->sfd_arg);
  701                 }
  702         }
  703 }
  704 
  705 /*
  706  * Determine the root device and, if instructed to, the root file system.
  707  */
  708 
  709 #include "md.h"
  710 #if NMD == 0
  711 #undef MEMORY_DISK_HOOKS
  712 #endif
  713 
  714 #ifdef MEMORY_DISK_HOOKS
  715 static struct device fakemdrootdev[NMD];
  716 #endif
  717 
  718 #ifdef MEMORY_DISK_IS_ROOT
  719 #define BOOT_FROM_MEMORY_HOOKS 1
  720 #endif
  721 
  722 #include "raid.h"
  723 #if NRAID == 1
  724 #define BOOT_FROM_RAID_HOOKS 1
  725 #endif
  726 
  727 #ifdef BOOT_FROM_RAID_HOOKS
  728 extern int numraid;
  729 extern struct device *raidrootdev;
  730 #endif
  731 
  732 void
  733 setroot(bootdv, bootpartition)
  734         struct device *bootdv;
  735         int bootpartition;
  736 {
  737         struct device *dv;
  738         int len;
  739 #ifdef MEMORY_DISK_HOOKS
  740         int i;
  741 #endif
  742         dev_t nrootdev;
  743         dev_t ndumpdev = NODEV;
  744         char buf[128];
  745         const char *rootdevname;
  746         const char *dumpdevname;
  747         struct device *rootdv = NULL;           /* XXX gcc -Wuninitialized */
  748         struct device *dumpdv = NULL;
  749         struct ifnet *ifp;
  750         const char *deffsname;
  751         struct vfsops *vops;
  752 
  753 #ifdef MEMORY_DISK_HOOKS
  754         for (i = 0; i < NMD; i++) {
  755                 fakemdrootdev[i].dv_class  = DV_DISK;
  756                 fakemdrootdev[i].dv_cfdata = NULL;
  757                 fakemdrootdev[i].dv_unit   = i;
  758                 fakemdrootdev[i].dv_parent = NULL;
  759                 sprintf(fakemdrootdev[i].dv_xname, "md%d", i);
  760         }
  761 #endif /* MEMORY_DISK_HOOKS */
  762 
  763 #ifdef MEMORY_DISK_IS_ROOT
  764         bootdv = &fakemdrootdev[0];
  765         bootpartition = 0;
  766 #endif
  767 
  768         /*
  769          * If NFS is specified as the file system, and we found
  770          * a DV_DISK boot device (or no boot device at all), then
  771          * find a reasonable network interface for "rootspec".
  772          */
  773         vops = vfs_getopsbyname("nfs");
  774         if (vops != NULL && vops->vfs_mountroot == mountroot &&
  775             rootspec == NULL &&
  776             (bootdv == NULL || bootdv->dv_class != DV_IFNET)) {
  777                 TAILQ_FOREACH(ifp, &ifnet, if_list) {
  778                         if ((ifp->if_flags &
  779                              (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
  780                                 break;
  781                 }
  782                 if (ifp == NULL) {
  783                         /*
  784                          * Can't find a suitable interface; ask the
  785                          * user.
  786                          */
  787                         boothowto |= RB_ASKNAME;
  788                 } else {
  789                         /*
  790                          * Have a suitable interface; behave as if
  791                          * the user specified this interface.
  792                          */
  793                         rootspec = (const char *)ifp->if_xname;
  794                 }
  795         }
  796 
  797         /*
  798          * If wildcarded root and we the boot device wasn't determined,
  799          * ask the user.
  800          */
  801         if (rootspec == NULL && bootdv == NULL)
  802                 boothowto |= RB_ASKNAME;
  803 
  804  top:
  805         if (boothowto & RB_ASKNAME) {
  806                 struct device *defdumpdv;
  807 
  808                 for (;;) {
  809                         printf("root device");
  810                         if (bootdv != NULL) {
  811                                 printf(" (default %s", bootdv->dv_xname);
  812                                 if (bootdv->dv_class == DV_DISK)
  813                                         printf("%c", bootpartition + 'a');
  814                                 printf(")");
  815                         }
  816                         printf(": ");
  817                         len = cngetsn(buf, sizeof(buf));
  818                         if (len == 0 && bootdv != NULL) {
  819                                 strlcpy(buf, bootdv->dv_xname, sizeof(buf));
  820                                 len = strlen(buf);
  821                         }
  822                         if (len > 0 && buf[len - 1] == '*') {
  823                                 buf[--len] = '\0';
  824                                 dv = getdisk(buf, len, 1, &nrootdev, 0);
  825                                 if (dv != NULL) {
  826                                         rootdv = dv;
  827                                         break;
  828                                 }
  829                         }
  830                         dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
  831                         if (dv != NULL) {
  832                                 rootdv = dv;
  833                                 break;
  834                         }
  835                 }
  836 
  837                 /*
  838                  * Set up the default dump device.  If root is on
  839                  * a network device, there is no default dump
  840                  * device, since we don't support dumps to the
  841                  * network.
  842                  */
  843                 if (rootdv->dv_class == DV_IFNET)
  844                         defdumpdv = NULL;
  845                 else
  846                         defdumpdv = rootdv;
  847 
  848                 for (;;) {
  849                         printf("dump device");
  850                         if (defdumpdv != NULL) {
  851                                 /*
  852                                  * Note, we know it's a disk if we get here.
  853                                  */
  854                                 printf(" (default %sb)", defdumpdv->dv_xname);
  855                         }
  856                         printf(": ");
  857                         len = cngetsn(buf, sizeof(buf));
  858                         if (len == 0) {
  859                                 if (defdumpdv != NULL) {
  860                                         ndumpdev = MAKEDISKDEV(major(nrootdev),
  861                                             DISKUNIT(nrootdev), 1);
  862                                 }
  863                                 dumpdv = defdumpdv;
  864                                 break;
  865                         }
  866                         if (len == 4 && strcmp(buf, "none") == 0) {
  867                                 dumpdv = NULL;
  868                                 break;
  869                         }
  870                         dv = getdisk(buf, len, 1, &ndumpdev, 1);
  871                         if (dv != NULL) {
  872                                 dumpdv = dv;
  873                                 break;
  874                         }
  875                 }
  876 
  877                 rootdev = nrootdev;
  878                 dumpdev = ndumpdev;
  879 
  880                 for (vops = LIST_FIRST(&vfs_list); vops != NULL;
  881                      vops = LIST_NEXT(vops, vfs_list)) {
  882                         if (vops->vfs_mountroot != NULL &&
  883                             vops->vfs_mountroot == mountroot)
  884                         break;
  885                 }
  886 
  887                 if (vops == NULL) {
  888                         mountroot = NULL;
  889                         deffsname = "generic";
  890                 } else
  891                         deffsname = vops->vfs_name;
  892 
  893                 for (;;) {
  894                         printf("file system (default %s): ", deffsname);
  895                         len = cngetsn(buf, sizeof(buf));
  896                         if (len == 0)
  897                                 break;
  898                         if (len == 4 && strcmp(buf, "halt") == 0)
  899                                 cpu_reboot(RB_HALT, NULL);
  900                         else if (len == 6 && strcmp(buf, "reboot") == 0)
  901                                 cpu_reboot(0, NULL);
  902 #if defined(DDB)
  903                         else if (len == 3 && strcmp(buf, "ddb") == 0) {
  904                                 console_debugger();
  905                         }
  906 #endif
  907                         else if (len == 7 && strcmp(buf, "generic") == 0) {
  908                                 mountroot = NULL;
  909                                 break;
  910                         }
  911                         vops = vfs_getopsbyname(buf);
  912                         if (vops == NULL || vops->vfs_mountroot == NULL) {
  913                                 printf("use one of: generic");
  914                                 for (vops = LIST_FIRST(&vfs_list);
  915                                      vops != NULL;
  916                                      vops = LIST_NEXT(vops, vfs_list)) {
  917                                         if (vops->vfs_mountroot != NULL)
  918                                                 printf(" %s", vops->vfs_name);
  919                                 }
  920 #if defined(DDB)
  921                                 printf(" ddb");
  922 #endif
  923                                 printf(" halt reboot\n");
  924                         } else {
  925                                 mountroot = vops->vfs_mountroot;
  926                                 break;
  927                         }
  928                 }
  929 
  930         } else if (rootspec == NULL) {
  931                 int majdev;
  932 
  933                 /*
  934                  * Wildcarded root; use the boot device.
  935                  */
  936                 rootdv = bootdv;
  937 
  938                 majdev = devsw_name2blk(bootdv->dv_xname, NULL, 0);
  939                 if (majdev >= 0) {
  940                         /*
  941                          * Root is on a disk.  `bootpartition' is root.
  942                          */
  943                         rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
  944                             bootpartition);
  945                 }
  946         } else {
  947 
  948                 /*
  949                  * `root on <dev> ...'
  950                  */
  951 
  952                 /*
  953                  * If it's a network interface, we can bail out
  954                  * early.
  955                  */
  956                 dv = finddevice(rootspec);
  957                 if (dv != NULL && dv->dv_class == DV_IFNET) {
  958                         rootdv = dv;
  959                         goto haveroot;
  960                 }
  961 
  962                 rootdevname = devsw_blk2name(major(rootdev));
  963                 if (rootdevname == NULL) {
  964                         printf("unknown device major 0x%x\n", rootdev);
  965                         boothowto |= RB_ASKNAME;
  966                         goto top;
  967                 }
  968                 memset(buf, 0, sizeof(buf));
  969                 sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev));
  970 
  971                 rootdv = finddevice(buf);
  972                 if (rootdv == NULL) {
  973                         printf("device %s (0x%x) not configured\n",
  974                             buf, rootdev);
  975                         boothowto |= RB_ASKNAME;
  976                         goto top;
  977                 }
  978         }
  979 
  980  haveroot:
  981 
  982         root_device = rootdv;
  983 
  984         switch (rootdv->dv_class) {
  985         case DV_IFNET:
  986                 aprint_normal("root on %s", rootdv->dv_xname);
  987                 break;
  988 
  989         case DV_DISK:
  990                 aprint_normal("root on %s%c", rootdv->dv_xname,
  991                     DISKPART(rootdev) + 'a');
  992                 break;
  993 
  994         default:
  995                 printf("can't determine root device\n");
  996                 boothowto |= RB_ASKNAME;
  997                 goto top;
  998         }
  999 
 1000         /*
 1001          * Now configure the dump device.
 1002          *
 1003          * If we haven't figured out the dump device, do so, with
 1004          * the following rules:
 1005          *
 1006          *      (a) We already know dumpdv in the RB_ASKNAME case.
 1007          *
 1008          *      (b) If dumpspec is set, try to use it.  If the device
 1009          *          is not available, punt.
 1010          *
 1011          *      (c) If dumpspec is not set, the dump device is
 1012          *          wildcarded or unspecified.  If the root device
 1013          *          is DV_IFNET, punt.  Otherwise, use partition b
 1014          *          of the root device.
 1015          */
 1016 
 1017         if (boothowto & RB_ASKNAME) {           /* (a) */
 1018                 if (dumpdv == NULL)
 1019                         goto nodumpdev;
 1020         } else if (dumpspec != NULL) {          /* (b) */
 1021                 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
 1022                         /*
 1023                          * Operator doesn't want a dump device.
 1024                          * Or looks like they tried to pick a network
 1025                          * device.  Oops.
 1026                          */
 1027                         goto nodumpdev;
 1028                 }
 1029 
 1030                 dumpdevname = devsw_blk2name(major(dumpdev));
 1031                 if (dumpdevname == NULL)
 1032                         goto nodumpdev;
 1033                 memset(buf, 0, sizeof(buf));
 1034                 sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev));
 1035 
 1036                 dumpdv = finddevice(buf);
 1037                 if (dumpdv == NULL) {
 1038                         /*
 1039                          * Device not configured.
 1040                          */
 1041                         goto nodumpdev;
 1042                 }
 1043         } else {                                /* (c) */
 1044                 if (rootdv->dv_class == DV_IFNET)
 1045                         goto nodumpdev;
 1046                 else {
 1047                         dumpdv = rootdv;
 1048                         dumpdev = MAKEDISKDEV(major(rootdev),
 1049                             dumpdv->dv_unit, 1);
 1050                 }
 1051         }
 1052 
 1053         aprint_normal(" dumps on %s%c\n", dumpdv->dv_xname,
 1054             DISKPART(dumpdev) + 'a');
 1055         return;
 1056 
 1057  nodumpdev:
 1058         dumpdev = NODEV;
 1059         aprint_normal("\n");
 1060 }
 1061 
 1062 static struct device *
 1063 finddevice(name)
 1064         const char *name;
 1065 {
 1066         struct device *dv;
 1067 #if defined(BOOT_FROM_RAID_HOOKS) || defined(BOOT_FROM_MEMORY_HOOKS)
 1068         int j;
 1069 #endif /* BOOT_FROM_RAID_HOOKS || BOOT_FROM_MEMORY_HOOKS */
 1070 
 1071 #ifdef BOOT_FROM_RAID_HOOKS
 1072         for (j = 0; j < numraid; j++) {
 1073                 if (strcmp(name, raidrootdev[j].dv_xname) == 0) {
 1074                         dv = &raidrootdev[j];
 1075                         return (dv);
 1076                 }
 1077         }
 1078 #endif /* BOOT_FROM_RAID_HOOKS */
 1079 
 1080 #ifdef BOOT_FROM_MEMORY_HOOKS
 1081         for (j = 0; j < NMD; j++) {
 1082                 if (strcmp(name, fakemdrootdev[j].dv_xname) == 0) {
 1083                         dv = &fakemdrootdev[j];
 1084                         return (dv);
 1085                 }
 1086         }
 1087 #endif /* BOOT_FROM_MEMORY_HOOKS */
 1088 
 1089         for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
 1090             dv = TAILQ_NEXT(dv, dv_list))
 1091                 if (strcmp(dv->dv_xname, name) == 0)
 1092                         break;
 1093         return (dv);
 1094 }
 1095 
 1096 static struct device *
 1097 getdisk(str, len, defpart, devp, isdump)
 1098         char *str;
 1099         int len, defpart;
 1100         dev_t *devp;
 1101         int isdump;
 1102 {
 1103         struct device   *dv;
 1104 #ifdef MEMORY_DISK_HOOKS
 1105         int             i;
 1106 #endif
 1107 #ifdef BOOT_FROM_RAID_HOOKS
 1108         int             j;
 1109 #endif
 1110 
 1111         if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
 1112                 printf("use one of:");
 1113 #ifdef MEMORY_DISK_HOOKS
 1114                 if (isdump == 0)
 1115                         for (i = 0; i < NMD; i++)
 1116                                 printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
 1117                                     'a' + MAXPARTITIONS - 1);
 1118 #endif
 1119 #ifdef BOOT_FROM_RAID_HOOKS
 1120                 if (isdump == 0)
 1121                         for (j = 0; j < numraid; j++)
 1122                                 printf(" %s[a-%c]", raidrootdev[j].dv_xname,
 1123                                     'a' + MAXPARTITIONS - 1);
 1124 #endif
 1125                 TAILQ_FOREACH(dv, &alldevs, dv_list) {
 1126                         if (dv->dv_class == DV_DISK)
 1127                                 printf(" %s[a-%c]", dv->dv_xname,
 1128                                     'a' + MAXPARTITIONS - 1);
 1129                         if (isdump == 0 && dv->dv_class == DV_IFNET)
 1130                                 printf(" %s", dv->dv_xname);
 1131                 }
 1132                 if (isdump)
 1133                         printf(" none");
 1134 #if defined(DDB)
 1135                 printf(" ddb");
 1136 #endif
 1137                 printf(" halt reboot\n");
 1138         }
 1139         return (dv);
 1140 }
 1141 
 1142 static struct device *
 1143 parsedisk(str, len, defpart, devp)
 1144         char *str;
 1145         int len, defpart;
 1146         dev_t *devp;
 1147 {
 1148         struct device *dv;
 1149         char *cp, c;
 1150         int majdev, part;
 1151 #ifdef MEMORY_DISK_HOOKS
 1152         int i;
 1153 #endif
 1154         if (len == 0)
 1155                 return (NULL);
 1156 
 1157         if (len == 4 && strcmp(str, "halt") == 0)
 1158                 cpu_reboot(RB_HALT, NULL);
 1159         else if (len == 6 && strcmp(str, "reboot") == 0)
 1160                 cpu_reboot(0, NULL);
 1161 #if defined(DDB)
 1162         else if (len == 3 && strcmp(str, "ddb") == 0)
 1163                 console_debugger();
 1164 #endif
 1165 
 1166         cp = str + len - 1;
 1167         c = *cp;
 1168         if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
 1169                 part = c - 'a';
 1170                 *cp = '\0';
 1171         } else
 1172                 part = defpart;
 1173 
 1174 #ifdef MEMORY_DISK_HOOKS
 1175         for (i = 0; i < NMD; i++)
 1176                 if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
 1177                         dv = &fakemdrootdev[i];
 1178                         goto gotdisk;
 1179                 }
 1180 #endif
 1181 
 1182         dv = finddevice(str);
 1183         if (dv != NULL) {
 1184                 if (dv->dv_class == DV_DISK) {
 1185 #ifdef MEMORY_DISK_HOOKS
 1186  gotdisk:
 1187 #endif
 1188                         majdev = devsw_name2blk(dv->dv_xname, NULL, 0);
 1189                         if (majdev < 0)
 1190                                 panic("parsedisk");
 1191                         *devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
 1192                 }
 1193 
 1194                 if (dv->dv_class == DV_IFNET)
 1195                         *devp = NODEV;
 1196         }
 1197 
 1198         *cp = c;
 1199         return (dv);
 1200 }
 1201 
 1202 /*
 1203  * snprintf() `bytes' into `buf', reformatting it so that the number,
 1204  * plus a possible `x' + suffix extension) fits into len bytes (including
 1205  * the terminating NUL).
 1206  * Returns the number of bytes stored in buf, or -1 if there was a problem.
 1207  * E.g, given a len of 9 and a suffix of `B':
 1208  *      bytes           result
 1209  *      -----           ------
 1210  *      99999           `99999 B'
 1211  *      100000          `97 kB'
 1212  *      66715648        `65152 kB'
 1213  *      252215296       `240 MB'
 1214  */
 1215 int
 1216 humanize_number(buf, len, bytes, suffix, divisor)
 1217         char            *buf;
 1218         size_t           len;
 1219         u_int64_t        bytes;
 1220         const char      *suffix;
 1221         int             divisor;
 1222 {
 1223         /* prefixes are: (none), kilo, Mega, Giga, Tera, Peta, Exa */
 1224         const char *prefixes;
 1225         int             r;
 1226         u_int64_t       max;
 1227         size_t          i, suffixlen;
 1228 
 1229         if (buf == NULL || suffix == NULL)
 1230                 return (-1);
 1231         if (len > 0)
 1232                 buf[0] = '\0';
 1233         suffixlen = strlen(suffix);
 1234         /* check if enough room for `x y' + suffix + `\0' */
 1235         if (len < 4 + suffixlen)
 1236                 return (-1);
 1237 
 1238         if (divisor == 1024) {
 1239                 /*
 1240                  * binary multiplies
 1241                  * XXX IEC 60027-2 recommends Ki, Mi, Gi...
 1242                  */
 1243                 prefixes = " KMGTPE";
 1244         } else
 1245                 prefixes = " kMGTPE"; /* SI for decimal multiplies */
 1246 
 1247         max = 1;
 1248         for (i = 0; i < len - suffixlen - 3; i++)
 1249                 max *= 10;
 1250         for (i = 0; bytes >= max && prefixes[i + 1]; i++)
 1251                 bytes /= divisor;
 1252 
 1253         r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
 1254             i == 0 ? "" : " ", prefixes[i], suffix);
 1255 
 1256         return (r);
 1257 }
 1258 
 1259 int
 1260 format_bytes(buf, len, bytes)
 1261         char            *buf;
 1262         size_t           len;
 1263         u_int64_t        bytes;
 1264 {
 1265         int     rv;
 1266         size_t  nlen;
 1267 
 1268         rv = humanize_number(buf, len, bytes, "B", 1024);
 1269         if (rv != -1) {
 1270                         /* nuke the trailing ` B' if it exists */
 1271                 nlen = strlen(buf) - 2;
 1272                 if (strcmp(&buf[nlen], " B") == 0)
 1273                         buf[nlen] = '\0';
 1274         }
 1275         return (rv);
 1276 }
 1277 
 1278 /*
 1279  * Start trace of particular system call. If process is being traced,
 1280  * this routine is called by MD syscall dispatch code just before
 1281  * a system call is actually executed.
 1282  * MD caller guarantees the passed 'code' is within the supported
 1283  * system call number range for emulation the process runs under.
 1284  */
 1285 int
 1286 trace_enter(struct lwp *l, register_t code,
 1287         register_t realcode, const struct sysent *callp, void *args)
 1288 {
 1289 #if defined(KTRACE) || defined(SYSTRACE)
 1290         struct proc *p = l->l_proc;
 1291 #endif
 1292 
 1293 #ifdef SYSCALL_DEBUG
 1294         scdebug_call(l, code, args);
 1295 #endif /* SYSCALL_DEBUG */
 1296 
 1297 #ifdef KTRACE
 1298         if (KTRPOINT(p, KTR_SYSCALL))
 1299                 ktrsyscall(p, code, realcode, callp, args);
 1300 #endif /* KTRACE */
 1301 
 1302 #ifdef SYSTRACE
 1303         if (ISSET(p->p_flag, P_SYSTRACE))
 1304                 return systrace_enter(p, code, args);
 1305 #endif
 1306         return 0;
 1307 }
 1308 
 1309 /*
 1310  * End trace of particular system call. If process is being traced,
 1311  * this routine is called by MD syscall dispatch code just after
 1312  * a system call finishes.
 1313  * MD caller guarantees the passed 'code' is within the supported
 1314  * system call number range for emulation the process runs under.
 1315  */
 1316 void
 1317 trace_exit(struct lwp *l, register_t code, void *args, register_t rval[],
 1318     int error)
 1319 {
 1320 #if defined(KTRACE) || defined(SYSTRACE)
 1321         struct proc *p = l->l_proc;
 1322 #endif
 1323 
 1324 #ifdef SYSCALL_DEBUG
 1325         scdebug_ret(l, code, error, rval);
 1326 #endif /* SYSCALL_DEBUG */
 1327 
 1328 #ifdef KTRACE
 1329         if (KTRPOINT(p, KTR_SYSRET)) {
 1330                 KERNEL_PROC_LOCK(l);
 1331                 ktrsysret(p, code, error, rval);
 1332                 KERNEL_PROC_UNLOCK(l);
 1333         }
 1334 #endif /* KTRACE */
 1335 
 1336 #ifdef SYSTRACE
 1337         if (ISSET(p->p_flag, P_SYSTRACE))
 1338                 systrace_exit(p, code, args, rval, error);
 1339 #endif
 1340 }

Cache object: 96abfa5cd4052a99988f95015c051e35


[ 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.