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_api.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 (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 /*
   22  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
   23  *
   24  * Copyright (c) 2016, Intel Corporation.
   25  */
   26 
   27 /*
   28  * This file implements the minimal FMD module API required to support the
   29  * fault logic modules in ZED. This support includes module registration,
   30  * memory allocation, module property accessors, basic case management,
   31  * one-shot timers and SERD engines.
   32  *
   33  * In the ZED runtime, the modules are called from a single thread so no
   34  * locking is required in this emulated FMD environment.
   35  */
   36 
   37 #include <sys/types.h>
   38 #include <sys/fm/protocol.h>
   39 #include <uuid/uuid.h>
   40 #include <signal.h>
   41 #include <string.h>
   42 #include <time.h>
   43 
   44 #include "fmd_api.h"
   45 #include "fmd_serd.h"
   46 
   47 #include "zfs_agents.h"
   48 #include "../zed_log.h"
   49 
   50 typedef struct fmd_modstat {
   51         fmd_stat_t      ms_accepted;    /* total events accepted by module */
   52         fmd_stat_t      ms_caseopen;    /* cases currently open */
   53         fmd_stat_t      ms_casesolved;  /* total cases solved by module */
   54         fmd_stat_t      ms_caseclosed;  /* total cases closed by module */
   55 } fmd_modstat_t;
   56 
   57 typedef struct fmd_module {
   58         const char      *mod_name;      /* basename of module (ro) */
   59         const fmd_hdl_info_t *mod_info; /* module info registered with handle */
   60         void            *mod_spec;      /* fmd_hdl_get/setspecific data value */
   61         fmd_stat_t      *mod_ustat;     /* module specific custom stats */
   62         uint_t          mod_ustat_cnt;  /* count of ustat stats */
   63         fmd_modstat_t   mod_stats;      /* fmd built-in per-module statistics */
   64         fmd_serd_hash_t mod_serds;      /* hash of serd engs owned by module */
   65         char            *mod_vers;      /* a copy of module version string */
   66 } fmd_module_t;
   67 
   68 /*
   69  * ZED has two FMD hardwired module instances
   70  */
   71 fmd_module_t    zfs_retire_module;
   72 fmd_module_t    zfs_diagnosis_module;
   73 
   74 /*
   75  * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
   76  */
   77 
   78 #ifdef DEBUG
   79 const char *
   80 _umem_debug_init(void)
   81 {
   82         return ("default,verbose"); /* $UMEM_DEBUG setting */
   83 }
   84 
   85 const char *
   86 _umem_logging_init(void)
   87 {
   88         return ("fail,contents"); /* $UMEM_LOGGING setting */
   89 }
   90 #endif
   91 
   92 /*
   93  * Register a module with fmd and finish module initialization.
   94  * Returns an integer indicating whether it succeeded (zero) or
   95  * failed (non-zero).
   96  */
   97 int
   98 fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
   99 {
  100         (void) version;
  101         fmd_module_t *mp = (fmd_module_t *)hdl;
  102 
  103         mp->mod_info = mip;
  104         mp->mod_name = mip->fmdi_desc + 4;      /* drop 'ZFS ' prefix */
  105         mp->mod_spec = NULL;
  106 
  107         /* bare minimum module stats */
  108         (void) strcpy(mp->mod_stats.ms_accepted.fmds_name, "fmd.accepted");
  109         (void) strcpy(mp->mod_stats.ms_caseopen.fmds_name, "fmd.caseopen");
  110         (void) strcpy(mp->mod_stats.ms_casesolved.fmds_name, "fmd.casesolved");
  111         (void) strcpy(mp->mod_stats.ms_caseclosed.fmds_name, "fmd.caseclosed");
  112 
  113         fmd_serd_hash_create(&mp->mod_serds);
  114 
  115         fmd_hdl_debug(hdl, "register module");
  116 
  117         return (0);
  118 }
  119 
  120 void
  121 fmd_hdl_unregister(fmd_hdl_t *hdl)
  122 {
  123         fmd_module_t *mp = (fmd_module_t *)hdl;
  124         fmd_modstat_t *msp = &mp->mod_stats;
  125         const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
  126 
  127         /* dump generic module stats */
  128         fmd_hdl_debug(hdl, "%s: %llu", msp->ms_accepted.fmds_name,
  129             msp->ms_accepted.fmds_value.ui64);
  130         if (ops->fmdo_close != NULL) {
  131                 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseopen.fmds_name,
  132                     msp->ms_caseopen.fmds_value.ui64);
  133                 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_casesolved.fmds_name,
  134                     msp->ms_casesolved.fmds_value.ui64);
  135                 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseclosed.fmds_name,
  136                     msp->ms_caseclosed.fmds_value.ui64);
  137         }
  138 
  139         /* dump module specific stats */
  140         if (mp->mod_ustat != NULL) {
  141                 int i;
  142 
  143                 for (i = 0; i < mp->mod_ustat_cnt; i++) {
  144                         fmd_hdl_debug(hdl, "%s: %llu",
  145                             mp->mod_ustat[i].fmds_name,
  146                             mp->mod_ustat[i].fmds_value.ui64);
  147                 }
  148         }
  149 
  150         fmd_serd_hash_destroy(&mp->mod_serds);
  151 
  152         fmd_hdl_debug(hdl, "unregister module");
  153 }
  154 
  155 /*
  156  * fmd_hdl_setspecific() is used to associate a data pointer with
  157  * the specified handle for the duration of the module's lifetime.
  158  * This pointer can be retrieved using fmd_hdl_getspecific().
  159  */
  160 void
  161 fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec)
  162 {
  163         fmd_module_t *mp = (fmd_module_t *)hdl;
  164 
  165         mp->mod_spec = spec;
  166 }
  167 
  168 /*
  169  * Return the module-specific data pointer previously associated
  170  * with the handle using fmd_hdl_setspecific().
  171  */
  172 void *
  173 fmd_hdl_getspecific(fmd_hdl_t *hdl)
  174 {
  175         fmd_module_t *mp = (fmd_module_t *)hdl;
  176 
  177         return (mp->mod_spec);
  178 }
  179 
  180 void *
  181 fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
  182 {
  183         (void) hdl;
  184         return (umem_alloc(size, flags));
  185 }
  186 
  187 void *
  188 fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
  189 {
  190         (void) hdl;
  191         return (umem_zalloc(size, flags));
  192 }
  193 
  194 void
  195 fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
  196 {
  197         (void) hdl;
  198         umem_free(data, size);
  199 }
  200 
  201 /*
  202  * Record a module debug message using the specified format.
  203  */
  204 void
  205 fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
  206 {
  207         char message[256];
  208         va_list vargs;
  209         fmd_module_t *mp = (fmd_module_t *)hdl;
  210 
  211         va_start(vargs, format);
  212         (void) vsnprintf(message, sizeof (message), format, vargs);
  213         va_end(vargs);
  214 
  215         /* prefix message with module name */
  216         zed_log_msg(LOG_INFO, "%s: %s", mp->mod_name, message);
  217 }
  218 
  219 /* Property Retrieval */
  220 
  221 int32_t
  222 fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
  223 {
  224         (void) hdl;
  225 
  226         /*
  227          * These can be looked up in mp->modinfo->fmdi_props
  228          * For now we just hard code for phase 2. In the
  229          * future, there can be a ZED based override.
  230          */
  231         if (strcmp(name, "spare_on_remove") == 0)
  232                 return (1);
  233 
  234         if (strcmp(name, "io_N") == 0 || strcmp(name, "checksum_N") == 0)
  235                 return (10);    /* N = 10 events */
  236 
  237         return (0);
  238 }
  239 
  240 int64_t
  241 fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name)
  242 {
  243         (void) hdl;
  244 
  245         /*
  246          * These can be looked up in mp->modinfo->fmdi_props
  247          * For now we just hard code for phase 2. In the
  248          * future, there can be a ZED based override.
  249          */
  250         if (strcmp(name, "remove_timeout") == 0)
  251                 return (15ULL * 1000ULL * 1000ULL * 1000ULL);   /* 15 sec */
  252 
  253         if (strcmp(name, "io_T") == 0 || strcmp(name, "checksum_T") == 0)
  254                 return (1000ULL * 1000ULL * 1000ULL * 600ULL);  /* 10 min */
  255 
  256         return (0);
  257 }
  258 
  259 /* FMD Statistics */
  260 
  261 fmd_stat_t *
  262 fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t nstats, fmd_stat_t *statv)
  263 {
  264         fmd_module_t *mp = (fmd_module_t *)hdl;
  265 
  266         if (flags == FMD_STAT_NOALLOC) {
  267                 mp->mod_ustat = statv;
  268                 mp->mod_ustat_cnt = nstats;
  269         }
  270 
  271         return (statv);
  272 }
  273 
  274 /* Case Management */
  275 
  276 fmd_case_t *
  277 fmd_case_open(fmd_hdl_t *hdl, void *data)
  278 {
  279         fmd_module_t *mp = (fmd_module_t *)hdl;
  280         uuid_t uuid;
  281 
  282         fmd_case_t *cp;
  283 
  284         cp = fmd_hdl_zalloc(hdl, sizeof (fmd_case_t), FMD_SLEEP);
  285         cp->ci_mod = hdl;
  286         cp->ci_state = FMD_CASE_UNSOLVED;
  287         cp->ci_flags = FMD_CF_DIRTY;
  288         cp->ci_data = data;
  289         cp->ci_bufptr = NULL;
  290         cp->ci_bufsiz = 0;
  291 
  292         uuid_generate(uuid);
  293         uuid_unparse(uuid, cp->ci_uuid);
  294 
  295         fmd_hdl_debug(hdl, "case opened (%s)", cp->ci_uuid);
  296         mp->mod_stats.ms_caseopen.fmds_value.ui64++;
  297 
  298         return (cp);
  299 }
  300 
  301 void
  302 fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp)
  303 {
  304         fmd_module_t *mp = (fmd_module_t *)hdl;
  305 
  306         /*
  307          * For ZED, the event was already sent from fmd_case_add_suspect()
  308          */
  309 
  310         if (cp->ci_state >= FMD_CASE_SOLVED)
  311                 fmd_hdl_debug(hdl, "case is already solved or closed");
  312 
  313         cp->ci_state = FMD_CASE_SOLVED;
  314 
  315         fmd_hdl_debug(hdl, "case solved (%s)", cp->ci_uuid);
  316         mp->mod_stats.ms_casesolved.fmds_value.ui64++;
  317 }
  318 
  319 void
  320 fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp)
  321 {
  322         fmd_module_t *mp = (fmd_module_t *)hdl;
  323         const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
  324 
  325         fmd_hdl_debug(hdl, "case closed (%s)", cp->ci_uuid);
  326 
  327         if (ops->fmdo_close != NULL)
  328                 ops->fmdo_close(hdl, cp);
  329 
  330         mp->mod_stats.ms_caseopen.fmds_value.ui64--;
  331         mp->mod_stats.ms_caseclosed.fmds_value.ui64++;
  332 
  333         if (cp->ci_bufptr != NULL && cp->ci_bufsiz > 0)
  334                 fmd_hdl_free(hdl, cp->ci_bufptr, cp->ci_bufsiz);
  335 
  336         fmd_hdl_free(hdl, cp, sizeof (fmd_case_t));
  337 }
  338 
  339 void
  340 fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
  341 {
  342         fmd_hdl_debug(hdl, "case resolved by uuid (%s)", uuid);
  343 }
  344 
  345 boolean_t
  346 fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
  347 {
  348         (void) hdl;
  349         return (cp->ci_state >= FMD_CASE_SOLVED);
  350 }
  351 
  352 void
  353 fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
  354 {
  355         (void) hdl, (void) cp, (void) ep;
  356 }
  357 
  358 static void
  359 zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
  360 {
  361         nvlist_t *rsrc;
  362         char *strval;
  363         uint64_t guid;
  364         uint8_t byte;
  365 
  366         zed_log_msg(LOG_INFO, "\nzed_fault_event:");
  367 
  368         if (uuid != NULL)
  369                 zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_UUID, uuid);
  370         if (nvlist_lookup_string(nvl, FM_CLASS, &strval) == 0)
  371                 zed_log_msg(LOG_INFO, "\t%s: %s", FM_CLASS, strval);
  372         if (code != NULL)
  373                 zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
  374         if (nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &byte) == 0)
  375                 zed_log_msg(LOG_INFO, "\t%s: %hhu", FM_FAULT_CERTAINTY, byte);
  376         if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
  377                 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
  378                         zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
  379                             strval);
  380                 if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_POOL, &guid) == 0)
  381                         zed_log_msg(LOG_INFO, "\t%s: %llu", FM_FMRI_ZFS_POOL,
  382                             guid);
  383                 if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_VDEV, &guid) == 0)
  384                         zed_log_msg(LOG_INFO, "\t%s: %llu \n", FM_FMRI_ZFS_VDEV,
  385                             guid);
  386         }
  387 }
  388 
  389 static const char *
  390 fmd_fault_mkcode(nvlist_t *fault)
  391 {
  392         char *class;
  393         const char *code = "-";
  394 
  395         /*
  396          * Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
  397          */
  398         if (nvlist_lookup_string(fault, FM_CLASS, &class) == 0) {
  399                 if (strcmp(class, "fault.fs.zfs.vdev.io") == 0)
  400                         code = "ZFS-8000-FD";
  401                 else if (strcmp(class, "fault.fs.zfs.vdev.checksum") == 0)
  402                         code = "ZFS-8000-GH";
  403                 else if (strcmp(class, "fault.fs.zfs.io_failure_wait") == 0)
  404                         code = "ZFS-8000-HC";
  405                 else if (strcmp(class, "fault.fs.zfs.io_failure_continue") == 0)
  406                         code = "ZFS-8000-JQ";
  407                 else if (strcmp(class, "fault.fs.zfs.log_replay") == 0)
  408                         code = "ZFS-8000-K4";
  409                 else if (strcmp(class, "fault.fs.zfs.pool") == 0)
  410                         code = "ZFS-8000-CS";
  411                 else if (strcmp(class, "fault.fs.zfs.device") == 0)
  412                         code = "ZFS-8000-D3";
  413 
  414         }
  415         return (code);
  416 }
  417 
  418 void
  419 fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
  420 {
  421         nvlist_t *nvl;
  422         const char *code = fmd_fault_mkcode(fault);
  423         int64_t tod[2];
  424         int err = 0;
  425 
  426         /*
  427          * payload derived from fmd_protocol_list()
  428          */
  429 
  430         (void) gettimeofday(&cp->ci_tv, NULL);
  431         tod[0] = cp->ci_tv.tv_sec;
  432         tod[1] = cp->ci_tv.tv_usec;
  433 
  434         nvl = fmd_nvl_alloc(hdl, FMD_SLEEP);
  435 
  436         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_SUSPECT_VERSION);
  437         err |= nvlist_add_string(nvl, FM_CLASS, FM_LIST_SUSPECT_CLASS);
  438         err |= nvlist_add_string(nvl, FM_SUSPECT_UUID, cp->ci_uuid);
  439         err |= nvlist_add_string(nvl, FM_SUSPECT_DIAG_CODE, code);
  440         err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
  441         err |= nvlist_add_uint32(nvl, FM_SUSPECT_FAULT_SZ, 1);
  442         err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
  443             (const nvlist_t **)&fault, 1);
  444 
  445         if (err)
  446                 zed_log_die("failed to populate nvlist");
  447 
  448         zed_log_fault(fault, cp->ci_uuid, code);
  449         zfs_agent_post_event(FM_LIST_SUSPECT_CLASS, NULL, nvl);
  450 
  451         nvlist_free(nvl);
  452         nvlist_free(fault);
  453 }
  454 
  455 void
  456 fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
  457 {
  458         (void) hdl;
  459         cp->ci_data = data;
  460 }
  461 
  462 void *
  463 fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
  464 {
  465         (void) hdl;
  466         return (cp->ci_data);
  467 }
  468 
  469 void
  470 fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
  471 {
  472         assert(strcmp(name, "data") == 0), (void) name;
  473         assert(cp->ci_bufptr == NULL);
  474         assert(size < (1024 * 1024));
  475 
  476         cp->ci_bufptr = fmd_hdl_alloc(hdl, size, FMD_SLEEP);
  477         cp->ci_bufsiz = size;
  478 }
  479 
  480 void
  481 fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
  482     const char *name, void *buf, size_t size)
  483 {
  484         (void) hdl;
  485         assert(strcmp(name, "data") == 0), (void) name;
  486         assert(cp->ci_bufptr != NULL);
  487         assert(size <= cp->ci_bufsiz);
  488 
  489         memcpy(buf, cp->ci_bufptr, size);
  490 }
  491 
  492 void
  493 fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
  494     const char *name, const void *buf, size_t size)
  495 {
  496         (void) hdl;
  497         assert(strcmp(name, "data") == 0), (void) name;
  498         assert(cp->ci_bufptr != NULL);
  499         assert(cp->ci_bufsiz >= size);
  500 
  501         memcpy(cp->ci_bufptr, buf, size);
  502 }
  503 
  504 /* SERD Engines */
  505 
  506 void
  507 fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t)
  508 {
  509         fmd_module_t *mp = (fmd_module_t *)hdl;
  510 
  511         if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) {
  512                 zed_log_msg(LOG_ERR, "failed to create SERD engine '%s': "
  513                     " name already exists", name);
  514                 return;
  515         }
  516 
  517         (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t);
  518 }
  519 
  520 void
  521 fmd_serd_destroy(fmd_hdl_t *hdl, const char *name)
  522 {
  523         fmd_module_t *mp = (fmd_module_t *)hdl;
  524 
  525         fmd_serd_eng_delete(&mp->mod_serds, name);
  526 
  527         fmd_hdl_debug(hdl, "serd_destroy %s", name);
  528 }
  529 
  530 int
  531 fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
  532 {
  533         fmd_module_t *mp = (fmd_module_t *)hdl;
  534 
  535         return (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
  536 }
  537 
  538 void
  539 fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
  540 {
  541         fmd_module_t *mp = (fmd_module_t *)hdl;
  542         fmd_serd_eng_t *sgp;
  543 
  544         if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
  545                 zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
  546                 return;
  547         }
  548 
  549         fmd_serd_eng_reset(sgp);
  550 
  551         fmd_hdl_debug(hdl, "serd_reset %s", name);
  552 }
  553 
  554 int
  555 fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep)
  556 {
  557         fmd_module_t *mp = (fmd_module_t *)hdl;
  558         fmd_serd_eng_t *sgp;
  559         int err;
  560 
  561         if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
  562                 zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
  563                     name);
  564                 return (0);
  565         }
  566         err = fmd_serd_eng_record(sgp, ep->ev_hrt);
  567 
  568         return (err);
  569 }
  570 
  571 /* FMD Timers */
  572 
  573 static void
  574 _timer_notify(union sigval sv)
  575 {
  576         fmd_timer_t *ftp = sv.sival_ptr;
  577         fmd_hdl_t *hdl = ftp->ft_hdl;
  578         fmd_module_t *mp = (fmd_module_t *)hdl;
  579         const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
  580         struct itimerspec its;
  581 
  582         fmd_hdl_debug(hdl, "timer fired (%p)", ftp->ft_tid);
  583 
  584         /* disarm the timer */
  585         memset(&its, 0, sizeof (struct itimerspec));
  586         timer_settime(ftp->ft_tid, 0, &its, NULL);
  587 
  588         /* Note that the fmdo_timeout can remove this timer */
  589         if (ops->fmdo_timeout != NULL)
  590                 ops->fmdo_timeout(hdl, ftp, ftp->ft_arg);
  591 }
  592 
  593 /*
  594  * Install a new timer which will fire at least delta nanoseconds after the
  595  * current time. After the timeout has expired, the module's fmdo_timeout
  596  * entry point is called.
  597  */
  598 fmd_timer_t *
  599 fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
  600 {
  601         (void) ep;
  602         struct sigevent sev;
  603         struct itimerspec its;
  604         fmd_timer_t *ftp;
  605 
  606         ftp = fmd_hdl_alloc(hdl, sizeof (fmd_timer_t), FMD_SLEEP);
  607         ftp->ft_arg = arg;
  608         ftp->ft_hdl = hdl;
  609 
  610         its.it_value.tv_sec = delta / 1000000000;
  611         its.it_value.tv_nsec = delta % 1000000000;
  612         its.it_interval.tv_sec = its.it_value.tv_sec;
  613         its.it_interval.tv_nsec = its.it_value.tv_nsec;
  614 
  615         sev.sigev_notify = SIGEV_THREAD;
  616         sev.sigev_notify_function = _timer_notify;
  617         sev.sigev_notify_attributes = NULL;
  618         sev.sigev_value.sival_ptr = ftp;
  619         sev.sigev_signo = 0;
  620 
  621         timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
  622         timer_settime(ftp->ft_tid, 0, &its, NULL);
  623 
  624         fmd_hdl_debug(hdl, "installing timer for %d secs (%p)",
  625             (int)its.it_value.tv_sec, ftp->ft_tid);
  626 
  627         return (ftp);
  628 }
  629 
  630 void
  631 fmd_timer_remove(fmd_hdl_t *hdl, fmd_timer_t *ftp)
  632 {
  633         fmd_hdl_debug(hdl, "removing timer (%p)", ftp->ft_tid);
  634 
  635         timer_delete(ftp->ft_tid);
  636 
  637         fmd_hdl_free(hdl, ftp, sizeof (fmd_timer_t));
  638 }
  639 
  640 /* Name-Value Pair Lists */
  641 
  642 nvlist_t *
  643 fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
  644     nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
  645 {
  646         (void) hdl;
  647         nvlist_t *nvl;
  648         int err = 0;
  649 
  650         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
  651                 zed_log_die("failed to xalloc fault nvlist");
  652 
  653         err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FAULT_VERSION);
  654         err |= nvlist_add_string(nvl, FM_CLASS, class);
  655         err |= nvlist_add_uint8(nvl, FM_FAULT_CERTAINTY, certainty);
  656 
  657         if (asru != NULL)
  658                 err |= nvlist_add_nvlist(nvl, FM_FAULT_ASRU, asru);
  659         if (fru != NULL)
  660                 err |= nvlist_add_nvlist(nvl, FM_FAULT_FRU, fru);
  661         if (resource != NULL)
  662                 err |= nvlist_add_nvlist(nvl, FM_FAULT_RESOURCE, resource);
  663 
  664         if (err)
  665                 zed_log_die("failed to populate nvlist: %s\n", strerror(err));
  666 
  667         return (nvl);
  668 }
  669 
  670 /*
  671  * sourced from fmd_string.c
  672  */
  673 static int
  674 fmd_strmatch(const char *s, const char *p)
  675 {
  676         char c;
  677 
  678         if (p == NULL)
  679                 return (0);
  680 
  681         if (s == NULL)
  682                 s = ""; /* treat NULL string as the empty string */
  683 
  684         do {
  685                 if ((c = *p++) == '\0')
  686                         return (*s == '\0');
  687 
  688                 if (c == '*') {
  689                         while (*p == '*')
  690                                 p++; /* consecutive *'s can be collapsed */
  691 
  692                         if (*p == '\0')
  693                                 return (1);
  694 
  695                         while (*s != '\0') {
  696                                 if (fmd_strmatch(s++, p) != 0)
  697                                         return (1);
  698                         }
  699 
  700                         return (0);
  701                 }
  702         } while (c == *s++);
  703 
  704         return (0);
  705 }
  706 
  707 int
  708 fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
  709 {
  710         (void) hdl;
  711         char *class;
  712 
  713         return (nvl != NULL &&
  714             nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
  715             fmd_strmatch(class, pattern));
  716 }
  717 
  718 nvlist_t *
  719 fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
  720 {
  721         (void) hdl, (void) flags;
  722         nvlist_t *nvl = NULL;
  723 
  724         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
  725                 return (NULL);
  726 
  727         return (nvl);
  728 }
  729 
  730 
  731 /*
  732  * ZED Agent specific APIs
  733  */
  734 
  735 fmd_hdl_t *
  736 fmd_module_hdl(const char *name)
  737 {
  738         if (strcmp(name, "zfs-retire") == 0)
  739                 return ((fmd_hdl_t *)&zfs_retire_module);
  740         if (strcmp(name, "zfs-diagnosis") == 0)
  741                 return ((fmd_hdl_t *)&zfs_diagnosis_module);
  742 
  743         return (NULL);
  744 }
  745 
  746 boolean_t
  747 fmd_module_initialized(fmd_hdl_t *hdl)
  748 {
  749         fmd_module_t *mp = (fmd_module_t *)hdl;
  750 
  751         return (mp->mod_info != NULL);
  752 }
  753 
  754 /*
  755  * fmd_module_recv is called for each event that is received by
  756  * the fault manager that has a class that matches one of the
  757  * module's subscriptions.
  758  */
  759 void
  760 fmd_module_recv(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class)
  761 {
  762         fmd_module_t *mp = (fmd_module_t *)hdl;
  763         const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
  764         fmd_event_t faux_event = {0};
  765         int64_t *tv;
  766         uint_t n;
  767 
  768         /*
  769          * Will need to normalized this if we persistently store the case data
  770          */
  771         if (nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0)
  772                 faux_event.ev_hrt = tv[0] * NANOSEC + tv[1];
  773         else
  774                 faux_event.ev_hrt = 0;
  775 
  776         ops->fmdo_recv(hdl, &faux_event, nvl, class);
  777 
  778         mp->mod_stats.ms_accepted.fmds_value.ui64++;
  779 
  780         /* TBD - should we initiate fm_module_gc() periodically? */
  781 }

Cache object: 1ce8e943141abd732f08dcdcebd392f4


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