Optimize RAIDZ expansion
[zfs.git] / cmd / zed / agents / fmd_api.c
blobfe43e2ab971e05e9c2857f7c466973f6498ee243
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016, Intel Corporation.
25 * Copyright (c) 2023, Klara Inc.
29 * This file implements the minimal FMD module API required to support the
30 * fault logic modules in ZED. This support includes module registration,
31 * memory allocation, module property accessors, basic case management,
32 * one-shot timers and SERD engines.
34 * In the ZED runtime, the modules are called from a single thread so no
35 * locking is required in this emulated FMD environment.
38 #include <sys/types.h>
39 #include <sys/fm/protocol.h>
40 #include <uuid/uuid.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <time.h>
45 #include "fmd_api.h"
46 #include "fmd_serd.h"
48 #include "zfs_agents.h"
49 #include "../zed_log.h"
51 typedef struct fmd_modstat {
52 fmd_stat_t ms_accepted; /* total events accepted by module */
53 fmd_stat_t ms_caseopen; /* cases currently open */
54 fmd_stat_t ms_casesolved; /* total cases solved by module */
55 fmd_stat_t ms_caseclosed; /* total cases closed by module */
56 } fmd_modstat_t;
58 typedef struct fmd_module {
59 const char *mod_name; /* basename of module (ro) */
60 const fmd_hdl_info_t *mod_info; /* module info registered with handle */
61 void *mod_spec; /* fmd_hdl_get/setspecific data value */
62 fmd_stat_t *mod_ustat; /* module specific custom stats */
63 uint_t mod_ustat_cnt; /* count of ustat stats */
64 fmd_modstat_t mod_stats; /* fmd built-in per-module statistics */
65 fmd_serd_hash_t mod_serds; /* hash of serd engs owned by module */
66 char *mod_vers; /* a copy of module version string */
67 } fmd_module_t;
70 * ZED has two FMD hardwired module instances
72 fmd_module_t zfs_retire_module;
73 fmd_module_t zfs_diagnosis_module;
76 * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
79 #ifdef DEBUG
80 const char *
81 _umem_debug_init(void)
83 return ("default,verbose"); /* $UMEM_DEBUG setting */
86 const char *
87 _umem_logging_init(void)
89 return ("fail,contents"); /* $UMEM_LOGGING setting */
91 #endif
94 * Register a module with fmd and finish module initialization.
95 * Returns an integer indicating whether it succeeded (zero) or
96 * failed (non-zero).
98 int
99 fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
101 (void) version;
102 fmd_module_t *mp = (fmd_module_t *)hdl;
104 mp->mod_info = mip;
105 mp->mod_name = mip->fmdi_desc + 4; /* drop 'ZFS ' prefix */
106 mp->mod_spec = NULL;
108 /* bare minimum module stats */
109 (void) strcpy(mp->mod_stats.ms_accepted.fmds_name, "fmd.accepted");
110 (void) strcpy(mp->mod_stats.ms_caseopen.fmds_name, "fmd.caseopen");
111 (void) strcpy(mp->mod_stats.ms_casesolved.fmds_name, "fmd.casesolved");
112 (void) strcpy(mp->mod_stats.ms_caseclosed.fmds_name, "fmd.caseclosed");
114 fmd_serd_hash_create(&mp->mod_serds);
116 fmd_hdl_debug(hdl, "register module");
118 return (0);
121 void
122 fmd_hdl_unregister(fmd_hdl_t *hdl)
124 fmd_module_t *mp = (fmd_module_t *)hdl;
125 fmd_modstat_t *msp = &mp->mod_stats;
126 const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
128 /* dump generic module stats */
129 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_accepted.fmds_name,
130 msp->ms_accepted.fmds_value.ui64);
131 if (ops->fmdo_close != NULL) {
132 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseopen.fmds_name,
133 msp->ms_caseopen.fmds_value.ui64);
134 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_casesolved.fmds_name,
135 msp->ms_casesolved.fmds_value.ui64);
136 fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseclosed.fmds_name,
137 msp->ms_caseclosed.fmds_value.ui64);
140 /* dump module specific stats */
141 if (mp->mod_ustat != NULL) {
142 int i;
144 for (i = 0; i < mp->mod_ustat_cnt; i++) {
145 fmd_hdl_debug(hdl, "%s: %llu",
146 mp->mod_ustat[i].fmds_name,
147 mp->mod_ustat[i].fmds_value.ui64);
151 fmd_serd_hash_destroy(&mp->mod_serds);
153 fmd_hdl_debug(hdl, "unregister module");
157 * fmd_hdl_setspecific() is used to associate a data pointer with
158 * the specified handle for the duration of the module's lifetime.
159 * This pointer can be retrieved using fmd_hdl_getspecific().
161 void
162 fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec)
164 fmd_module_t *mp = (fmd_module_t *)hdl;
166 mp->mod_spec = spec;
170 * Return the module-specific data pointer previously associated
171 * with the handle using fmd_hdl_setspecific().
173 void *
174 fmd_hdl_getspecific(fmd_hdl_t *hdl)
176 fmd_module_t *mp = (fmd_module_t *)hdl;
178 return (mp->mod_spec);
181 void *
182 fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
184 (void) hdl;
185 return (umem_alloc(size, flags));
188 void *
189 fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
191 (void) hdl;
192 return (umem_zalloc(size, flags));
195 void
196 fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
198 (void) hdl;
199 umem_free(data, size);
203 * Record a module debug message using the specified format.
205 void
206 fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
208 char message[256];
209 va_list vargs;
210 fmd_module_t *mp = (fmd_module_t *)hdl;
212 va_start(vargs, format);
213 (void) vsnprintf(message, sizeof (message), format, vargs);
214 va_end(vargs);
216 /* prefix message with module name */
217 zed_log_msg(LOG_INFO, "%s: %s", mp->mod_name, message);
220 /* Property Retrieval */
222 int32_t
223 fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
225 (void) hdl;
228 * These can be looked up in mp->modinfo->fmdi_props
229 * For now we just hard code for phase 2. In the
230 * future, there can be a ZED based override.
232 if (strcmp(name, "spare_on_remove") == 0)
233 return (1);
235 return (0);
238 /* FMD Statistics */
240 fmd_stat_t *
241 fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t nstats, fmd_stat_t *statv)
243 fmd_module_t *mp = (fmd_module_t *)hdl;
245 if (flags == FMD_STAT_NOALLOC) {
246 mp->mod_ustat = statv;
247 mp->mod_ustat_cnt = nstats;
250 return (statv);
253 /* Case Management */
255 fmd_case_t *
256 fmd_case_open(fmd_hdl_t *hdl, void *data)
258 fmd_module_t *mp = (fmd_module_t *)hdl;
259 uuid_t uuid;
261 fmd_case_t *cp;
263 cp = fmd_hdl_zalloc(hdl, sizeof (fmd_case_t), FMD_SLEEP);
264 cp->ci_mod = hdl;
265 cp->ci_state = FMD_CASE_UNSOLVED;
266 cp->ci_flags = FMD_CF_DIRTY;
267 cp->ci_data = data;
268 cp->ci_bufptr = NULL;
269 cp->ci_bufsiz = 0;
271 uuid_generate(uuid);
272 uuid_unparse(uuid, cp->ci_uuid);
274 fmd_hdl_debug(hdl, "case opened (%s)", cp->ci_uuid);
275 mp->mod_stats.ms_caseopen.fmds_value.ui64++;
277 return (cp);
280 void
281 fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp)
283 fmd_module_t *mp = (fmd_module_t *)hdl;
286 * For ZED, the event was already sent from fmd_case_add_suspect()
289 if (cp->ci_state >= FMD_CASE_SOLVED)
290 fmd_hdl_debug(hdl, "case is already solved or closed");
292 cp->ci_state = FMD_CASE_SOLVED;
294 fmd_hdl_debug(hdl, "case solved (%s)", cp->ci_uuid);
295 mp->mod_stats.ms_casesolved.fmds_value.ui64++;
298 void
299 fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp)
301 fmd_module_t *mp = (fmd_module_t *)hdl;
302 const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
304 fmd_hdl_debug(hdl, "case closed (%s)", cp->ci_uuid);
306 if (ops->fmdo_close != NULL)
307 ops->fmdo_close(hdl, cp);
309 mp->mod_stats.ms_caseopen.fmds_value.ui64--;
310 mp->mod_stats.ms_caseclosed.fmds_value.ui64++;
312 if (cp->ci_bufptr != NULL && cp->ci_bufsiz > 0)
313 fmd_hdl_free(hdl, cp->ci_bufptr, cp->ci_bufsiz);
315 fmd_hdl_free(hdl, cp, sizeof (fmd_case_t));
318 void
319 fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
321 fmd_hdl_debug(hdl, "case resolved by uuid (%s)", uuid);
324 boolean_t
325 fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
327 (void) hdl;
328 return (cp->ci_state >= FMD_CASE_SOLVED);
331 void
332 fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
334 (void) hdl, (void) cp, (void) ep;
337 static void
338 zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
340 nvlist_t *rsrc;
341 const char *strval;
342 uint64_t guid;
343 uint8_t byte;
345 zed_log_msg(LOG_INFO, "\nzed_fault_event:");
347 if (uuid != NULL)
348 zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_UUID, uuid);
349 if (nvlist_lookup_string(nvl, FM_CLASS, &strval) == 0)
350 zed_log_msg(LOG_INFO, "\t%s: %s", FM_CLASS, strval);
351 if (code != NULL)
352 zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
353 if (nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &byte) == 0)
354 zed_log_msg(LOG_INFO, "\t%s: %hhu", FM_FAULT_CERTAINTY, byte);
355 if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
356 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
357 zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
358 strval);
359 if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_POOL, &guid) == 0)
360 zed_log_msg(LOG_INFO, "\t%s: %llu", FM_FMRI_ZFS_POOL,
361 guid);
362 if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_VDEV, &guid) == 0)
363 zed_log_msg(LOG_INFO, "\t%s: %llu \n", FM_FMRI_ZFS_VDEV,
364 guid);
368 static const char *
369 fmd_fault_mkcode(nvlist_t *fault)
371 const char *class;
372 const char *code = "-";
375 * Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
377 if (nvlist_lookup_string(fault, FM_CLASS, &class) == 0) {
378 if (strcmp(class, "fault.fs.zfs.vdev.io") == 0)
379 code = "ZFS-8000-FD";
380 else if (strcmp(class, "fault.fs.zfs.vdev.checksum") == 0)
381 code = "ZFS-8000-GH";
382 else if (strcmp(class, "fault.fs.zfs.io_failure_wait") == 0)
383 code = "ZFS-8000-HC";
384 else if (strcmp(class, "fault.fs.zfs.io_failure_continue") == 0)
385 code = "ZFS-8000-JQ";
386 else if (strcmp(class, "fault.fs.zfs.log_replay") == 0)
387 code = "ZFS-8000-K4";
388 else if (strcmp(class, "fault.fs.zfs.pool") == 0)
389 code = "ZFS-8000-CS";
390 else if (strcmp(class, "fault.fs.zfs.device") == 0)
391 code = "ZFS-8000-D3";
394 return (code);
397 void
398 fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
400 nvlist_t *nvl;
401 const char *code = fmd_fault_mkcode(fault);
402 int64_t tod[2];
403 int err = 0;
406 * payload derived from fmd_protocol_list()
409 (void) gettimeofday(&cp->ci_tv, NULL);
410 tod[0] = cp->ci_tv.tv_sec;
411 tod[1] = cp->ci_tv.tv_usec;
413 nvl = fmd_nvl_alloc(hdl, FMD_SLEEP);
415 err |= nvlist_add_uint8(nvl, FM_VERSION, FM_SUSPECT_VERSION);
416 err |= nvlist_add_string(nvl, FM_CLASS, FM_LIST_SUSPECT_CLASS);
417 err |= nvlist_add_string(nvl, FM_SUSPECT_UUID, cp->ci_uuid);
418 err |= nvlist_add_string(nvl, FM_SUSPECT_DIAG_CODE, code);
419 err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
420 err |= nvlist_add_uint32(nvl, FM_SUSPECT_FAULT_SZ, 1);
421 err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
422 (const nvlist_t **)&fault, 1);
424 if (err)
425 zed_log_die("failed to populate nvlist");
427 zed_log_fault(fault, cp->ci_uuid, code);
428 zfs_agent_post_event(FM_LIST_SUSPECT_CLASS, NULL, nvl);
430 nvlist_free(nvl);
431 nvlist_free(fault);
434 void
435 fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
437 (void) hdl;
438 cp->ci_data = data;
441 void *
442 fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
444 (void) hdl;
445 return (cp->ci_data);
448 void
449 fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
451 assert(strcmp(name, "data") == 0), (void) name;
452 assert(cp->ci_bufptr == NULL);
453 assert(size < (1024 * 1024));
455 cp->ci_bufptr = fmd_hdl_alloc(hdl, size, FMD_SLEEP);
456 cp->ci_bufsiz = size;
459 void
460 fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
461 const char *name, void *buf, size_t size)
463 (void) hdl;
464 assert(strcmp(name, "data") == 0), (void) name;
465 assert(cp->ci_bufptr != NULL);
466 assert(size <= cp->ci_bufsiz);
468 memcpy(buf, cp->ci_bufptr, size);
471 void
472 fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
473 const char *name, const void *buf, size_t size)
475 (void) hdl;
476 assert(strcmp(name, "data") == 0), (void) name;
477 assert(cp->ci_bufptr != NULL);
478 assert(cp->ci_bufsiz >= size);
480 memcpy(cp->ci_bufptr, buf, size);
483 /* SERD Engines */
485 void
486 fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t)
488 fmd_module_t *mp = (fmd_module_t *)hdl;
490 if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) {
491 zed_log_msg(LOG_ERR, "failed to create SERD engine '%s': "
492 " name already exists", name);
493 return;
496 (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t);
499 void
500 fmd_serd_destroy(fmd_hdl_t *hdl, const char *name)
502 fmd_module_t *mp = (fmd_module_t *)hdl;
504 fmd_serd_eng_delete(&mp->mod_serds, name);
506 fmd_hdl_debug(hdl, "serd_destroy %s", name);
510 fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
512 fmd_module_t *mp = (fmd_module_t *)hdl;
514 return (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
518 fmd_serd_active(fmd_hdl_t *hdl, const char *name)
520 fmd_module_t *mp = (fmd_module_t *)hdl;
521 fmd_serd_eng_t *sgp;
523 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
524 zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
525 return (0);
527 return (fmd_serd_eng_fired(sgp) || !fmd_serd_eng_empty(sgp));
530 void
531 fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
533 fmd_module_t *mp = (fmd_module_t *)hdl;
534 fmd_serd_eng_t *sgp;
536 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
537 zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
538 } else {
539 fmd_serd_eng_reset(sgp);
540 fmd_hdl_debug(hdl, "serd_reset %s", name);
545 fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep)
547 fmd_module_t *mp = (fmd_module_t *)hdl;
548 fmd_serd_eng_t *sgp;
550 if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
551 zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
552 name);
553 return (0);
555 return (fmd_serd_eng_record(sgp, ep->ev_hrt));
558 void
559 fmd_serd_gc(fmd_hdl_t *hdl)
561 fmd_module_t *mp = (fmd_module_t *)hdl;
563 fmd_serd_hash_apply(&mp->mod_serds, fmd_serd_eng_gc, NULL);
566 /* FMD Timers */
568 static void
569 _timer_notify(union sigval sv)
571 fmd_timer_t *ftp = sv.sival_ptr;
572 fmd_hdl_t *hdl = ftp->ft_hdl;
573 fmd_module_t *mp = (fmd_module_t *)hdl;
574 const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
575 struct itimerspec its;
577 fmd_hdl_debug(hdl, "%s timer fired (%p)", mp->mod_name, ftp->ft_tid);
579 /* disarm the timer */
580 memset(&its, 0, sizeof (struct itimerspec));
581 timer_settime(ftp->ft_tid, 0, &its, NULL);
583 /* Note that the fmdo_timeout can remove this timer */
584 if (ops->fmdo_timeout != NULL)
585 ops->fmdo_timeout(hdl, ftp, ftp->ft_arg);
589 * Install a new timer which will fire at least delta nanoseconds after the
590 * current time. After the timeout has expired, the module's fmdo_timeout
591 * entry point is called.
593 fmd_timer_t *
594 fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
596 (void) ep;
597 struct sigevent sev;
598 struct itimerspec its;
599 fmd_timer_t *ftp;
601 ftp = fmd_hdl_alloc(hdl, sizeof (fmd_timer_t), FMD_SLEEP);
602 ftp->ft_arg = arg;
603 ftp->ft_hdl = hdl;
605 its.it_value.tv_sec = delta / 1000000000;
606 its.it_value.tv_nsec = delta % 1000000000;
607 its.it_interval.tv_sec = its.it_value.tv_sec;
608 its.it_interval.tv_nsec = its.it_value.tv_nsec;
610 sev.sigev_notify = SIGEV_THREAD;
611 sev.sigev_notify_function = _timer_notify;
612 sev.sigev_notify_attributes = NULL;
613 sev.sigev_value.sival_ptr = ftp;
614 sev.sigev_signo = 0;
616 timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
617 timer_settime(ftp->ft_tid, 0, &its, NULL);
619 fmd_hdl_debug(hdl, "installing timer for %d secs (%p)",
620 (int)its.it_value.tv_sec, ftp->ft_tid);
622 return (ftp);
625 void
626 fmd_timer_remove(fmd_hdl_t *hdl, fmd_timer_t *ftp)
628 fmd_hdl_debug(hdl, "removing timer (%p)", ftp->ft_tid);
630 timer_delete(ftp->ft_tid);
632 fmd_hdl_free(hdl, ftp, sizeof (fmd_timer_t));
635 /* Name-Value Pair Lists */
637 nvlist_t *
638 fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
639 nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
641 (void) hdl;
642 nvlist_t *nvl;
643 int err = 0;
645 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
646 zed_log_die("failed to xalloc fault nvlist");
648 err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FAULT_VERSION);
649 err |= nvlist_add_string(nvl, FM_CLASS, class);
650 err |= nvlist_add_uint8(nvl, FM_FAULT_CERTAINTY, certainty);
652 if (asru != NULL)
653 err |= nvlist_add_nvlist(nvl, FM_FAULT_ASRU, asru);
654 if (fru != NULL)
655 err |= nvlist_add_nvlist(nvl, FM_FAULT_FRU, fru);
656 if (resource != NULL)
657 err |= nvlist_add_nvlist(nvl, FM_FAULT_RESOURCE, resource);
659 if (err)
660 zed_log_die("failed to populate nvlist: %s\n", strerror(err));
662 return (nvl);
666 * sourced from fmd_string.c
668 static int
669 fmd_strmatch(const char *s, const char *p)
671 char c;
673 if (p == NULL)
674 return (0);
676 if (s == NULL)
677 s = ""; /* treat NULL string as the empty string */
679 do {
680 if ((c = *p++) == '\0')
681 return (*s == '\0');
683 if (c == '*') {
684 while (*p == '*')
685 p++; /* consecutive *'s can be collapsed */
687 if (*p == '\0')
688 return (1);
690 while (*s != '\0') {
691 if (fmd_strmatch(s++, p) != 0)
692 return (1);
695 return (0);
697 } while (c == *s++);
699 return (0);
703 fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
705 (void) hdl;
706 const char *class;
708 return (nvl != NULL &&
709 nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
710 fmd_strmatch(class, pattern));
713 nvlist_t *
714 fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
716 (void) hdl, (void) flags;
717 nvlist_t *nvl = NULL;
719 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
720 return (NULL);
722 return (nvl);
727 * ZED Agent specific APIs
730 fmd_hdl_t *
731 fmd_module_hdl(const char *name)
733 if (strcmp(name, "zfs-retire") == 0)
734 return ((fmd_hdl_t *)&zfs_retire_module);
735 if (strcmp(name, "zfs-diagnosis") == 0)
736 return ((fmd_hdl_t *)&zfs_diagnosis_module);
738 return (NULL);
741 boolean_t
742 fmd_module_initialized(fmd_hdl_t *hdl)
744 fmd_module_t *mp = (fmd_module_t *)hdl;
746 return (mp->mod_info != NULL);
750 * fmd_module_recv is called for each event that is received by
751 * the fault manager that has a class that matches one of the
752 * module's subscriptions.
754 void
755 fmd_module_recv(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class)
757 fmd_module_t *mp = (fmd_module_t *)hdl;
758 const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
759 fmd_event_t faux_event = {0};
760 int64_t *tv;
761 uint_t n;
764 * Will need to normalized this if we persistently store the case data
766 if (nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0)
767 faux_event.ev_hrt = tv[0] * NANOSEC + tv[1];
768 else
769 faux_event.ev_hrt = 0;
771 ops->fmdo_recv(hdl, &faux_event, nvl, class);
773 mp->mod_stats.ms_accepted.fmds_value.ui64++;
775 /* TBD - should we initiate fm_module_gc() periodically? */