17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 524db4641Seschrock * Common Development and Distribution License (the "License"). 624db4641Seschrock * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 210b9e3e76Smws 227c478bd9Sstevel@tonic-gate /* 232a417b23SRobert Johnston * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <signal.h> 277c478bd9Sstevel@tonic-gate #include <dirent.h> 287c478bd9Sstevel@tonic-gate #include <limits.h> 297c478bd9Sstevel@tonic-gate #include <alloca.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <stdio.h> 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <fmd_string.h> 347c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 357c478bd9Sstevel@tonic-gate #include <fmd_module.h> 367c478bd9Sstevel@tonic-gate #include <fmd_error.h> 377c478bd9Sstevel@tonic-gate #include <fmd_conf.h> 387c478bd9Sstevel@tonic-gate #include <fmd_dispq.h> 397c478bd9Sstevel@tonic-gate #include <fmd_eventq.h> 407c478bd9Sstevel@tonic-gate #include <fmd_timerq.h> 417c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 427c478bd9Sstevel@tonic-gate #include <fmd_thread.h> 437c478bd9Sstevel@tonic-gate #include <fmd_ustat.h> 447c478bd9Sstevel@tonic-gate #include <fmd_case.h> 457c478bd9Sstevel@tonic-gate #include <fmd_protocol.h> 467c478bd9Sstevel@tonic-gate #include <fmd_buf.h> 477c478bd9Sstevel@tonic-gate #include <fmd_ckpt.h> 48d9638e54Smws #include <fmd_xprt.h> 4924db4641Seschrock #include <fmd_topo.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #include <fmd.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * Template for per-module statistics installed by fmd on behalf of each active 557c478bd9Sstevel@tonic-gate * module. These are used to initialize the per-module mp->mod_stats below. 567c478bd9Sstevel@tonic-gate * NOTE: FMD_TYPE_STRING statistics should not be used here. If they are 577c478bd9Sstevel@tonic-gate * required in the future, the FMD_ADM_MODDSTAT service routine must change. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate static const fmd_modstat_t _fmd_modstat_tmpl = { 60d9638e54Smws { 617c478bd9Sstevel@tonic-gate { "fmd.dispatched", FMD_TYPE_UINT64, "total events dispatched to module" }, 627c478bd9Sstevel@tonic-gate { "fmd.dequeued", FMD_TYPE_UINT64, "total events dequeued by module" }, 637c478bd9Sstevel@tonic-gate { "fmd.prdequeued", FMD_TYPE_UINT64, "protocol events dequeued by module" }, 647c478bd9Sstevel@tonic-gate { "fmd.dropped", FMD_TYPE_UINT64, "total events dropped on queue overflow" }, 657c478bd9Sstevel@tonic-gate { "fmd.wcnt", FMD_TYPE_UINT32, "count of events waiting on queue" }, 667c478bd9Sstevel@tonic-gate { "fmd.wtime", FMD_TYPE_TIME, "total wait time on queue" }, 677c478bd9Sstevel@tonic-gate { "fmd.wlentime", FMD_TYPE_TIME, "total wait length * time product" }, 687c478bd9Sstevel@tonic-gate { "fmd.wlastupdate", FMD_TYPE_TIME, "hrtime of last wait queue update" }, 697c478bd9Sstevel@tonic-gate { "fmd.dtime", FMD_TYPE_TIME, "total processing time after dequeue" }, 707c478bd9Sstevel@tonic-gate { "fmd.dlastupdate", FMD_TYPE_TIME, "hrtime of last event dequeue completion" }, 71d9638e54Smws }, 72d9638e54Smws { "fmd.loadtime", FMD_TYPE_TIME, "hrtime at which module was loaded" }, 73d9638e54Smws { "fmd.snaptime", FMD_TYPE_TIME, "hrtime of last statistics snapshot" }, 74d9638e54Smws { "fmd.accepted", FMD_TYPE_UINT64, "total events accepted by module" }, 757c478bd9Sstevel@tonic-gate { "fmd.debugdrop", FMD_TYPE_UINT64, "dropped debug messages" }, 767c478bd9Sstevel@tonic-gate { "fmd.memtotal", FMD_TYPE_SIZE, "total memory allocated by module" }, 777c478bd9Sstevel@tonic-gate { "fmd.memlimit", FMD_TYPE_SIZE, "limit on total memory allocated" }, 787c478bd9Sstevel@tonic-gate { "fmd.buftotal", FMD_TYPE_SIZE, "total buffer space used by module" }, 797c478bd9Sstevel@tonic-gate { "fmd.buflimit", FMD_TYPE_SIZE, "limit on total buffer space" }, 807c478bd9Sstevel@tonic-gate { "fmd.thrtotal", FMD_TYPE_UINT32, "total number of auxiliary threads" }, 817c478bd9Sstevel@tonic-gate { "fmd.thrlimit", FMD_TYPE_UINT32, "limit on number of auxiliary threads" }, 82f6e214c7SGavin Maltby { "fmd.doorthrtotal", FMD_TYPE_UINT32, "total number of door server threads" }, 83f6e214c7SGavin Maltby { "fmd.doorthrlimit", FMD_TYPE_UINT32, "limit on door server threads" }, 847c478bd9Sstevel@tonic-gate { "fmd.caseopen", FMD_TYPE_UINT64, "cases currently open by module" }, 857c478bd9Sstevel@tonic-gate { "fmd.casesolved", FMD_TYPE_UINT64, "total cases solved by module" }, 867c478bd9Sstevel@tonic-gate { "fmd.caseclosed", FMD_TYPE_UINT64, "total cases closed by module" }, 877c478bd9Sstevel@tonic-gate { "fmd.ckptsave", FMD_TYPE_BOOL, "save checkpoints for module" }, 887c478bd9Sstevel@tonic-gate { "fmd.ckptrestore", FMD_TYPE_BOOL, "restore checkpoints for module" }, 897c478bd9Sstevel@tonic-gate { "fmd.ckptzero", FMD_TYPE_BOOL, "zeroed checkpoint at startup" }, 907c478bd9Sstevel@tonic-gate { "fmd.ckptcnt", FMD_TYPE_UINT64, "number of checkpoints taken" }, 917c478bd9Sstevel@tonic-gate { "fmd.ckpttime", FMD_TYPE_TIME, "total checkpoint time" }, 92d9638e54Smws { "fmd.xprtopen", FMD_TYPE_UINT32, "total number of open transports" }, 93d9638e54Smws { "fmd.xprtlimit", FMD_TYPE_UINT32, "limit on number of open transports" }, 94d9638e54Smws { "fmd.xprtqlimit", FMD_TYPE_UINT32, "limit on transport event queue length" }, 957c478bd9Sstevel@tonic-gate }; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static void 987c478bd9Sstevel@tonic-gate fmd_module_start(void *arg) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate fmd_module_t *mp = arg; 1017c478bd9Sstevel@tonic-gate fmd_event_t *ep; 102d9638e54Smws fmd_xprt_t *xp; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate if (mp->mod_ops->mop_init(mp) != 0 || mp->mod_error != 0) { 1077c478bd9Sstevel@tonic-gate if (mp->mod_error == 0) 1087c478bd9Sstevel@tonic-gate mp->mod_error = errno ? errno : EFMD_MOD_INIT; 1097c478bd9Sstevel@tonic-gate goto out; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 112d9638e54Smws if (fmd.d_mod_event != NULL) 113d9638e54Smws fmd_eventq_insert_at_head(mp->mod_queue, fmd.d_mod_event); 114d9638e54Smws 1157c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mp->mod_lock)); 1167c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_INIT; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 119d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 120d9638e54Smws 121d9638e54Smws /* 122d9638e54Smws * If the module opened any transports while executing _fmd_init(), 123d9638e54Smws * they are suspended. Now that _fmd_init() is done, wake them up. 124d9638e54Smws */ 125d9638e54Smws for (xp = fmd_list_next(&mp->mod_transports); 126d9638e54Smws xp != NULL; xp = fmd_list_next(xp)) 127d9638e54Smws fmd_xprt_xresume(xp, FMD_XPRT_ISUSPENDED); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * Wait for events to arrive by checking mod_error and then sleeping in 1317c478bd9Sstevel@tonic-gate * fmd_eventq_delete(). If a NULL event is returned, the eventq has 1327c478bd9Sstevel@tonic-gate * been aborted and we continue on to call fini and exit the thread. 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate while ((ep = fmd_eventq_delete(mp->mod_queue)) != NULL) { 1357c478bd9Sstevel@tonic-gate /* 136d9638e54Smws * If the module has failed, discard the event without ever 137d9638e54Smws * passing it to the module and go back to sleep. 1387c478bd9Sstevel@tonic-gate */ 139d9638e54Smws if (mp->mod_error != 0) { 140d9638e54Smws fmd_eventq_done(mp->mod_queue); 1417c478bd9Sstevel@tonic-gate fmd_event_rele(ep); 1427c478bd9Sstevel@tonic-gate continue; 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate mp->mod_ops->mop_dispatch(mp, ep); 146d9638e54Smws fmd_eventq_done(mp->mod_queue); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Once mop_dispatch() is complete, grab the lock and perform 1507c478bd9Sstevel@tonic-gate * any event-specific post-processing. Finally, if necessary, 1517c478bd9Sstevel@tonic-gate * checkpoint the state of the module after this event. 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 1547c478bd9Sstevel@tonic-gate 155d9638e54Smws if (FMD_EVENT_TYPE(ep) == FMD_EVT_CLOSE) 156d9638e54Smws fmd_case_delete(FMD_EVENT_DATA(ep)); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate fmd_ckpt_save(mp); 1597c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 1607c478bd9Sstevel@tonic-gate fmd_event_rele(ep); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if (mp->mod_ops->mop_fini(mp) != 0 && mp->mod_error == 0) 1647c478bd9Sstevel@tonic-gate mp->mod_error = errno ? errno : EFMD_MOD_FINI; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 1677c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_FINI; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate out: 1707c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 171d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate fmd_module_t * 1757c478bd9Sstevel@tonic-gate fmd_module_create(const char *path, const fmd_modops_t *ops) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate fmd_module_t *mp = fmd_zalloc(sizeof (fmd_module_t), FMD_SLEEP); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate char buf[PATH_MAX], *p; 1807c478bd9Sstevel@tonic-gate const char *dir; 1817c478bd9Sstevel@tonic-gate uint32_t limit; 1827c478bd9Sstevel@tonic-gate int err; 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate (void) strlcpy(buf, fmd_strbasename(path), sizeof (buf)); 1857c478bd9Sstevel@tonic-gate if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".so") == 0) 1867c478bd9Sstevel@tonic-gate *p = '\0'; /* strip trailing .so from any module name */ 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&mp->mod_lock, NULL); 1897c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&mp->mod_cv, NULL); 1907c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&mp->mod_stats_lock, NULL); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate mp->mod_name = fmd_strdup(buf, FMD_SLEEP); 1937c478bd9Sstevel@tonic-gate mp->mod_path = fmd_strdup(path, FMD_SLEEP); 1947c478bd9Sstevel@tonic-gate mp->mod_ops = ops; 1957c478bd9Sstevel@tonic-gate mp->mod_ustat = fmd_ustat_create(); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.dir", &dir); 1987c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 1997c478bd9Sstevel@tonic-gate "%s/%s/%s", fmd.d_rootdir, dir, mp->mod_name); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate mp->mod_ckpt = fmd_strdup(buf, FMD_SLEEP); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "client.tmrlim", &limit); 2047c478bd9Sstevel@tonic-gate mp->mod_timerids = fmd_idspace_create(mp->mod_name, 1, limit + 1); 2057c478bd9Sstevel@tonic-gate mp->mod_threads = fmd_idspace_create(mp->mod_name, 0, INT_MAX); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate fmd_buf_hash_create(&mp->mod_bufs); 2087c478bd9Sstevel@tonic-gate fmd_serd_hash_create(&mp->mod_serds); 2097c478bd9Sstevel@tonic-gate 21024db4641Seschrock mp->mod_topo_current = fmd_topo_hold(); 21124db4641Seschrock 2127c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_mod_lock); 2137c478bd9Sstevel@tonic-gate fmd_list_append(&fmd.d_mod_list, mp); 2147c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_mod_lock); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Initialize the module statistics that are kept on its behalf by fmd. 2187c478bd9Sstevel@tonic-gate * These are set up using a template defined at the top of this file. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate if ((mp->mod_stats = (fmd_modstat_t *)fmd_ustat_insert(mp->mod_ustat, 2217c478bd9Sstevel@tonic-gate FMD_USTAT_ALLOC, sizeof (_fmd_modstat_tmpl) / sizeof (fmd_stat_t), 2227c478bd9Sstevel@tonic-gate (fmd_stat_t *)&_fmd_modstat_tmpl, NULL)) == NULL) { 2237c478bd9Sstevel@tonic-gate fmd_error(EFMD_MOD_INIT, "failed to initialize per-mod stats"); 2247c478bd9Sstevel@tonic-gate fmd_module_destroy(mp); 2257c478bd9Sstevel@tonic-gate return (NULL); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2289af3851aSeschrock if (nv_alloc_init(&mp->mod_nva_sleep, 2299af3851aSeschrock &fmd_module_nva_ops_sleep, mp) != 0 || 2309af3851aSeschrock nv_alloc_init(&mp->mod_nva_nosleep, 2319af3851aSeschrock &fmd_module_nva_ops_nosleep, mp) != 0) { 2329af3851aSeschrock fmd_error(EFMD_MOD_INIT, "failed to initialize nvlist " 2339af3851aSeschrock "allocation routines"); 2349af3851aSeschrock fmd_module_destroy(mp); 2359af3851aSeschrock return (NULL); 2369af3851aSeschrock } 2379af3851aSeschrock 238d9638e54Smws (void) fmd_conf_getprop(fmd.d_conf, "client.evqlim", &limit); 239d9638e54Smws 240d9638e54Smws mp->mod_queue = fmd_eventq_create(mp, 241d9638e54Smws &mp->mod_stats->ms_evqstat, &mp->mod_stats_lock, limit); 242d9638e54Smws 2437c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "client.memlim", 2447c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_memlimit.fmds_value.ui64); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "client.buflim", 2477c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_buflimit.fmds_value.ui64); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "client.thrlim", 2507c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_thrlimit.fmds_value.ui32); 2517c478bd9Sstevel@tonic-gate 252f6e214c7SGavin Maltby (void) fmd_conf_getprop(fmd.d_conf, "client.doorthrlim", 253f6e214c7SGavin Maltby &mp->mod_stats->ms_doorthrlimit.fmds_value.ui32); 254f6e214c7SGavin Maltby 255d9638e54Smws (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlim", 256d9638e54Smws &mp->mod_stats->ms_xprtlimit.fmds_value.ui32); 257d9638e54Smws 258d9638e54Smws (void) fmd_conf_getprop(fmd.d_conf, "client.xprtqlim", 259d9638e54Smws &mp->mod_stats->ms_xprtqlimit.fmds_value.ui32); 260d9638e54Smws 2617c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.save", 2627c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_ckpt_save.fmds_value.bool); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.restore", 2657c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_ckpt_restore.fmds_value.bool); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.zero", 2687c478bd9Sstevel@tonic-gate &mp->mod_stats->ms_ckpt_zeroed.fmds_value.bool); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_ckpt_zeroed.fmds_value.bool) 2717c478bd9Sstevel@tonic-gate fmd_ckpt_delete(mp); /* blow away any pre-existing checkpoint */ 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Place a hold on the module and grab the module lock before creating 2757c478bd9Sstevel@tonic-gate * the module's thread to ensure that it cannot destroy the module and 2767c478bd9Sstevel@tonic-gate * that it cannot call ops->mop_init() before we're done setting up. 2777c478bd9Sstevel@tonic-gate * NOTE: from now on, we must use fmd_module_rele() for error paths. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate fmd_module_hold(mp); 2807c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 2817c478bd9Sstevel@tonic-gate mp->mod_stats->ms_loadtime.fmds_value.ui64 = gethrtime(); 2827c478bd9Sstevel@tonic-gate mp->mod_thread = fmd_thread_create(mp, fmd_module_start, mp); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if (mp->mod_thread == NULL) { 2857c478bd9Sstevel@tonic-gate fmd_error(EFMD_MOD_THR, "failed to create thread for %s", path); 2867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 2877c478bd9Sstevel@tonic-gate fmd_module_rele(mp); 2887c478bd9Sstevel@tonic-gate return (NULL); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * At this point our module structure is nearly finished and its thread 2937c478bd9Sstevel@tonic-gate * is starting execution in fmd_module_start() above, which will begin 2947c478bd9Sstevel@tonic-gate * by blocking for mod_lock. We now drop mod_lock and wait for either 2957c478bd9Sstevel@tonic-gate * FMD_MOD_INIT or mod_error to be set before proceeding. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate while (!(mp->mod_flags & FMD_MOD_INIT) && mp->mod_error == 0) 2987c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * If the module has failed to initialize, copy its errno to the errno 3027c478bd9Sstevel@tonic-gate * of the caller, wait for it to unload, and then destroy it. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate if (!(mp->mod_flags & FMD_MOD_INIT)) { 3057c478bd9Sstevel@tonic-gate err = mp->mod_error; 3067c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if (err == EFMD_CKPT_INVAL) 3097c478bd9Sstevel@tonic-gate fmd_ckpt_rename(mp); /* move aside bad checkpoint */ 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate /* 3127c478bd9Sstevel@tonic-gate * If we're in the background, keep quiet about failure to 3137c478bd9Sstevel@tonic-gate * load because a handle wasn't registered: this is a module's 3147c478bd9Sstevel@tonic-gate * way of telling us it didn't want to be loaded for some 3157c478bd9Sstevel@tonic-gate * reason related to system configuration. If we're in the 3167c478bd9Sstevel@tonic-gate * foreground we log this too in order to inform developers. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate if (fmd.d_fg || err != EFMD_HDL_INIT) { 3197c478bd9Sstevel@tonic-gate fmd_error(EFMD_MOD_INIT, "failed to load %s: %s\n", 3207c478bd9Sstevel@tonic-gate path, fmd_strerror(err)); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate fmd_module_unload(mp); 3247c478bd9Sstevel@tonic-gate fmd_module_rele(mp); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate (void) fmd_set_errno(err); 3277c478bd9Sstevel@tonic-gate return (NULL); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 331d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_MOD, "loaded module %s\n", mp->mod_name); 3347c478bd9Sstevel@tonic-gate return (mp); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate static void 338d9638e54Smws fmd_module_untimeout(fmd_idspace_t *ids, id_t id, fmd_module_t *mp) 3397c478bd9Sstevel@tonic-gate { 340d9638e54Smws void *arg = fmd_timerq_remove(fmd.d_timers, ids, id); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * The root module calls fmd_timerq_install() directly and must take 3447c478bd9Sstevel@tonic-gate * responsibility for any cleanup of timer arguments that is required. 3457c478bd9Sstevel@tonic-gate * All other modules use fmd_modtimer_t's as the arg data; free them. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate if (arg != NULL && mp != fmd.d_rmod) 3487c478bd9Sstevel@tonic-gate fmd_free(arg, sizeof (fmd_modtimer_t)); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate void 3527c478bd9Sstevel@tonic-gate fmd_module_unload(fmd_module_t *mp) 3537c478bd9Sstevel@tonic-gate { 35424db4641Seschrock fmd_modtopo_t *mtp; 35524db4641Seschrock 3567c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_QUIT) { 3597c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 3607c478bd9Sstevel@tonic-gate return; /* module is already unloading */ 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate ASSERT(mp->mod_thread != NULL); 3647c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_QUIT; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (mp->mod_queue != NULL) 3677c478bd9Sstevel@tonic-gate fmd_eventq_abort(mp->mod_queue); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * Wait for the module's thread to stop processing events and call 3717c478bd9Sstevel@tonic-gate * _fmd_fini() and exit. We do this by waiting for FMD_MOD_FINI to be 3727c478bd9Sstevel@tonic-gate * set if INIT was set, and then attempting to join with the thread. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate while ((mp->mod_flags & (FMD_MOD_INIT | FMD_MOD_FINI)) == FMD_MOD_INIT) 3757c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 378d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate fmd_thread_destroy(mp->mod_thread, FMD_THREAD_JOIN); 3817c478bd9Sstevel@tonic-gate mp->mod_thread = NULL; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Once the module is no longer active, clean up any data structures 385d9638e54Smws * that are only required when the module is loaded. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (mp->mod_timerids != NULL) { 3907c478bd9Sstevel@tonic-gate fmd_idspace_apply(mp->mod_timerids, 3917c478bd9Sstevel@tonic-gate (void (*)())fmd_module_untimeout, mp); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate fmd_idspace_destroy(mp->mod_timerids); 3947c478bd9Sstevel@tonic-gate mp->mod_timerids = NULL; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate if (mp->mod_threads != NULL) { 3987c478bd9Sstevel@tonic-gate fmd_idspace_destroy(mp->mod_threads); 3997c478bd9Sstevel@tonic-gate mp->mod_threads = NULL; 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4020b9e3e76Smws (void) fmd_buf_hash_destroy(&mp->mod_bufs); 4037c478bd9Sstevel@tonic-gate fmd_serd_hash_destroy(&mp->mod_serds); 4047c478bd9Sstevel@tonic-gate 40524db4641Seschrock while ((mtp = fmd_list_next(&mp->mod_topolist)) != NULL) { 40624db4641Seschrock fmd_list_delete(&mp->mod_topolist, mtp); 40724db4641Seschrock fmd_topo_rele(mtp->mt_topo); 40824db4641Seschrock fmd_free(mtp, sizeof (fmd_modtopo_t)); 40924db4641Seschrock } 41024db4641Seschrock 4117c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 4127c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_MOD, "unloaded module %s\n", mp->mod_name); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate void 4167c478bd9Sstevel@tonic-gate fmd_module_destroy(fmd_module_t *mp) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate fmd_conf_formal_t *cfp = mp->mod_argv; 4197c478bd9Sstevel@tonic-gate int i; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mp->mod_lock)); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (mp->mod_thread != NULL) { 4247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 4257c478bd9Sstevel@tonic-gate fmd_module_unload(mp); 4267c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate ASSERT(mp->mod_thread == NULL); 4307c478bd9Sstevel@tonic-gate ASSERT(mp->mod_refs == 0); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Once the module's thread is dead, we can safely remove the module 4347c478bd9Sstevel@tonic-gate * from global visibility and by removing it from d_mod_list. Any 4357c478bd9Sstevel@tonic-gate * modhash pointers are already gone by virtue of mod_refs being zero. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_mod_lock); 4387c478bd9Sstevel@tonic-gate fmd_list_delete(&fmd.d_mod_list, mp); 4397c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_mod_lock); 4407c478bd9Sstevel@tonic-gate 44124db4641Seschrock if (mp->mod_topo_current != NULL) 44224db4641Seschrock fmd_topo_rele(mp->mod_topo_current); 44324db4641Seschrock 4449af3851aSeschrock if (mp->mod_nva_sleep.nva_ops != NULL) 4459af3851aSeschrock nv_alloc_fini(&mp->mod_nva_sleep); 4469af3851aSeschrock if (mp->mod_nva_nosleep.nva_ops != NULL) 4479af3851aSeschrock nv_alloc_fini(&mp->mod_nva_nosleep); 4489af3851aSeschrock 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * Once the module is no longer processing events and no longer visible 4517c478bd9Sstevel@tonic-gate * through any program data structures, we can free all of its content. 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate if (mp->mod_queue != NULL) { 4547c478bd9Sstevel@tonic-gate fmd_eventq_destroy(mp->mod_queue); 4557c478bd9Sstevel@tonic-gate mp->mod_queue = NULL; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 458d9638e54Smws if (mp->mod_ustat != NULL) { 459d9638e54Smws (void) pthread_mutex_lock(&mp->mod_stats_lock); 460d9638e54Smws fmd_ustat_destroy(mp->mod_ustat); 461d9638e54Smws mp->mod_ustat = NULL; 462d9638e54Smws mp->mod_stats = NULL; 463d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_stats_lock); 464d9638e54Smws } 465d9638e54Smws 4667c478bd9Sstevel@tonic-gate for (i = 0; i < mp->mod_dictc; i++) 4677c478bd9Sstevel@tonic-gate fm_dc_closedict(mp->mod_dictv[i]); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate fmd_free(mp->mod_dictv, sizeof (struct fm_dc_handle *) * mp->mod_dictc); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if (mp->mod_conf != NULL) 4727c478bd9Sstevel@tonic-gate fmd_conf_close(mp->mod_conf); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate for (i = 0; i < mp->mod_argc; i++, cfp++) { 4757c478bd9Sstevel@tonic-gate fmd_strfree((char *)cfp->cf_name); 4767c478bd9Sstevel@tonic-gate fmd_strfree((char *)cfp->cf_default); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate fmd_strfree(mp->mod_name); 4827c478bd9Sstevel@tonic-gate fmd_strfree(mp->mod_path); 4837c478bd9Sstevel@tonic-gate fmd_strfree(mp->mod_ckpt); 4847c478bd9Sstevel@tonic-gate nvlist_free(mp->mod_fmri); 48519e1255fScy152378 fmd_strfree(mp->mod_vers); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate fmd_free(mp, sizeof (fmd_module_t)); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * fmd_module_error() is called after the stack is unwound from a call to 4927c478bd9Sstevel@tonic-gate * fmd_module_abort() to indicate that the module has failed. The mod_error 4937c478bd9Sstevel@tonic-gate * field is used to hold the error code of the first fatal error to the module. 4947c478bd9Sstevel@tonic-gate * An EFMD_MOD_FAIL event is then created and sent to fmd-self-diagnosis. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate static void 4977c478bd9Sstevel@tonic-gate fmd_module_error(fmd_module_t *mp, int err) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate fmd_event_t *e; 5007c478bd9Sstevel@tonic-gate nvlist_t *nvl; 5017c478bd9Sstevel@tonic-gate char *class; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mp->mod_lock)); 5047c478bd9Sstevel@tonic-gate ASSERT(err != 0); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_MOD, "module aborted: err=%d", err)); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if (mp->mod_error == 0) 5097c478bd9Sstevel@tonic-gate mp->mod_error = err; 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate if (mp == fmd.d_self) 5127c478bd9Sstevel@tonic-gate return; /* do not post event if fmd.d_self itself fails */ 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Send an error indicating the module has now failed to fmd.d_self. 5167c478bd9Sstevel@tonic-gate * Since the error causing the failure has already been logged by 5177c478bd9Sstevel@tonic-gate * fmd_api_xerror(), we do not need to bother logging this event. 5187c478bd9Sstevel@tonic-gate * It only exists for the purpose of notifying fmd.d_self that it can 5197c478bd9Sstevel@tonic-gate * close the case associated with this module because mod_error is set. 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate nvl = fmd_protocol_moderror(mp, EFMD_MOD_FAIL, fmd_strerror(err)); 5227c478bd9Sstevel@tonic-gate (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 5237c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 5247c478bd9Sstevel@tonic-gate fmd_dispq_dispatch(fmd.d_disp, e, class); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate void 5287c478bd9Sstevel@tonic-gate fmd_module_dispatch(fmd_module_t *mp, fmd_event_t *e) 5297c478bd9Sstevel@tonic-gate { 5307c478bd9Sstevel@tonic-gate const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops; 5317c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 5327c478bd9Sstevel@tonic-gate fmd_hdl_t *hdl = (fmd_hdl_t *)mp; 5337c478bd9Sstevel@tonic-gate fmd_modtimer_t *t; 534d10eddf7SHyon Kim fmd_topo_t *old_topo; 5357c478bd9Sstevel@tonic-gate volatile int err; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * Before calling the appropriate module callback, enter the module as 5397c478bd9Sstevel@tonic-gate * if by fmd_module_enter() and establish mod_jmpbuf for any aborts. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate ASSERT(!(mp->mod_flags & FMD_MOD_BUSY)); 5447c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_BUSY; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if ((err = setjmp(mp->mod_jmpbuf)) != 0) { 5477c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 5487c478bd9Sstevel@tonic-gate fmd_module_error(mp, err); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 552d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * If it's the first time through fmd_module_dispatch(), call the 5567c478bd9Sstevel@tonic-gate * appropriate module callback based on the event type. If the call 5577c478bd9Sstevel@tonic-gate * triggers an fmd_module_abort(), we'll return to setjmp() above with 5587c478bd9Sstevel@tonic-gate * err set to a non-zero value and then bypass this before exiting. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate if (err == 0) { 5617c478bd9Sstevel@tonic-gate switch (ep->ev_type) { 5627c478bd9Sstevel@tonic-gate case FMD_EVT_PROTOCOL: 5637c478bd9Sstevel@tonic-gate ops->fmdo_recv(hdl, e, ep->ev_nvl, ep->ev_data); 5647c478bd9Sstevel@tonic-gate break; 5657c478bd9Sstevel@tonic-gate case FMD_EVT_TIMEOUT: 5667c478bd9Sstevel@tonic-gate t = ep->ev_data; 5677c478bd9Sstevel@tonic-gate ASSERT(t->mt_mod == mp); 5687c478bd9Sstevel@tonic-gate ops->fmdo_timeout(hdl, t->mt_id, t->mt_arg); 5697c478bd9Sstevel@tonic-gate break; 5707c478bd9Sstevel@tonic-gate case FMD_EVT_CLOSE: 5717c478bd9Sstevel@tonic-gate ops->fmdo_close(hdl, ep->ev_data); 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate case FMD_EVT_STATS: 5747c478bd9Sstevel@tonic-gate ops->fmdo_stats(hdl); 5757c478bd9Sstevel@tonic-gate fmd_modstat_publish(mp); 5767c478bd9Sstevel@tonic-gate break; 5777c478bd9Sstevel@tonic-gate case FMD_EVT_GC: 5787c478bd9Sstevel@tonic-gate ops->fmdo_gc(hdl); 5797c478bd9Sstevel@tonic-gate break; 580d9638e54Smws case FMD_EVT_PUBLISH: 581d9638e54Smws fmd_case_publish(ep->ev_data, FMD_CASE_CURRENT); 582d9638e54Smws break; 58324db4641Seschrock case FMD_EVT_TOPO: 584d10eddf7SHyon Kim /* 585d10eddf7SHyon Kim * Save the pointer to the old topology and update 586d10eddf7SHyon Kim * the pointer with the updated topology. 587d10eddf7SHyon Kim * With this approach, other threads that reference the 588d10eddf7SHyon Kim * topology either 589d10eddf7SHyon Kim * - finishes with old topology since 590d10eddf7SHyon Kim * it is released after updating 591d10eddf7SHyon Kim * mod_topo_current. 592d10eddf7SHyon Kim * - or is blocked while mod_topo_current is updated. 593d10eddf7SHyon Kim */ 594d10eddf7SHyon Kim old_topo = mp->mod_topo_current; 595d10eddf7SHyon Kim fmd_module_lock(mp); 59624db4641Seschrock mp->mod_topo_current = (fmd_topo_t *)ep->ev_data; 59724db4641Seschrock fmd_topo_addref(mp->mod_topo_current); 598d10eddf7SHyon Kim fmd_module_unlock(mp); 599d10eddf7SHyon Kim fmd_topo_rele(old_topo); 60024db4641Seschrock ops->fmdo_topo(hdl, mp->mod_topo_current->ft_hdl); 60124db4641Seschrock break; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate fmd_module_exit(mp); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 608d9638e54Smws int 609d9638e54Smws fmd_module_transport(fmd_module_t *mp, fmd_xprt_t *xp, fmd_event_t *e) 610d9638e54Smws { 611d9638e54Smws fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 612d9638e54Smws fmd_hdl_t *hdl = (fmd_hdl_t *)mp; 613d9638e54Smws 614d9638e54Smws ASSERT(ep->ev_type == FMD_EVT_PROTOCOL); 615d9638e54Smws return (mp->mod_info->fmdi_ops->fmdo_send(hdl, xp, e, ep->ev_nvl)); 616d9638e54Smws } 617d9638e54Smws 6187c478bd9Sstevel@tonic-gate void 6197c478bd9Sstevel@tonic-gate fmd_module_timeout(fmd_modtimer_t *t, id_t id, hrtime_t hrt) 6207c478bd9Sstevel@tonic-gate { 6217c478bd9Sstevel@tonic-gate fmd_event_t *e; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate t->mt_id = id; /* save id in case we need to delete from eventq */ 6247c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_TIMEOUT, hrt, NULL, t); 6257c478bd9Sstevel@tonic-gate fmd_eventq_insert_at_time(t->mt_mod->mod_queue, e); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * Garbage collection is initiated by a timer callback once per day or at the 6307c478bd9Sstevel@tonic-gate * request of fmadm. Purge old SERD entries and send the module a GC event. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate void 6337c478bd9Sstevel@tonic-gate fmd_module_gc(fmd_module_t *mp) 6347c478bd9Sstevel@tonic-gate { 6357c478bd9Sstevel@tonic-gate fmd_hdl_info_t *info; 6367c478bd9Sstevel@tonic-gate fmd_event_t *e; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate if (mp->mod_error != 0) 6397c478bd9Sstevel@tonic-gate return; /* do not do anything if the module has failed */ 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate if ((info = mp->mod_info) != NULL) { 6447c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 6457c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_serd_eng_gc, NULL); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (info != NULL) { 6517c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_GC, FMD_HRT_NOW, NULL, NULL); 6527c478bd9Sstevel@tonic-gate fmd_eventq_insert_at_head(mp->mod_queue, e); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate void 6577c478bd9Sstevel@tonic-gate fmd_module_trygc(fmd_module_t *mp) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate if (fmd_module_trylock(mp)) { 6607c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 6617c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_serd_eng_gc, NULL); 6627c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate int 6677c478bd9Sstevel@tonic-gate fmd_module_contains(fmd_module_t *mp, fmd_event_t *ep) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate fmd_case_t *cp; 6707c478bd9Sstevel@tonic-gate int rv = 0; 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); 6757c478bd9Sstevel@tonic-gate cp != NULL; cp = fmd_list_next(cp)) { 6767c478bd9Sstevel@tonic-gate if ((rv = fmd_case_contains(cp, ep)) != 0) 6777c478bd9Sstevel@tonic-gate break; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if (rv == 0) 6817c478bd9Sstevel@tonic-gate rv = fmd_serd_hash_contains(&mp->mod_serds, ep); 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 6847c478bd9Sstevel@tonic-gate return (rv); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate void 6887c478bd9Sstevel@tonic-gate fmd_module_setdirty(fmd_module_t *mp) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 6917c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_MDIRTY; 6927c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate void 6967c478bd9Sstevel@tonic-gate fmd_module_setcdirty(fmd_module_t *mp) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 6997c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_CDIRTY; 7007c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate void 7047c478bd9Sstevel@tonic-gate fmd_module_clrdirty(fmd_module_t *mp) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate fmd_case_t *cp; 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_CDIRTY) { 7117c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); 7127c478bd9Sstevel@tonic-gate cp != NULL; cp = fmd_list_next(cp)) 7137c478bd9Sstevel@tonic-gate fmd_case_clrdirty(cp); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_MDIRTY) { 7177c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 7187c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_serd_eng_clrdirty, NULL); 7197c478bd9Sstevel@tonic-gate fmd_buf_hash_commit(&mp->mod_bufs); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 7237c478bd9Sstevel@tonic-gate mp->mod_flags &= ~(FMD_MOD_MDIRTY | FMD_MOD_CDIRTY); 7247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate void 7307c478bd9Sstevel@tonic-gate fmd_module_commit(fmd_module_t *mp) 7317c478bd9Sstevel@tonic-gate { 7327c478bd9Sstevel@tonic-gate fmd_case_t *cp; 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate ASSERT(fmd_module_locked(mp)); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_CDIRTY) { 7377c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); 7387c478bd9Sstevel@tonic-gate cp != NULL; cp = fmd_list_next(cp)) 7397c478bd9Sstevel@tonic-gate fmd_case_commit(cp); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_MDIRTY) { 7437c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 7447c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_serd_eng_commit, NULL); 7457c478bd9Sstevel@tonic-gate fmd_buf_hash_commit(&mp->mod_bufs); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 7497c478bd9Sstevel@tonic-gate mp->mod_flags &= ~(FMD_MOD_MDIRTY | FMD_MOD_CDIRTY); 7507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate mp->mod_gen++; 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate void 7567c478bd9Sstevel@tonic-gate fmd_module_lock(fmd_module_t *mp) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate pthread_t self = pthread_self(); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate while (mp->mod_flags & FMD_MOD_LOCK) { 7637c478bd9Sstevel@tonic-gate if (mp->mod_owner != self) 7647c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 7657c478bd9Sstevel@tonic-gate else 7667c478bd9Sstevel@tonic-gate fmd_panic("recursive module lock of %p\n", (void *)mp); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate mp->mod_owner = self; 7707c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_LOCK; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 773d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate void 7777c478bd9Sstevel@tonic-gate fmd_module_unlock(fmd_module_t *mp) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate ASSERT(mp->mod_owner == pthread_self()); 7827c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_LOCK); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate mp->mod_owner = 0; 7857c478bd9Sstevel@tonic-gate mp->mod_flags &= ~FMD_MOD_LOCK; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 788d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate int 7927c478bd9Sstevel@tonic-gate fmd_module_trylock(fmd_module_t *mp) 7937c478bd9Sstevel@tonic-gate { 7947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate if (mp->mod_flags & FMD_MOD_LOCK) { 7977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 7987c478bd9Sstevel@tonic-gate return (0); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate mp->mod_owner = pthread_self(); 8027c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_LOCK; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 805d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate return (1); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate int 8117c478bd9Sstevel@tonic-gate fmd_module_locked(fmd_module_t *mp) 8127c478bd9Sstevel@tonic-gate { 8137c478bd9Sstevel@tonic-gate return ((mp->mod_flags & FMD_MOD_LOCK) && 8147c478bd9Sstevel@tonic-gate mp->mod_owner == pthread_self()); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate int 8187c478bd9Sstevel@tonic-gate fmd_module_enter(fmd_module_t *mp, void (*func)(fmd_hdl_t *)) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate volatile int err; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate ASSERT(!(mp->mod_flags & FMD_MOD_BUSY)); 8257c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_BUSY; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if ((err = setjmp(mp->mod_jmpbuf)) != 0) { 8287c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 8297c478bd9Sstevel@tonic-gate fmd_module_error(mp, err); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 833d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * If it's the first time through fmd_module_enter(), call the provided 8377c478bd9Sstevel@tonic-gate * function on the module. If no fmd_module_abort() results, we will 8387c478bd9Sstevel@tonic-gate * fall through and return zero. Otherwise we'll longjmp with an err, 8397c478bd9Sstevel@tonic-gate * return to the setjmp() above, and return the error to our caller. 8407c478bd9Sstevel@tonic-gate */ 8417c478bd9Sstevel@tonic-gate if (err == 0 && func != NULL) 8427c478bd9Sstevel@tonic-gate (*func)((fmd_hdl_t *)mp); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate return (err); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate void 8487c478bd9Sstevel@tonic-gate fmd_module_exit(fmd_module_t *mp) 8497c478bd9Sstevel@tonic-gate { 8507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_BUSY); 8537c478bd9Sstevel@tonic-gate mp->mod_flags &= ~FMD_MOD_BUSY; 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 856d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * If the client.error policy has been set by a developer, stop or dump core 8617c478bd9Sstevel@tonic-gate * based on the policy; if we stop and are resumed we'll continue and execute 8627c478bd9Sstevel@tonic-gate * the default behavior to discard events in fmd_module_start(). If the caller 8637c478bd9Sstevel@tonic-gate * is the primary module thread, we reach this state by longjmp'ing back to 8647c478bd9Sstevel@tonic-gate * fmd_module_enter(), above. If the caller is an auxiliary thread, we cancel 8657c478bd9Sstevel@tonic-gate * ourself and arrange for the primary thread to call fmd_module_abort(). 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate void 8687c478bd9Sstevel@tonic-gate fmd_module_abort(fmd_module_t *mp, int err) 8697c478bd9Sstevel@tonic-gate { 8707c478bd9Sstevel@tonic-gate uint_t policy = FMD_CERROR_UNLOAD; 8717c478bd9Sstevel@tonic-gate pthread_t tid = pthread_self(); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "client.error", &policy); 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate if (policy == FMD_CERROR_STOP) { 8767c478bd9Sstevel@tonic-gate fmd_error(err, "stopping after %s in client %s (%p)\n", 8777c478bd9Sstevel@tonic-gate fmd_errclass(err), mp->mod_name, (void *)mp); 8787c478bd9Sstevel@tonic-gate (void) raise(SIGSTOP); 8797c478bd9Sstevel@tonic-gate } else if (policy == FMD_CERROR_ABORT) { 8807c478bd9Sstevel@tonic-gate fmd_panic("aborting due to %s in client %s (%p)\n", 8817c478bd9Sstevel@tonic-gate fmd_errclass(err), mp->mod_name, (void *)mp); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * If the caller is an auxiliary thread, cancel the current thread. We 8867c478bd9Sstevel@tonic-gate * prefer to cancel because it affords developers the option of using 8877c478bd9Sstevel@tonic-gate * the pthread_cleanup* APIs. If cancellations have been disabled, 8887c478bd9Sstevel@tonic-gate * fall through to forcing the current thread to exit. In either case 8897c478bd9Sstevel@tonic-gate * we update mod_error (if zero) to enter the failed state. Once that 8907c478bd9Sstevel@tonic-gate * is set, further events received by the module will be discarded. 8917c478bd9Sstevel@tonic-gate * 8927c478bd9Sstevel@tonic-gate * We also set the FMD_MOD_FAIL bit, indicating an unrecoverable error. 8937c478bd9Sstevel@tonic-gate * When an auxiliary thread fails, the module is left in a delicate 8947c478bd9Sstevel@tonic-gate * state where it is likely not able to continue execution (even to 8957c478bd9Sstevel@tonic-gate * execute its _fmd_fini() routine) because our caller may hold locks 8967c478bd9Sstevel@tonic-gate * that are private to the module and can no longer be released. The 8977c478bd9Sstevel@tonic-gate * FMD_MOD_FAIL bit forces fmd_api_module_lock() to abort if any other 8987c478bd9Sstevel@tonic-gate * module threads reach an API call, in an attempt to get them to exit. 8997c478bd9Sstevel@tonic-gate */ 9007c478bd9Sstevel@tonic-gate if (tid != mp->mod_thread->thr_tid) { 9017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate if (mp->mod_error == 0) 9047c478bd9Sstevel@tonic-gate mp->mod_error = err; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_FAIL; 9077c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate (void) pthread_cancel(tid); 9107c478bd9Sstevel@tonic-gate pthread_exit(NULL); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_BUSY); 9147c478bd9Sstevel@tonic-gate longjmp(mp->mod_jmpbuf, err); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate void 9187c478bd9Sstevel@tonic-gate fmd_module_hold(fmd_module_t *mp) 9197c478bd9Sstevel@tonic-gate { 9207c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_MOD, "hold %p (%s/%u)\n", 9237c478bd9Sstevel@tonic-gate (void *)mp, mp->mod_name, mp->mod_refs)); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate mp->mod_refs++; 9267c478bd9Sstevel@tonic-gate ASSERT(mp->mod_refs != 0); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate void 9327c478bd9Sstevel@tonic-gate fmd_module_rele(fmd_module_t *mp) 9337c478bd9Sstevel@tonic-gate { 9347c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_MOD, "rele %p (%s/%u)\n", 9377c478bd9Sstevel@tonic-gate (void *)mp, mp->mod_name, mp->mod_refs)); 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate ASSERT(mp->mod_refs != 0); 9407c478bd9Sstevel@tonic-gate 941d9638e54Smws if (--mp->mod_refs == 0) 942d9638e54Smws fmd_module_destroy(mp); 943d9638e54Smws else 9447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * Wrapper around libdiagcode's fm_dc_opendict() to load module dictionaries. 9497c478bd9Sstevel@tonic-gate * If the dictionary open is successful, the new dictionary is added to the 9507c478bd9Sstevel@tonic-gate * mod_dictv[] array and mod_codelen is updated with the new maximum length. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate int 9537c478bd9Sstevel@tonic-gate fmd_module_dc_opendict(fmd_module_t *mp, const char *dict) 9547c478bd9Sstevel@tonic-gate { 9557c478bd9Sstevel@tonic-gate struct fm_dc_handle *dcp, **dcv; 9567c478bd9Sstevel@tonic-gate char *dictdir, *dictnam, *p; 9577c478bd9Sstevel@tonic-gate size_t len; 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate ASSERT(fmd_module_locked(mp)); 9607c478bd9Sstevel@tonic-gate 961*23a1cceaSRoger A. Faulkner dictnam = strdupa(fmd_strbasename(dict)); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate if ((p = strrchr(dictnam, '.')) != NULL && 9647c478bd9Sstevel@tonic-gate strcmp(p, ".dict") == 0) 9657c478bd9Sstevel@tonic-gate *p = '\0'; /* eliminate any trailing .dict suffix */ 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * If 'dict' is an absolute path, dictdir = $rootdir/`dirname dict` 9697c478bd9Sstevel@tonic-gate * If 'dict' is not an absolute path, dictdir = $dictdir/`dirname dict` 9707c478bd9Sstevel@tonic-gate */ 9717c478bd9Sstevel@tonic-gate if (dict[0] == '/') { 9727c478bd9Sstevel@tonic-gate len = strlen(fmd.d_rootdir) + strlen(dict) + 1; 9737c478bd9Sstevel@tonic-gate dictdir = alloca(len); 9747c478bd9Sstevel@tonic-gate (void) snprintf(dictdir, len, "%s%s", fmd.d_rootdir, dict); 9757c478bd9Sstevel@tonic-gate (void) fmd_strdirname(dictdir); 9767c478bd9Sstevel@tonic-gate } else { 9777c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "dictdir", &p); 9787c478bd9Sstevel@tonic-gate len = strlen(fmd.d_rootdir) + strlen(p) + strlen(dict) + 3; 9797c478bd9Sstevel@tonic-gate dictdir = alloca(len); 9807c478bd9Sstevel@tonic-gate (void) snprintf(dictdir, len, 9817c478bd9Sstevel@tonic-gate "%s/%s/%s", fmd.d_rootdir, p, dict); 9827c478bd9Sstevel@tonic-gate (void) fmd_strdirname(dictdir); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_MOD, "module %s opening %s -> %s/%s.dict\n", 9867c478bd9Sstevel@tonic-gate mp->mod_name, dict, dictdir, dictnam); 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate if ((dcp = fm_dc_opendict(FM_DC_VERSION, dictdir, dictnam)) == NULL) 9897c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate dcv = fmd_alloc(sizeof (dcp) * (mp->mod_dictc + 1), FMD_SLEEP); 9927c478bd9Sstevel@tonic-gate bcopy(mp->mod_dictv, dcv, sizeof (dcp) * mp->mod_dictc); 9937c478bd9Sstevel@tonic-gate fmd_free(mp->mod_dictv, sizeof (dcp) * mp->mod_dictc); 9947c478bd9Sstevel@tonic-gate mp->mod_dictv = dcv; 9957c478bd9Sstevel@tonic-gate mp->mod_dictv[mp->mod_dictc++] = dcp; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate len = fm_dc_codelen(dcp); 9987c478bd9Sstevel@tonic-gate mp->mod_codelen = MAX(mp->mod_codelen, len); 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate return (0); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * Wrapper around libdiagcode's fm_dc_key2code() that examines all the module's 10057c478bd9Sstevel@tonic-gate * dictionaries. We adhere to the libdiagcode return values and semantics. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate int 10087c478bd9Sstevel@tonic-gate fmd_module_dc_key2code(fmd_module_t *mp, 10097c478bd9Sstevel@tonic-gate char *const keys[], char *code, size_t codelen) 10107c478bd9Sstevel@tonic-gate { 10117c478bd9Sstevel@tonic-gate int i, err; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate for (i = 0; i < mp->mod_dictc; i++) { 10147c478bd9Sstevel@tonic-gate if ((err = fm_dc_key2code(mp->mod_dictv[i], (const char **)keys, 10157c478bd9Sstevel@tonic-gate code, codelen)) == 0 || errno != ENOMSG) 10167c478bd9Sstevel@tonic-gate return (err); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate return (fmd_set_errno(ENOMSG)); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate fmd_modhash_t * 10237c478bd9Sstevel@tonic-gate fmd_modhash_create(void) 10247c478bd9Sstevel@tonic-gate { 10257c478bd9Sstevel@tonic-gate fmd_modhash_t *mhp = fmd_alloc(sizeof (fmd_modhash_t), FMD_SLEEP); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate (void) pthread_rwlock_init(&mhp->mh_lock, NULL); 10287c478bd9Sstevel@tonic-gate mhp->mh_hashlen = fmd.d_str_buckets; 10297c478bd9Sstevel@tonic-gate mhp->mh_hash = fmd_zalloc(sizeof (void *) * mhp->mh_hashlen, FMD_SLEEP); 10307c478bd9Sstevel@tonic-gate mhp->mh_nelems = 0; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate return (mhp); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate void 10367c478bd9Sstevel@tonic-gate fmd_modhash_destroy(fmd_modhash_t *mhp) 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate fmd_module_t *mp, *nmp; 10397c478bd9Sstevel@tonic-gate uint_t i; 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate for (i = 0; i < mhp->mh_hashlen; i++) { 10427c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[i]; mp != NULL; mp = nmp) { 10437c478bd9Sstevel@tonic-gate nmp = mp->mod_next; 10447c478bd9Sstevel@tonic-gate mp->mod_next = NULL; 10457c478bd9Sstevel@tonic-gate fmd_module_rele(mp); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate fmd_free(mhp->mh_hash, sizeof (void *) * mhp->mh_hashlen); 10507c478bd9Sstevel@tonic-gate (void) pthread_rwlock_destroy(&mhp->mh_lock); 10517c478bd9Sstevel@tonic-gate fmd_free(mhp, sizeof (fmd_modhash_t)); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate static void 10557c478bd9Sstevel@tonic-gate fmd_modhash_loaddir(fmd_modhash_t *mhp, const char *dir, 10560b9e3e76Smws const fmd_modops_t *ops, const char *suffix) 10577c478bd9Sstevel@tonic-gate { 10587c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 10594bc0a2efScasper struct dirent *dp; 10607c478bd9Sstevel@tonic-gate const char *p; 10617c478bd9Sstevel@tonic-gate DIR *dirp; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if ((dirp = opendir(dir)) == NULL) 10647c478bd9Sstevel@tonic-gate return; /* failed to open directory; just skip it */ 10657c478bd9Sstevel@tonic-gate 10664bc0a2efScasper while ((dp = readdir(dirp)) != NULL) { 10677c478bd9Sstevel@tonic-gate if (dp->d_name[0] == '.') 10687c478bd9Sstevel@tonic-gate continue; /* skip "." and ".." */ 10697c478bd9Sstevel@tonic-gate 10700b9e3e76Smws p = strrchr(dp->d_name, '.'); 10710b9e3e76Smws 10720b9e3e76Smws if (p != NULL && strcmp(p, ".conf") == 0) 10737c478bd9Sstevel@tonic-gate continue; /* skip .conf files */ 10747c478bd9Sstevel@tonic-gate 10750b9e3e76Smws if (suffix != NULL && (p == NULL || strcmp(p, suffix) != 0)) 10760b9e3e76Smws continue; /* skip files with the wrong suffix */ 10770b9e3e76Smws 10787c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%s", dir, dp->d_name); 10797c478bd9Sstevel@tonic-gate (void) fmd_modhash_load(mhp, path, ops); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate (void) closedir(dirp); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate void 10867c478bd9Sstevel@tonic-gate fmd_modhash_loadall(fmd_modhash_t *mhp, const fmd_conf_path_t *pap, 10870b9e3e76Smws const fmd_modops_t *ops, const char *suffix) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate int i; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate for (i = 0; i < pap->cpa_argc; i++) 10920b9e3e76Smws fmd_modhash_loaddir(mhp, pap->cpa_argv[i], ops, suffix); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate void 10967c478bd9Sstevel@tonic-gate fmd_modhash_apply(fmd_modhash_t *mhp, void (*func)(fmd_module_t *)) 10977c478bd9Sstevel@tonic-gate { 10987c478bd9Sstevel@tonic-gate fmd_module_t *mp, *np; 10997c478bd9Sstevel@tonic-gate uint_t i; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&mhp->mh_lock); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate for (i = 0; i < mhp->mh_hashlen; i++) { 11047c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[i]; mp != NULL; mp = np) { 11057c478bd9Sstevel@tonic-gate np = mp->mod_next; 11067c478bd9Sstevel@tonic-gate func(mp); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate void 11147c478bd9Sstevel@tonic-gate fmd_modhash_tryapply(fmd_modhash_t *mhp, void (*func)(fmd_module_t *)) 11157c478bd9Sstevel@tonic-gate { 11167c478bd9Sstevel@tonic-gate fmd_module_t *mp, *np; 11177c478bd9Sstevel@tonic-gate uint_t i; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate if (mhp == NULL || pthread_rwlock_tryrdlock(&mhp->mh_lock) != 0) 11207c478bd9Sstevel@tonic-gate return; /* not initialized or couldn't grab lock */ 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate for (i = 0; i < mhp->mh_hashlen; i++) { 11237c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[i]; mp != NULL; mp = np) { 11247c478bd9Sstevel@tonic-gate np = mp->mod_next; 11257c478bd9Sstevel@tonic-gate func(mp); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate void 11337c478bd9Sstevel@tonic-gate fmd_modhash_dispatch(fmd_modhash_t *mhp, fmd_event_t *ep) 11347c478bd9Sstevel@tonic-gate { 11357c478bd9Sstevel@tonic-gate fmd_module_t *mp; 11367c478bd9Sstevel@tonic-gate uint_t i; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate fmd_event_hold(ep); 11397c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&mhp->mh_lock); 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate for (i = 0; i < mhp->mh_hashlen; i++) { 11427c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) { 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * If FMD_MOD_INIT is set but MOD_FINI, MOD_QUIT, and 11457c478bd9Sstevel@tonic-gate * mod_error are all zero, then the module is active: 11467c478bd9Sstevel@tonic-gate * enqueue the event in the corresponding event queue. 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate if ((mp->mod_flags & (FMD_MOD_INIT | FMD_MOD_FINI | 11512a417b23SRobert Johnston FMD_MOD_QUIT)) == FMD_MOD_INIT && !mp->mod_error) { 11522a417b23SRobert Johnston 11532a417b23SRobert Johnston /* 11542a417b23SRobert Johnston * If the event we're dispatching is of type 11552a417b23SRobert Johnston * FMD_EVT_TOPO and there are already redundant 11562a417b23SRobert Johnston * FMD_EVT_TOPO events in this module's queue, 11572a417b23SRobert Johnston * then drop those before adding the new one. 11582a417b23SRobert Johnston */ 11592a417b23SRobert Johnston if (FMD_EVENT_TYPE(ep) == FMD_EVT_TOPO) 11602a417b23SRobert Johnston fmd_eventq_drop_topo(mp->mod_queue); 11612a417b23SRobert Johnston 11627c478bd9Sstevel@tonic-gate fmd_eventq_insert_at_time(mp->mod_queue, ep); 11637c478bd9Sstevel@tonic-gate 11642a417b23SRobert Johnston } 11657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 11707c478bd9Sstevel@tonic-gate fmd_event_rele(ep); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate fmd_module_t * 11747c478bd9Sstevel@tonic-gate fmd_modhash_lookup(fmd_modhash_t *mhp, const char *name) 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate fmd_module_t *mp; 11777c478bd9Sstevel@tonic-gate uint_t h; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&mhp->mh_lock); 11807c478bd9Sstevel@tonic-gate h = fmd_strhash(name) % mhp->mh_hashlen; 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[h]; mp != NULL; mp = mp->mod_next) { 11837c478bd9Sstevel@tonic-gate if (strcmp(name, mp->mod_name) == 0) 11847c478bd9Sstevel@tonic-gate break; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate if (mp != NULL) 11887c478bd9Sstevel@tonic-gate fmd_module_hold(mp); 11897c478bd9Sstevel@tonic-gate else 11907c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_MOD_NOMOD); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 11937c478bd9Sstevel@tonic-gate return (mp); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate fmd_module_t * 11977c478bd9Sstevel@tonic-gate fmd_modhash_load(fmd_modhash_t *mhp, const char *path, const fmd_modops_t *ops) 11987c478bd9Sstevel@tonic-gate { 11997c478bd9Sstevel@tonic-gate char name[PATH_MAX], *p; 12007c478bd9Sstevel@tonic-gate fmd_module_t *mp; 12017c478bd9Sstevel@tonic-gate int tries = 0; 12027c478bd9Sstevel@tonic-gate uint_t h; 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate (void) strlcpy(name, fmd_strbasename(path), sizeof (name)); 12057c478bd9Sstevel@tonic-gate if ((p = strrchr(name, '.')) != NULL && strcmp(p, ".so") == 0) 12067c478bd9Sstevel@tonic-gate *p = '\0'; /* strip trailing .so from any module name */ 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&mhp->mh_lock); 12097c478bd9Sstevel@tonic-gate h = fmd_strhash(name) % mhp->mh_hashlen; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate /* 12127c478bd9Sstevel@tonic-gate * First check to see if a module is already present in the hash table 12137c478bd9Sstevel@tonic-gate * for this name. If so, the module is already loaded: skip it. 12147c478bd9Sstevel@tonic-gate */ 12157c478bd9Sstevel@tonic-gate for (mp = mhp->mh_hash[h]; mp != NULL; mp = mp->mod_next) { 12167c478bd9Sstevel@tonic-gate if (strcmp(name, mp->mod_name) == 0) 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if (mp != NULL) { 12217c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 12227c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_MOD_LOADED); 12237c478bd9Sstevel@tonic-gate return (NULL); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate /* 12277c478bd9Sstevel@tonic-gate * fmd_module_create() will return a held (as if by fmd_module_hold()) 12287c478bd9Sstevel@tonic-gate * module. We leave this hold in place to correspond to the hash-in. 12297c478bd9Sstevel@tonic-gate */ 12307c478bd9Sstevel@tonic-gate while ((mp = fmd_module_create(path, ops)) == NULL) { 12317c478bd9Sstevel@tonic-gate if (tries++ != 0 || errno != EFMD_CKPT_INVAL) { 12327c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 12337c478bd9Sstevel@tonic-gate return (NULL); /* errno is set for us */ 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate mp->mod_hash = mhp; 12387c478bd9Sstevel@tonic-gate mp->mod_next = mhp->mh_hash[h]; 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate mhp->mh_hash[h] = mp; 12417c478bd9Sstevel@tonic-gate mhp->mh_nelems++; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 12447c478bd9Sstevel@tonic-gate return (mp); 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate int 12487c478bd9Sstevel@tonic-gate fmd_modhash_unload(fmd_modhash_t *mhp, const char *name) 12497c478bd9Sstevel@tonic-gate { 12507c478bd9Sstevel@tonic-gate fmd_module_t *mp, **pp; 12517c478bd9Sstevel@tonic-gate uint_t h; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&mhp->mh_lock); 12547c478bd9Sstevel@tonic-gate h = fmd_strhash(name) % mhp->mh_hashlen; 12557c478bd9Sstevel@tonic-gate pp = &mhp->mh_hash[h]; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate for (mp = *pp; mp != NULL; mp = mp->mod_next) { 12587c478bd9Sstevel@tonic-gate if (strcmp(name, mp->mod_name) == 0) 12597c478bd9Sstevel@tonic-gate break; 12607c478bd9Sstevel@tonic-gate else 12617c478bd9Sstevel@tonic-gate pp = &mp->mod_next; 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (mp == NULL) { 12657c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 12667c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_MOD_NOMOD)); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate *pp = mp->mod_next; 12707c478bd9Sstevel@tonic-gate mp->mod_next = NULL; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate ASSERT(mhp->mh_nelems != 0); 12737c478bd9Sstevel@tonic-gate mhp->mh_nelems--; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&mhp->mh_lock); 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate fmd_module_unload(mp); 12787c478bd9Sstevel@tonic-gate fmd_module_rele(mp); 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate return (0); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate void 12847c478bd9Sstevel@tonic-gate fmd_modstat_publish(fmd_module_t *mp) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_STSUB); 12897c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_STPUB; 12907c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate while (mp->mod_flags & FMD_MOD_STPUB) 12937c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate int 12997c478bd9Sstevel@tonic-gate fmd_modstat_snapshot(fmd_module_t *mp, fmd_ustat_snap_t *uss) 13007c478bd9Sstevel@tonic-gate { 13017c478bd9Sstevel@tonic-gate fmd_event_t *e; 13027c478bd9Sstevel@tonic-gate int err; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * Grab the module lock and wait for the STSUB bit to be clear. Then 13067c478bd9Sstevel@tonic-gate * set it to indicate we are a subscriber and everyone else must wait. 13077c478bd9Sstevel@tonic-gate */ 13087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate while (mp->mod_error == 0 && (mp->mod_flags & FMD_MOD_STSUB)) 13117c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate if (mp->mod_error != 0) { 13147c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 13157c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_HDL_ABORT)); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate mp->mod_flags |= FMD_MOD_STSUB; 13197c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 1320d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Create a stats pseudo-event and dispatch it to the module, forcing 13247c478bd9Sstevel@tonic-gate * it to next execute its custom snapshot routine (or the empty one). 13257c478bd9Sstevel@tonic-gate */ 13267c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_STATS, FMD_HRT_NOW, NULL, NULL); 13277c478bd9Sstevel@tonic-gate fmd_eventq_insert_at_head(mp->mod_queue, e); 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate /* 13307c478bd9Sstevel@tonic-gate * Grab the module lock and then wait on mod_cv for STPUB to be set, 13317c478bd9Sstevel@tonic-gate * indicating the snapshot routine is completed and the module is idle. 13327c478bd9Sstevel@tonic-gate */ 13337c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 13347c478bd9Sstevel@tonic-gate 1335e58a33b6SStephen Hanson while (mp->mod_error == 0 && !(mp->mod_flags & FMD_MOD_STPUB)) { 1336e58a33b6SStephen Hanson struct timespec tms; 1337e58a33b6SStephen Hanson 13387c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&mp->mod_cv, &mp->mod_lock); 1339e58a33b6SStephen Hanson (void) pthread_mutex_unlock(&mp->mod_lock); 1340e58a33b6SStephen Hanson tms.tv_sec = 0; 1341e58a33b6SStephen Hanson tms.tv_nsec = 10000000; 1342e58a33b6SStephen Hanson (void) nanosleep(&tms, NULL); 1343e58a33b6SStephen Hanson (void) pthread_mutex_lock(&mp->mod_lock); 1344e58a33b6SStephen Hanson } 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (mp->mod_error != 0) { 13477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_lock); 13487c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_HDL_ABORT)); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 1352d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * Update ms_snaptime and take the actual snapshot of the various 13567c478bd9Sstevel@tonic-gate * statistics while the module is quiescent and waiting for us. 13577c478bd9Sstevel@tonic-gate */ 13587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_stats_lock); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate if (mp->mod_stats != NULL) { 13617c478bd9Sstevel@tonic-gate mp->mod_stats->ms_snaptime.fmds_value.ui64 = gethrtime(); 13627c478bd9Sstevel@tonic-gate err = fmd_ustat_snapshot(mp->mod_ustat, uss); 13637c478bd9Sstevel@tonic-gate } else 13647c478bd9Sstevel@tonic-gate err = fmd_set_errno(EFMD_HDL_ABORT); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&mp->mod_stats_lock); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* 13697c478bd9Sstevel@tonic-gate * With the snapshot complete, grab the module lock and clear both 13707c478bd9Sstevel@tonic-gate * STSUB and STPUB, permitting everyone to wake up and continue. 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&mp->mod_lock); 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_STSUB); 13757c478bd9Sstevel@tonic-gate ASSERT(mp->mod_flags & FMD_MOD_STPUB); 13767c478bd9Sstevel@tonic-gate mp->mod_flags &= ~(FMD_MOD_STSUB | FMD_MOD_STPUB); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&mp->mod_cv); 1379d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_lock); 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate return (err); 13827c478bd9Sstevel@tonic-gate } 138324db4641Seschrock 138424db4641Seschrock struct topo_hdl * 138524db4641Seschrock fmd_module_topo_hold(fmd_module_t *mp) 138624db4641Seschrock { 138724db4641Seschrock fmd_modtopo_t *mtp; 138824db4641Seschrock 138924db4641Seschrock ASSERT(fmd_module_locked(mp)); 139024db4641Seschrock 139124db4641Seschrock mtp = fmd_zalloc(sizeof (fmd_modtopo_t), FMD_SLEEP); 139224db4641Seschrock mtp->mt_topo = mp->mod_topo_current; 139324db4641Seschrock fmd_topo_addref(mtp->mt_topo); 139424db4641Seschrock fmd_list_prepend(&mp->mod_topolist, mtp); 139524db4641Seschrock 139624db4641Seschrock return (mtp->mt_topo->ft_hdl); 139724db4641Seschrock } 139824db4641Seschrock 139924db4641Seschrock int 140024db4641Seschrock fmd_module_topo_rele(fmd_module_t *mp, struct topo_hdl *hdl) 140124db4641Seschrock { 140224db4641Seschrock fmd_modtopo_t *mtp; 140324db4641Seschrock 140424db4641Seschrock ASSERT(fmd_module_locked(mp)); 140524db4641Seschrock 140624db4641Seschrock for (mtp = fmd_list_next(&mp->mod_topolist); mtp != NULL; 140724db4641Seschrock mtp = fmd_list_next(mtp)) { 140824db4641Seschrock if (mtp->mt_topo->ft_hdl == hdl) 140924db4641Seschrock break; 141024db4641Seschrock } 141124db4641Seschrock 141224db4641Seschrock if (mtp == NULL) 141324db4641Seschrock return (-1); 141424db4641Seschrock 141524db4641Seschrock fmd_list_delete(&mp->mod_topolist, mtp); 141624db4641Seschrock fmd_topo_rele(mtp->mt_topo); 141724db4641Seschrock fmd_free(mtp, sizeof (fmd_modtopo_t)); 141824db4641Seschrock return (0); 141924db4641Seschrock } 1420