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/subr_fault.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: subr_fault.c,v 1.2 2020/06/30 16:28:17 maxv Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2020 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Maxime Villard.
    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  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: subr_fault.c,v 1.2 2020/06/30 16:28:17 maxv Exp $");
   34 
   35 #include <sys/module.h>
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 
   40 #include <sys/conf.h>
   41 #include <sys/types.h>
   42 #include <sys/specificdata.h>
   43 #include <sys/kmem.h>
   44 #include <sys/atomic.h>
   45 #include <sys/ioccom.h>
   46 #include <sys/lwp.h>
   47 #include <sys/fault.h>
   48 
   49 typedef struct {
   50         volatile bool enabled;
   51         volatile bool oneshot;
   52         volatile unsigned long nth;
   53         volatile unsigned long cnt;
   54         volatile unsigned long nfaults;
   55 } fault_t;
   56 
   57 static fault_t fault_global __cacheline_aligned = {
   58         .enabled = false,
   59         .oneshot = false,
   60         .nth = FAULT_NTH_MIN,
   61         .cnt = 0,
   62         .nfaults = 0
   63 };
   64 
   65 static kmutex_t fault_global_lock __cacheline_aligned;
   66 static specificdata_key_t fault_lwp_key;
   67 
   68 /* -------------------------------------------------------------------------- */
   69 
   70 bool
   71 fault_inject(void)
   72 {
   73         volatile unsigned long cnt;
   74         fault_t *f;
   75 
   76         if (__predict_false(cold))
   77                 return false;
   78 
   79         if (__predict_false(atomic_load_acquire(&fault_global.enabled))) {
   80                 f = &fault_global;
   81         } else {
   82                 f = lwp_getspecific(fault_lwp_key);
   83                 if (__predict_true(f == NULL))
   84                         return false;
   85                 if (__predict_false(!f->enabled))
   86                         return false;
   87         }
   88 
   89         if (atomic_load_relaxed(&f->oneshot)) {
   90                 if (__predict_true(atomic_load_relaxed(&f->nfaults) > 0))
   91                         return false;
   92         }
   93 
   94         cnt = atomic_inc_ulong_nv(&f->cnt);
   95         if (__predict_false(cnt % atomic_load_relaxed(&f->nth) == 0)) {
   96                 atomic_inc_ulong(&f->nfaults);
   97                 return true;
   98         }
   99 
  100         return false;
  101 }
  102 
  103 /* -------------------------------------------------------------------------- */
  104 
  105 static int
  106 fault_open(dev_t dev, int flag, int mode, struct lwp *l)
  107 {
  108         return 0;
  109 }
  110 
  111 static int
  112 fault_close(dev_t dev, int flag, int mode, struct lwp *l)
  113 {
  114         return 0;
  115 }
  116 
  117 static int
  118 fault_ioc_enable(struct fault_ioc_enable *args)
  119 {
  120         fault_t *f;
  121 
  122         if (args->mode != FAULT_MODE_NTH_ONESHOT)
  123                 return EINVAL;
  124         if (args->nth < FAULT_NTH_MIN)
  125                 return EINVAL;
  126 
  127         switch (args->scope) {
  128         case FAULT_SCOPE_GLOBAL:
  129                 mutex_enter(&fault_global_lock);
  130                 if (fault_global.enabled) {
  131                         mutex_exit(&fault_global_lock);
  132                         return EEXIST;
  133                 }
  134                 fault_global.oneshot = true;
  135                 atomic_store_relaxed(&fault_global.nth, args->nth);
  136                 fault_global.cnt = 0;
  137                 fault_global.nfaults = 0;
  138                 atomic_store_release(&fault_global.enabled, true);
  139                 mutex_exit(&fault_global_lock);
  140                 break;
  141         case FAULT_SCOPE_LWP:
  142                 f = lwp_getspecific(fault_lwp_key);
  143                 if (f != NULL) {
  144                         if (f->enabled)
  145                                 return EEXIST;
  146                 } else {
  147                         f = kmem_zalloc(sizeof(*f), KM_SLEEP);
  148                         lwp_setspecific(fault_lwp_key, f);
  149                 }
  150                 f->oneshot = true;
  151                 atomic_store_relaxed(&f->nth, args->nth);
  152                 f->cnt = 0;
  153                 f->nfaults = 0;
  154                 atomic_store_release(&f->enabled, true);
  155                 break;
  156         default:
  157                 return EINVAL;
  158         }
  159 
  160         return 0;
  161 }
  162 
  163 static int
  164 fault_ioc_disable(struct fault_ioc_disable *args)
  165 {
  166         fault_t *f;
  167 
  168         switch (args->scope) {
  169         case FAULT_SCOPE_GLOBAL:
  170                 mutex_enter(&fault_global_lock);
  171                 if (!fault_global.enabled) {
  172                         mutex_exit(&fault_global_lock);
  173                         return ENOENT;
  174                 }
  175                 atomic_store_release(&fault_global.enabled, false);
  176                 mutex_exit(&fault_global_lock);
  177                 break;
  178         case FAULT_SCOPE_LWP:
  179                 f = lwp_getspecific(fault_lwp_key);
  180                 if (f == NULL)
  181                         return ENOENT;
  182                 if (!f->enabled)
  183                         return ENOENT;
  184                 atomic_store_release(&f->enabled, false);
  185                 break;
  186         default:
  187                 return EINVAL;
  188         }
  189 
  190         return 0;
  191 }
  192 
  193 static int
  194 fault_ioc_getinfo(struct fault_ioc_getinfo *args)
  195 {
  196         fault_t *f;
  197 
  198         switch (args->scope) {
  199         case FAULT_SCOPE_GLOBAL:
  200                 args->nfaults = atomic_load_relaxed(&fault_global.nfaults);
  201                 break;
  202         case FAULT_SCOPE_LWP:
  203                 f = lwp_getspecific(fault_lwp_key);
  204                 if (f == NULL)
  205                         return ENOENT;
  206                 args->nfaults = atomic_load_relaxed(&f->nfaults);
  207                 break;
  208         default:
  209                 return EINVAL;
  210         }
  211 
  212         return 0;
  213 }
  214 
  215 static int
  216 fault_ioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
  217 {
  218         switch (cmd) {
  219         case FAULT_IOC_ENABLE:
  220                 return fault_ioc_enable(addr);
  221         case FAULT_IOC_DISABLE:
  222                 return fault_ioc_disable(addr);
  223         case FAULT_IOC_GETINFO:
  224                 return fault_ioc_getinfo(addr);
  225         default:
  226                 return EINVAL;
  227         }
  228 }
  229 
  230 const struct cdevsw fault_cdevsw = {
  231         .d_open = fault_open,
  232         .d_close = fault_close,
  233         .d_read = noread,
  234         .d_write = nowrite,
  235         .d_ioctl = fault_ioctl,
  236         .d_stop = nostop,
  237         .d_tty = notty,
  238         .d_poll = nopoll,
  239         .d_mmap = nommap,
  240         .d_kqfilter = nokqfilter,
  241         .d_discard = nodiscard,
  242         .d_flag = D_OTHER | D_MPSAFE
  243 };
  244 
  245 /* -------------------------------------------------------------------------- */
  246 
  247 MODULE(MODULE_CLASS_MISC, fault, NULL);
  248 
  249 static void
  250 fault_lwp_free(void *arg)
  251 {
  252         fault_t *f = (fault_t *)arg;
  253 
  254         if (f == NULL) {
  255                 return;
  256         }
  257 
  258         kmem_free(f, sizeof(*f));
  259 }
  260 
  261 static void
  262 fault_init(void)
  263 {
  264         mutex_init(&fault_global_lock, MUTEX_DEFAULT, IPL_NONE);
  265         lwp_specific_key_create(&fault_lwp_key, fault_lwp_free);
  266 }
  267 
  268 static int
  269 fault_modcmd(modcmd_t cmd, void *arg)
  270 {
  271         switch (cmd) {
  272         case MODULE_CMD_INIT:
  273                 fault_init();
  274                 return 0;
  275         case MODULE_CMD_FINI:
  276                 return EINVAL;
  277         default:
  278                 return ENOTTY;
  279         }
  280 }

Cache object: 324a3a08a72d2d3eadca9c07c151dcb6


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