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/contrib/openzfs/cmd/zed/agents/fmd_serd.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  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License, Version 1.0 only
    6  * (the "License").  You may not use this file except in compliance
    7  * with the License.
    8  *
    9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   10  * or https://opensource.org/licenses/CDDL-1.0.
   11  * See the License for the specific language governing permissions
   12  * and limitations under the License.
   13  *
   14  * When distributing Covered Code, include this CDDL HEADER in each
   15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   16  * If applicable, add the following below this CDDL HEADER, with the
   17  * fields enclosed by brackets "[]" replaced with your own identifying
   18  * information: Portions Copyright [yyyy] [name of copyright owner]
   19  *
   20  * CDDL HEADER END
   21  */
   22 /*
   23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   24  * Use is subject to license terms.
   25  *
   26  * Copyright (c) 2016, Intel Corporation.
   27  */
   28 
   29 #include <assert.h>
   30 #include <stddef.h>
   31 #include <stdlib.h>
   32 #include <string.h>
   33 #include <sys/list.h>
   34 #include <sys/time.h>
   35 
   36 #include "fmd_api.h"
   37 #include "fmd_serd.h"
   38 #include "../zed_log.h"
   39 
   40 
   41 #define FMD_STR_BUCKETS         211
   42 
   43 
   44 #ifdef SERD_ENG_DEBUG
   45 #define serd_log_msg(fmt, ...) \
   46         zed_log_msg(LOG_INFO, fmt, __VA_ARGS__)
   47 #else
   48 #define serd_log_msg(fmt, ...)
   49 #endif
   50 
   51 
   52 /*
   53  * SERD Engine Backend
   54  */
   55 
   56 /*
   57  * Compute the delta between events in nanoseconds.  To account for very old
   58  * events which are replayed, we must handle the case where time is negative.
   59  * We convert the hrtime_t's to unsigned 64-bit integers and then handle the
   60  * case where 'old' is greater than 'new' (i.e. high-res time has wrapped).
   61  */
   62 static hrtime_t
   63 fmd_event_delta(hrtime_t t1, hrtime_t t2)
   64 {
   65         uint64_t old = t1;
   66         uint64_t new = t2;
   67 
   68         return (new >= old ? new - old : (UINT64_MAX - old) + new + 1);
   69 }
   70 
   71 static fmd_serd_eng_t *
   72 fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t)
   73 {
   74         fmd_serd_eng_t *sgp;
   75 
   76         sgp = malloc(sizeof (fmd_serd_eng_t));
   77         if (sgp == NULL) {
   78                 perror("malloc");
   79                 exit(EXIT_FAILURE);
   80         }
   81         memset(sgp, 0, sizeof (fmd_serd_eng_t));
   82 
   83         sgp->sg_name = strdup(name);
   84         if (sgp->sg_name == NULL) {
   85                 perror("strdup");
   86                 exit(EXIT_FAILURE);
   87         }
   88 
   89         sgp->sg_flags = FMD_SERD_DIRTY;
   90         sgp->sg_n = n;
   91         sgp->sg_t = t;
   92 
   93         list_create(&sgp->sg_list, sizeof (fmd_serd_elem_t),
   94             offsetof(fmd_serd_elem_t, se_list));
   95 
   96         return (sgp);
   97 }
   98 
   99 static void
  100 fmd_serd_eng_free(fmd_serd_eng_t *sgp)
  101 {
  102         fmd_serd_eng_reset(sgp);
  103         free(sgp->sg_name);
  104         list_destroy(&sgp->sg_list);
  105         free(sgp);
  106 }
  107 
  108 /*
  109  * sourced from fmd_string.c
  110  */
  111 static ulong_t
  112 fmd_strhash(const char *key)
  113 {
  114         ulong_t g, h = 0;
  115         const char *p;
  116 
  117         for (p = key; *p != '\0'; p++) {
  118                 h = (h << 4) + *p;
  119 
  120                 if ((g = (h & 0xf0000000)) != 0) {
  121                         h ^= (g >> 24);
  122                         h ^= g;
  123                 }
  124         }
  125 
  126         return (h);
  127 }
  128 
  129 void
  130 fmd_serd_hash_create(fmd_serd_hash_t *shp)
  131 {
  132         shp->sh_hashlen = FMD_STR_BUCKETS;
  133         shp->sh_hash = calloc(shp->sh_hashlen, sizeof (void *));
  134         shp->sh_count = 0;
  135 
  136         if (shp->sh_hash == NULL) {
  137                 perror("calloc");
  138                 exit(EXIT_FAILURE);
  139         }
  140 
  141 }
  142 
  143 void
  144 fmd_serd_hash_destroy(fmd_serd_hash_t *shp)
  145 {
  146         fmd_serd_eng_t *sgp, *ngp;
  147         uint_t i;
  148 
  149         for (i = 0; i < shp->sh_hashlen; i++) {
  150                 for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = ngp) {
  151                         ngp = sgp->sg_next;
  152                         fmd_serd_eng_free(sgp);
  153                 }
  154         }
  155 
  156         free(shp->sh_hash);
  157         memset(shp, 0, sizeof (fmd_serd_hash_t));
  158 }
  159 
  160 void
  161 fmd_serd_hash_apply(fmd_serd_hash_t *shp, fmd_serd_eng_f *func, void *arg)
  162 {
  163         fmd_serd_eng_t *sgp;
  164         uint_t i;
  165 
  166         for (i = 0; i < shp->sh_hashlen; i++) {
  167                 for (sgp = shp->sh_hash[i]; sgp != NULL; sgp = sgp->sg_next)
  168                         func(sgp, arg);
  169         }
  170 }
  171 
  172 fmd_serd_eng_t *
  173 fmd_serd_eng_insert(fmd_serd_hash_t *shp, const char *name,
  174     uint_t n, hrtime_t t)
  175 {
  176         uint_t h = fmd_strhash(name) % shp->sh_hashlen;
  177         fmd_serd_eng_t *sgp = fmd_serd_eng_alloc(name, n, t);
  178 
  179         serd_log_msg("  SERD Engine: inserting  %s N %d T %llu",
  180             name, (int)n, (long long unsigned)t);
  181 
  182         sgp->sg_next = shp->sh_hash[h];
  183         shp->sh_hash[h] = sgp;
  184         shp->sh_count++;
  185 
  186         return (sgp);
  187 }
  188 
  189 fmd_serd_eng_t *
  190 fmd_serd_eng_lookup(fmd_serd_hash_t *shp, const char *name)
  191 {
  192         uint_t h = fmd_strhash(name) % shp->sh_hashlen;
  193         fmd_serd_eng_t *sgp;
  194 
  195         for (sgp = shp->sh_hash[h]; sgp != NULL; sgp = sgp->sg_next) {
  196                 if (strcmp(name, sgp->sg_name) == 0)
  197                         return (sgp);
  198         }
  199 
  200         return (NULL);
  201 }
  202 
  203 void
  204 fmd_serd_eng_delete(fmd_serd_hash_t *shp, const char *name)
  205 {
  206         uint_t h = fmd_strhash(name) % shp->sh_hashlen;
  207         fmd_serd_eng_t *sgp, **pp = &shp->sh_hash[h];
  208 
  209         serd_log_msg("  SERD Engine: deleting %s", name);
  210 
  211         for (sgp = *pp; sgp != NULL; sgp = sgp->sg_next) {
  212                 if (strcmp(sgp->sg_name, name) != 0)
  213                         pp = &sgp->sg_next;
  214                 else
  215                         break;
  216         }
  217 
  218         if (sgp != NULL) {
  219                 *pp = sgp->sg_next;
  220                 fmd_serd_eng_free(sgp);
  221                 assert(shp->sh_count != 0);
  222                 shp->sh_count--;
  223         }
  224 }
  225 
  226 static void
  227 fmd_serd_eng_discard(fmd_serd_eng_t *sgp, fmd_serd_elem_t *sep)
  228 {
  229         list_remove(&sgp->sg_list, sep);
  230         sgp->sg_count--;
  231 
  232         serd_log_msg("  SERD Engine: discarding %s, %d remaining",
  233             sgp->sg_name, (int)sgp->sg_count);
  234 
  235         free(sep);
  236 }
  237 
  238 int
  239 fmd_serd_eng_record(fmd_serd_eng_t *sgp, hrtime_t hrt)
  240 {
  241         fmd_serd_elem_t *sep, *oep;
  242 
  243         /*
  244          * If the fired flag is already set, return false and discard the
  245          * event.  This means that the caller will only see the engine "fire"
  246          * once until fmd_serd_eng_reset() is called.  The fmd_serd_eng_fired()
  247          * function can also be used in combination with fmd_serd_eng_record().
  248          */
  249         if (sgp->sg_flags & FMD_SERD_FIRED) {
  250                 serd_log_msg("  SERD Engine: record %s already fired!",
  251                     sgp->sg_name);
  252                 return (B_FALSE);
  253         }
  254 
  255         while (sgp->sg_count >= sgp->sg_n)
  256                 fmd_serd_eng_discard(sgp, list_tail(&sgp->sg_list));
  257 
  258         sep = malloc(sizeof (fmd_serd_elem_t));
  259         if (sep == NULL) {
  260                 perror("malloc");
  261                 exit(EXIT_FAILURE);
  262         }
  263         sep->se_hrt = hrt;
  264 
  265         list_insert_head(&sgp->sg_list, sep);
  266         sgp->sg_count++;
  267 
  268         serd_log_msg("  SERD Engine: recording %s of %d (%llu)",
  269             sgp->sg_name, (int)sgp->sg_count, (long long unsigned)hrt);
  270 
  271         /*
  272          * Pick up the oldest element pointer for comparison to 'sep'.  We must
  273          * do this after adding 'sep' because 'oep' and 'sep' can be the same.
  274          */
  275         oep = list_tail(&sgp->sg_list);
  276 
  277         if (sgp->sg_count >= sgp->sg_n &&
  278             fmd_event_delta(oep->se_hrt, sep->se_hrt) <= sgp->sg_t) {
  279                 sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY;
  280                 serd_log_msg("  SERD Engine: fired %s", sgp->sg_name);
  281                 return (B_TRUE);
  282         }
  283 
  284         sgp->sg_flags |= FMD_SERD_DIRTY;
  285         return (B_FALSE);
  286 }
  287 
  288 int
  289 fmd_serd_eng_fired(fmd_serd_eng_t *sgp)
  290 {
  291         return (sgp->sg_flags & FMD_SERD_FIRED);
  292 }
  293 
  294 int
  295 fmd_serd_eng_empty(fmd_serd_eng_t *sgp)
  296 {
  297         return (sgp->sg_count == 0);
  298 }
  299 
  300 void
  301 fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
  302 {
  303         serd_log_msg("  SERD Engine: resetting %s", sgp->sg_name);
  304 
  305         while (sgp->sg_count != 0)
  306                 fmd_serd_eng_discard(sgp, list_head(&sgp->sg_list));
  307 
  308         sgp->sg_flags &= ~FMD_SERD_FIRED;
  309         sgp->sg_flags |= FMD_SERD_DIRTY;
  310 }
  311 
  312 void
  313 fmd_serd_eng_gc(fmd_serd_eng_t *sgp)
  314 {
  315         fmd_serd_elem_t *sep, *nep;
  316         hrtime_t hrt;
  317 
  318         if (sgp->sg_count == 0 || (sgp->sg_flags & FMD_SERD_FIRED))
  319                 return; /* no garbage collection needed if empty or fired */
  320 
  321         sep = list_head(&sgp->sg_list);
  322         if (sep == NULL)
  323                 return;
  324 
  325         hrt = sep->se_hrt - sgp->sg_t;
  326 
  327         for (sep = list_head(&sgp->sg_list); sep != NULL; sep = nep) {
  328                 if (sep->se_hrt >= hrt)
  329                         break; /* sep and subsequent events are all within T */
  330 
  331                 nep = list_next(&sgp->sg_list, sep);
  332                 fmd_serd_eng_discard(sgp, sep);
  333                 sgp->sg_flags |= FMD_SERD_DIRTY;
  334         }
  335 }

Cache object: 240db5afedcc5379176950dea1f93bd2


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