1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License Version 1.0 (CDDL-1.0). 6eda14cbcSMatt Macy * You can obtain a copy of the license from the top-level file 7eda14cbcSMatt Macy * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. 8eda14cbcSMatt Macy * You may not use this file except in compliance with the license. 9eda14cbcSMatt Macy * 10eda14cbcSMatt Macy * CDDL HEADER END 11eda14cbcSMatt Macy */ 12eda14cbcSMatt Macy 13eda14cbcSMatt Macy /* 14eda14cbcSMatt Macy * Copyright (c) 2016, Intel Corporation. 15eda14cbcSMatt Macy * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com> 16eda14cbcSMatt Macy */ 17eda14cbcSMatt Macy 18eda14cbcSMatt Macy #include <libnvpair.h> 19eda14cbcSMatt Macy #include <libzfs.h> 20eda14cbcSMatt Macy #include <stddef.h> 21eda14cbcSMatt Macy #include <stdlib.h> 22eda14cbcSMatt Macy #include <string.h> 23eda14cbcSMatt Macy #include <sys/list.h> 24eda14cbcSMatt Macy #include <sys/time.h> 25eda14cbcSMatt Macy #include <sys/sysevent/eventdefs.h> 26eda14cbcSMatt Macy #include <sys/sysevent/dev.h> 27eda14cbcSMatt Macy #include <sys/fm/protocol.h> 28eda14cbcSMatt Macy #include <sys/fm/fs/zfs.h> 29eda14cbcSMatt Macy #include <pthread.h> 30eda14cbcSMatt Macy #include <unistd.h> 31eda14cbcSMatt Macy 32eda14cbcSMatt Macy #include "zfs_agents.h" 33eda14cbcSMatt Macy #include "fmd_api.h" 34eda14cbcSMatt Macy #include "../zed_log.h" 35eda14cbcSMatt Macy 36eda14cbcSMatt Macy /* 37eda14cbcSMatt Macy * agent dispatch code 38eda14cbcSMatt Macy */ 39eda14cbcSMatt Macy 40eda14cbcSMatt Macy static pthread_mutex_t agent_lock = PTHREAD_MUTEX_INITIALIZER; 41eda14cbcSMatt Macy static pthread_cond_t agent_cond = PTHREAD_COND_INITIALIZER; 42eda14cbcSMatt Macy static list_t agent_events; /* list of pending events */ 43eda14cbcSMatt Macy static int agent_exiting; 44eda14cbcSMatt Macy 45eda14cbcSMatt Macy typedef struct agent_event { 46eda14cbcSMatt Macy char ae_class[64]; 47eda14cbcSMatt Macy char ae_subclass[32]; 48eda14cbcSMatt Macy nvlist_t *ae_nvl; 49eda14cbcSMatt Macy list_node_t ae_node; 50eda14cbcSMatt Macy } agent_event_t; 51eda14cbcSMatt Macy 52eda14cbcSMatt Macy pthread_t g_agents_tid; 53eda14cbcSMatt Macy 54eda14cbcSMatt Macy libzfs_handle_t *g_zfs_hdl; 55eda14cbcSMatt Macy 56eda14cbcSMatt Macy /* guid search data */ 57eda14cbcSMatt Macy typedef enum device_type { 58eda14cbcSMatt Macy DEVICE_TYPE_L2ARC, /* l2arc device */ 59eda14cbcSMatt Macy DEVICE_TYPE_SPARE, /* spare device */ 60eda14cbcSMatt Macy DEVICE_TYPE_PRIMARY /* any primary pool storage device */ 61eda14cbcSMatt Macy } device_type_t; 62eda14cbcSMatt Macy 63eda14cbcSMatt Macy typedef struct guid_search { 64eda14cbcSMatt Macy uint64_t gs_pool_guid; 65eda14cbcSMatt Macy uint64_t gs_vdev_guid; 66eda14cbcSMatt Macy char *gs_devid; 67eda14cbcSMatt Macy device_type_t gs_vdev_type; 68eda14cbcSMatt Macy uint64_t gs_vdev_expandtime; /* vdev expansion time */ 69eda14cbcSMatt Macy } guid_search_t; 70eda14cbcSMatt Macy 71eda14cbcSMatt Macy /* 72eda14cbcSMatt Macy * Walks the vdev tree recursively looking for a matching devid. 73eda14cbcSMatt Macy * Returns B_TRUE as soon as a matching device is found, B_FALSE otherwise. 74eda14cbcSMatt Macy */ 75eda14cbcSMatt Macy static boolean_t 76eda14cbcSMatt Macy zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg) 77eda14cbcSMatt Macy { 78eda14cbcSMatt Macy guid_search_t *gsp = arg; 79eda14cbcSMatt Macy char *path = NULL; 80eda14cbcSMatt Macy uint_t c, children; 81eda14cbcSMatt Macy nvlist_t **child; 82eda14cbcSMatt Macy 83eda14cbcSMatt Macy /* 84eda14cbcSMatt Macy * First iterate over any children. 85eda14cbcSMatt Macy */ 86eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, 87eda14cbcSMatt Macy &child, &children) == 0) { 88eda14cbcSMatt Macy for (c = 0; c < children; c++) { 89eda14cbcSMatt Macy if (zfs_agent_iter_vdev(zhp, child[c], gsp)) { 90eda14cbcSMatt Macy gsp->gs_vdev_type = DEVICE_TYPE_PRIMARY; 91eda14cbcSMatt Macy return (B_TRUE); 92eda14cbcSMatt Macy } 93eda14cbcSMatt Macy } 94eda14cbcSMatt Macy } 95eda14cbcSMatt Macy /* 96eda14cbcSMatt Macy * Iterate over any spares and cache devices 97eda14cbcSMatt Macy */ 98eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_SPARES, 99eda14cbcSMatt Macy &child, &children) == 0) { 100eda14cbcSMatt Macy for (c = 0; c < children; c++) { 101eda14cbcSMatt Macy if (zfs_agent_iter_vdev(zhp, child[c], gsp)) { 102eda14cbcSMatt Macy gsp->gs_vdev_type = DEVICE_TYPE_L2ARC; 103eda14cbcSMatt Macy return (B_TRUE); 104eda14cbcSMatt Macy } 105eda14cbcSMatt Macy } 106eda14cbcSMatt Macy } 107eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_L2CACHE, 108eda14cbcSMatt Macy &child, &children) == 0) { 109eda14cbcSMatt Macy for (c = 0; c < children; c++) { 110eda14cbcSMatt Macy if (zfs_agent_iter_vdev(zhp, child[c], gsp)) { 111eda14cbcSMatt Macy gsp->gs_vdev_type = DEVICE_TYPE_SPARE; 112eda14cbcSMatt Macy return (B_TRUE); 113eda14cbcSMatt Macy } 114eda14cbcSMatt Macy } 115eda14cbcSMatt Macy } 116eda14cbcSMatt Macy /* 117eda14cbcSMatt Macy * On a devid match, grab the vdev guid and expansion time, if any. 118eda14cbcSMatt Macy */ 119eda14cbcSMatt Macy if (gsp->gs_devid != NULL && 120eda14cbcSMatt Macy (nvlist_lookup_string(nvl, ZPOOL_CONFIG_DEVID, &path) == 0) && 121eda14cbcSMatt Macy (strcmp(gsp->gs_devid, path) == 0)) { 122eda14cbcSMatt Macy (void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, 123eda14cbcSMatt Macy &gsp->gs_vdev_guid); 124eda14cbcSMatt Macy (void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_EXPANSION_TIME, 125eda14cbcSMatt Macy &gsp->gs_vdev_expandtime); 126eda14cbcSMatt Macy return (B_TRUE); 127eda14cbcSMatt Macy } 128eda14cbcSMatt Macy 129eda14cbcSMatt Macy return (B_FALSE); 130eda14cbcSMatt Macy } 131eda14cbcSMatt Macy 132eda14cbcSMatt Macy static int 133eda14cbcSMatt Macy zfs_agent_iter_pool(zpool_handle_t *zhp, void *arg) 134eda14cbcSMatt Macy { 135eda14cbcSMatt Macy guid_search_t *gsp = arg; 136eda14cbcSMatt Macy nvlist_t *config, *nvl; 137eda14cbcSMatt Macy 138eda14cbcSMatt Macy /* 139eda14cbcSMatt Macy * For each vdev in this pool, look for a match by devid 140eda14cbcSMatt Macy */ 141eda14cbcSMatt Macy if ((config = zpool_get_config(zhp, NULL)) != NULL) { 142eda14cbcSMatt Macy if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 143eda14cbcSMatt Macy &nvl) == 0) { 144eda14cbcSMatt Macy (void) zfs_agent_iter_vdev(zhp, nvl, gsp); 145eda14cbcSMatt Macy } 146eda14cbcSMatt Macy } 147eda14cbcSMatt Macy /* 148eda14cbcSMatt Macy * if a match was found then grab the pool guid 149eda14cbcSMatt Macy */ 150eda14cbcSMatt Macy if (gsp->gs_vdev_guid) { 151eda14cbcSMatt Macy (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 152eda14cbcSMatt Macy &gsp->gs_pool_guid); 153eda14cbcSMatt Macy } 154eda14cbcSMatt Macy 155eda14cbcSMatt Macy zpool_close(zhp); 156eda14cbcSMatt Macy return (gsp->gs_vdev_guid != 0); 157eda14cbcSMatt Macy } 158eda14cbcSMatt Macy 159eda14cbcSMatt Macy void 160eda14cbcSMatt Macy zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl) 161eda14cbcSMatt Macy { 162eda14cbcSMatt Macy agent_event_t *event; 163eda14cbcSMatt Macy 164eda14cbcSMatt Macy if (subclass == NULL) 165eda14cbcSMatt Macy subclass = ""; 166eda14cbcSMatt Macy 167eda14cbcSMatt Macy event = malloc(sizeof (agent_event_t)); 168eda14cbcSMatt Macy if (event == NULL || nvlist_dup(nvl, &event->ae_nvl, 0) != 0) { 169eda14cbcSMatt Macy if (event) 170eda14cbcSMatt Macy free(event); 171eda14cbcSMatt Macy return; 172eda14cbcSMatt Macy } 173eda14cbcSMatt Macy 174eda14cbcSMatt Macy if (strcmp(class, "sysevent.fs.zfs.vdev_check") == 0) { 175eda14cbcSMatt Macy class = EC_ZFS; 176eda14cbcSMatt Macy subclass = ESC_ZFS_VDEV_CHECK; 177eda14cbcSMatt Macy } 178eda14cbcSMatt Macy 179eda14cbcSMatt Macy /* 180*180f8225SMatt Macy * On Linux, we don't get the expected FM_RESOURCE_REMOVED ereport 181*180f8225SMatt Macy * from the vdev_disk layer after a hot unplug. Fortunately we do 182*180f8225SMatt Macy * get an EC_DEV_REMOVE from our disk monitor and it is a suitable 183eda14cbcSMatt Macy * proxy so we remap it here for the benefit of the diagnosis engine. 184eda14cbcSMatt Macy */ 185eda14cbcSMatt Macy if ((strcmp(class, EC_DEV_REMOVE) == 0) && 186eda14cbcSMatt Macy (strcmp(subclass, ESC_DISK) == 0) && 187eda14cbcSMatt Macy (nvlist_exists(nvl, ZFS_EV_VDEV_GUID) || 188eda14cbcSMatt Macy nvlist_exists(nvl, DEV_IDENTIFIER))) { 189eda14cbcSMatt Macy nvlist_t *payload = event->ae_nvl; 190eda14cbcSMatt Macy struct timeval tv; 191eda14cbcSMatt Macy int64_t tod[2]; 192eda14cbcSMatt Macy uint64_t pool_guid = 0, vdev_guid = 0; 193eda14cbcSMatt Macy guid_search_t search = { 0 }; 194eda14cbcSMatt Macy device_type_t devtype = DEVICE_TYPE_PRIMARY; 195eda14cbcSMatt Macy 196eda14cbcSMatt Macy class = "resource.fs.zfs.removed"; 197eda14cbcSMatt Macy subclass = ""; 198eda14cbcSMatt Macy 199eda14cbcSMatt Macy (void) nvlist_add_string(payload, FM_CLASS, class); 200eda14cbcSMatt Macy (void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid); 201eda14cbcSMatt Macy (void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid); 202eda14cbcSMatt Macy 203eda14cbcSMatt Macy (void) gettimeofday(&tv, NULL); 204eda14cbcSMatt Macy tod[0] = tv.tv_sec; 205eda14cbcSMatt Macy tod[1] = tv.tv_usec; 206eda14cbcSMatt Macy (void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2); 207eda14cbcSMatt Macy 208eda14cbcSMatt Macy /* 209eda14cbcSMatt Macy * For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or 210eda14cbcSMatt Macy * ZFS_EV_POOL_GUID may be missing so find them. 211eda14cbcSMatt Macy */ 212eda14cbcSMatt Macy (void) nvlist_lookup_string(nvl, DEV_IDENTIFIER, 213eda14cbcSMatt Macy &search.gs_devid); 214eda14cbcSMatt Macy (void) zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search); 215eda14cbcSMatt Macy pool_guid = search.gs_pool_guid; 216eda14cbcSMatt Macy vdev_guid = search.gs_vdev_guid; 217eda14cbcSMatt Macy devtype = search.gs_vdev_type; 218eda14cbcSMatt Macy 219eda14cbcSMatt Macy /* 220eda14cbcSMatt Macy * We want to avoid reporting "remove" events coming from 221eda14cbcSMatt Macy * libudev for VDEVs which were expanded recently (10s) and 222eda14cbcSMatt Macy * avoid activating spares in response to partitions being 223eda14cbcSMatt Macy * deleted and created in rapid succession. 224eda14cbcSMatt Macy */ 225eda14cbcSMatt Macy if (search.gs_vdev_expandtime != 0 && 226eda14cbcSMatt Macy search.gs_vdev_expandtime + 10 > tv.tv_sec) { 227eda14cbcSMatt Macy zed_log_msg(LOG_INFO, "agent post event: ignoring '%s' " 228eda14cbcSMatt Macy "for recently expanded device '%s'", EC_DEV_REMOVE, 229eda14cbcSMatt Macy search.gs_devid); 230eda14cbcSMatt Macy goto out; 231eda14cbcSMatt Macy } 232eda14cbcSMatt Macy 233eda14cbcSMatt Macy (void) nvlist_add_uint64(payload, 234eda14cbcSMatt Macy FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, pool_guid); 235eda14cbcSMatt Macy (void) nvlist_add_uint64(payload, 236eda14cbcSMatt Macy FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vdev_guid); 237eda14cbcSMatt Macy switch (devtype) { 238eda14cbcSMatt Macy case DEVICE_TYPE_L2ARC: 239eda14cbcSMatt Macy (void) nvlist_add_string(payload, 240eda14cbcSMatt Macy FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE, 241eda14cbcSMatt Macy VDEV_TYPE_L2CACHE); 242eda14cbcSMatt Macy break; 243eda14cbcSMatt Macy case DEVICE_TYPE_SPARE: 244eda14cbcSMatt Macy (void) nvlist_add_string(payload, 245eda14cbcSMatt Macy FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE, VDEV_TYPE_SPARE); 246eda14cbcSMatt Macy break; 247eda14cbcSMatt Macy case DEVICE_TYPE_PRIMARY: 248eda14cbcSMatt Macy (void) nvlist_add_string(payload, 249eda14cbcSMatt Macy FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE, VDEV_TYPE_DISK); 250eda14cbcSMatt Macy break; 251eda14cbcSMatt Macy } 252eda14cbcSMatt Macy 253eda14cbcSMatt Macy zed_log_msg(LOG_INFO, "agent post event: mapping '%s' to '%s'", 254eda14cbcSMatt Macy EC_DEV_REMOVE, class); 255eda14cbcSMatt Macy } 256eda14cbcSMatt Macy 257eda14cbcSMatt Macy (void) strlcpy(event->ae_class, class, sizeof (event->ae_class)); 258eda14cbcSMatt Macy (void) strlcpy(event->ae_subclass, subclass, 259eda14cbcSMatt Macy sizeof (event->ae_subclass)); 260eda14cbcSMatt Macy 261eda14cbcSMatt Macy (void) pthread_mutex_lock(&agent_lock); 262eda14cbcSMatt Macy list_insert_tail(&agent_events, event); 263eda14cbcSMatt Macy (void) pthread_mutex_unlock(&agent_lock); 264eda14cbcSMatt Macy 265eda14cbcSMatt Macy out: 266eda14cbcSMatt Macy (void) pthread_cond_signal(&agent_cond); 267eda14cbcSMatt Macy } 268eda14cbcSMatt Macy 269eda14cbcSMatt Macy static void 270eda14cbcSMatt Macy zfs_agent_dispatch(const char *class, const char *subclass, nvlist_t *nvl) 271eda14cbcSMatt Macy { 272eda14cbcSMatt Macy /* 273eda14cbcSMatt Macy * The diagnosis engine subscribes to the following events. 274eda14cbcSMatt Macy * On illumos these subscriptions reside in: 275eda14cbcSMatt Macy * /usr/lib/fm/fmd/plugins/zfs-diagnosis.conf 276eda14cbcSMatt Macy */ 277eda14cbcSMatt Macy if (strstr(class, "ereport.fs.zfs.") != NULL || 278eda14cbcSMatt Macy strstr(class, "resource.fs.zfs.") != NULL || 279eda14cbcSMatt Macy strcmp(class, "sysevent.fs.zfs.vdev_remove") == 0 || 280eda14cbcSMatt Macy strcmp(class, "sysevent.fs.zfs.vdev_remove_dev") == 0 || 281eda14cbcSMatt Macy strcmp(class, "sysevent.fs.zfs.pool_destroy") == 0) { 282eda14cbcSMatt Macy fmd_module_recv(fmd_module_hdl("zfs-diagnosis"), nvl, class); 283eda14cbcSMatt Macy } 284eda14cbcSMatt Macy 285eda14cbcSMatt Macy /* 286eda14cbcSMatt Macy * The retire agent subscribes to the following events. 287eda14cbcSMatt Macy * On illumos these subscriptions reside in: 288eda14cbcSMatt Macy * /usr/lib/fm/fmd/plugins/zfs-retire.conf 289eda14cbcSMatt Macy * 290eda14cbcSMatt Macy * NOTE: faults events come directly from our diagnosis engine 291eda14cbcSMatt Macy * and will not pass through the zfs kernel module. 292eda14cbcSMatt Macy */ 293eda14cbcSMatt Macy if (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0 || 294eda14cbcSMatt Macy strcmp(class, "resource.fs.zfs.removed") == 0 || 295eda14cbcSMatt Macy strcmp(class, "resource.fs.zfs.statechange") == 0 || 296eda14cbcSMatt Macy strcmp(class, "sysevent.fs.zfs.vdev_remove") == 0) { 297eda14cbcSMatt Macy fmd_module_recv(fmd_module_hdl("zfs-retire"), nvl, class); 298eda14cbcSMatt Macy } 299eda14cbcSMatt Macy 300eda14cbcSMatt Macy /* 301eda14cbcSMatt Macy * The SLM module only consumes disk events and vdev check events 302eda14cbcSMatt Macy * 303eda14cbcSMatt Macy * NOTE: disk events come directly from disk monitor and will 304eda14cbcSMatt Macy * not pass through the zfs kernel module. 305eda14cbcSMatt Macy */ 306eda14cbcSMatt Macy if (strstr(class, "EC_dev_") != NULL || 307eda14cbcSMatt Macy strcmp(class, EC_ZFS) == 0) { 308eda14cbcSMatt Macy (void) zfs_slm_event(class, subclass, nvl); 309eda14cbcSMatt Macy } 310eda14cbcSMatt Macy } 311eda14cbcSMatt Macy 312eda14cbcSMatt Macy /* 313eda14cbcSMatt Macy * Events are consumed and dispatched from this thread 314eda14cbcSMatt Macy * An agent can also post an event so event list lock 315eda14cbcSMatt Macy * is not held when calling an agent. 316eda14cbcSMatt Macy * One event is consumed at a time. 317eda14cbcSMatt Macy */ 318eda14cbcSMatt Macy static void * 319eda14cbcSMatt Macy zfs_agent_consumer_thread(void *arg) 320eda14cbcSMatt Macy { 321eda14cbcSMatt Macy for (;;) { 322eda14cbcSMatt Macy agent_event_t *event; 323eda14cbcSMatt Macy 324eda14cbcSMatt Macy (void) pthread_mutex_lock(&agent_lock); 325eda14cbcSMatt Macy 326eda14cbcSMatt Macy /* wait for an event to show up */ 327eda14cbcSMatt Macy while (!agent_exiting && list_is_empty(&agent_events)) 328eda14cbcSMatt Macy (void) pthread_cond_wait(&agent_cond, &agent_lock); 329eda14cbcSMatt Macy 330eda14cbcSMatt Macy if (agent_exiting) { 331eda14cbcSMatt Macy (void) pthread_mutex_unlock(&agent_lock); 332eda14cbcSMatt Macy zed_log_msg(LOG_INFO, "zfs_agent_consumer_thread: " 333eda14cbcSMatt Macy "exiting"); 334eda14cbcSMatt Macy return (NULL); 335eda14cbcSMatt Macy } 336eda14cbcSMatt Macy 337eda14cbcSMatt Macy if ((event = (list_head(&agent_events))) != NULL) { 338eda14cbcSMatt Macy list_remove(&agent_events, event); 339eda14cbcSMatt Macy 340eda14cbcSMatt Macy (void) pthread_mutex_unlock(&agent_lock); 341eda14cbcSMatt Macy 342eda14cbcSMatt Macy /* dispatch to all event subscribers */ 343eda14cbcSMatt Macy zfs_agent_dispatch(event->ae_class, event->ae_subclass, 344eda14cbcSMatt Macy event->ae_nvl); 345eda14cbcSMatt Macy 346eda14cbcSMatt Macy nvlist_free(event->ae_nvl); 347eda14cbcSMatt Macy free(event); 348eda14cbcSMatt Macy continue; 349eda14cbcSMatt Macy } 350eda14cbcSMatt Macy 351eda14cbcSMatt Macy (void) pthread_mutex_unlock(&agent_lock); 352eda14cbcSMatt Macy } 353eda14cbcSMatt Macy 354eda14cbcSMatt Macy return (NULL); 355eda14cbcSMatt Macy } 356eda14cbcSMatt Macy 357eda14cbcSMatt Macy void 358eda14cbcSMatt Macy zfs_agent_init(libzfs_handle_t *zfs_hdl) 359eda14cbcSMatt Macy { 360eda14cbcSMatt Macy fmd_hdl_t *hdl; 361eda14cbcSMatt Macy 362eda14cbcSMatt Macy g_zfs_hdl = zfs_hdl; 363eda14cbcSMatt Macy 364eda14cbcSMatt Macy if (zfs_slm_init() != 0) 365eda14cbcSMatt Macy zed_log_die("Failed to initialize zfs slm"); 366eda14cbcSMatt Macy zed_log_msg(LOG_INFO, "Add Agent: init"); 367eda14cbcSMatt Macy 368eda14cbcSMatt Macy hdl = fmd_module_hdl("zfs-diagnosis"); 369eda14cbcSMatt Macy _zfs_diagnosis_init(hdl); 370eda14cbcSMatt Macy if (!fmd_module_initialized(hdl)) 371eda14cbcSMatt Macy zed_log_die("Failed to initialize zfs diagnosis"); 372eda14cbcSMatt Macy 373eda14cbcSMatt Macy hdl = fmd_module_hdl("zfs-retire"); 374eda14cbcSMatt Macy _zfs_retire_init(hdl); 375eda14cbcSMatt Macy if (!fmd_module_initialized(hdl)) 376eda14cbcSMatt Macy zed_log_die("Failed to initialize zfs retire"); 377eda14cbcSMatt Macy 378eda14cbcSMatt Macy list_create(&agent_events, sizeof (agent_event_t), 379eda14cbcSMatt Macy offsetof(struct agent_event, ae_node)); 380eda14cbcSMatt Macy 381eda14cbcSMatt Macy if (pthread_create(&g_agents_tid, NULL, zfs_agent_consumer_thread, 382eda14cbcSMatt Macy NULL) != 0) { 383eda14cbcSMatt Macy list_destroy(&agent_events); 384eda14cbcSMatt Macy zed_log_die("Failed to initialize agents"); 385eda14cbcSMatt Macy } 386eda14cbcSMatt Macy } 387eda14cbcSMatt Macy 388eda14cbcSMatt Macy void 389eda14cbcSMatt Macy zfs_agent_fini(void) 390eda14cbcSMatt Macy { 391eda14cbcSMatt Macy fmd_hdl_t *hdl; 392eda14cbcSMatt Macy agent_event_t *event; 393eda14cbcSMatt Macy 394eda14cbcSMatt Macy agent_exiting = 1; 395eda14cbcSMatt Macy (void) pthread_cond_signal(&agent_cond); 396eda14cbcSMatt Macy 397eda14cbcSMatt Macy /* wait for zfs_enum_pools thread to complete */ 398eda14cbcSMatt Macy (void) pthread_join(g_agents_tid, NULL); 399eda14cbcSMatt Macy 400eda14cbcSMatt Macy /* drain any pending events */ 401eda14cbcSMatt Macy while ((event = (list_head(&agent_events))) != NULL) { 402eda14cbcSMatt Macy list_remove(&agent_events, event); 403eda14cbcSMatt Macy nvlist_free(event->ae_nvl); 404eda14cbcSMatt Macy free(event); 405eda14cbcSMatt Macy } 406eda14cbcSMatt Macy 407eda14cbcSMatt Macy list_destroy(&agent_events); 408eda14cbcSMatt Macy 409eda14cbcSMatt Macy if ((hdl = fmd_module_hdl("zfs-retire")) != NULL) { 410eda14cbcSMatt Macy _zfs_retire_fini(hdl); 411eda14cbcSMatt Macy fmd_hdl_unregister(hdl); 412eda14cbcSMatt Macy } 413eda14cbcSMatt Macy if ((hdl = fmd_module_hdl("zfs-diagnosis")) != NULL) { 414eda14cbcSMatt Macy _zfs_diagnosis_fini(hdl); 415eda14cbcSMatt Macy fmd_hdl_unregister(hdl); 416eda14cbcSMatt Macy } 417eda14cbcSMatt Macy 418eda14cbcSMatt Macy zed_log_msg(LOG_INFO, "Add Agent: fini"); 419eda14cbcSMatt Macy zfs_slm_fini(); 420eda14cbcSMatt Macy 421eda14cbcSMatt Macy g_zfs_hdl = NULL; 422eda14cbcSMatt Macy } 423