1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * FMD Dynamic Reconfiguration (DR) Event Handling 30 * 31 * Fault manager scheme plug-ins must track characteristics of individual 32 * pieces of hardware. As these components can be added or removed by a DR 33 * operation, we need to provide a means by which plug-ins can determine when 34 * they need to re-examine the current configuration. We provide a simple 35 * mechanism whereby this task can be implemented using lazy evaluation: a 36 * simple 64-bit generation counter is maintained and incremented on *any* DR. 37 * Schemes can store the generation number in scheme-specific data structures, 38 * and then revalidate their contents if the current generation number has 39 * changed since the resource information was cached. This method saves time, 40 * avoids the complexity of direct participation in DR, avoids the need for 41 * resource-specific processing of DR events, and is relatively easy to port 42 * to other systems that support dynamic reconfiguration. 43 */ 44 45 #include <sys/types.h> 46 #include <sys/sysevent/dr.h> 47 #include <sys/sysevent/eventdefs.h> 48 49 #include <stdio.h> 50 #include <unistd.h> 51 #include <libsysevent.h> 52 53 #undef MUTEX_HELD 54 #undef RW_READ_HELD 55 #undef RW_WRITE_HELD 56 57 #include <fmd_asru.h> 58 #include <fmd_error.h> 59 #include <fmd_fmri.h> 60 #include <fmd_subr.h> 61 #include <fmd.h> 62 63 static void 64 fmd_dr_repair_containee(fmd_asru_t *ee, void *er) 65 { 66 if ((ee->asru_flags & FMD_ASRU_FAULTY) && 67 fmd_fmri_contains(er, ee->asru_fmri) > 0) 68 (void) fmd_asru_clrflags(ee, FMD_ASRU_FAULTY, NULL, NULL); 69 } 70 71 /*ARGSUSED*/ 72 static void 73 fmd_dr_rcache_sync(fmd_asru_t *ap, void *arg) 74 { 75 if (fmd_fmri_present(ap->asru_fmri) != 0) 76 return; 77 78 if (!fmd_asru_clrflags(ap, FMD_ASRU_FAULTY, NULL, NULL)) 79 return; 80 81 /* 82 * We've located the requested ASRU, and have repaired it. Now 83 * traverse the ASRU cache, looking for any faulty entries that 84 * are contained by this one. If we find any, repair them too. 85 */ 86 fmd_asru_hash_apply(fmd.d_asrus, fmd_dr_repair_containee, 87 ap->asru_fmri); 88 } 89 90 static void 91 fmd_dr_event(sysevent_t *sep) 92 { 93 uint64_t gen; 94 95 /* 96 * If the event target is in the R$ and this sysevent indicates it was 97 * removed, remove it from the R$ also. 98 */ 99 (void) fmd_asru_hash_apply(fmd.d_asrus, fmd_dr_rcache_sync, NULL); 100 101 (void) pthread_mutex_lock(&fmd.d_stats_lock); 102 gen = fmd.d_stats->ds_dr_gen.fmds_value.ui64++; 103 (void) pthread_mutex_unlock(&fmd.d_stats_lock); 104 105 TRACE((FMD_DBG_XPRT, "dr event %p, gen=%llu", (void *)sep, gen)); 106 } 107 108 void 109 fmd_dr_init(void) 110 { 111 const char *subclass = ESC_DR_AP_STATE_CHANGE; 112 113 if (geteuid() != 0) 114 return; /* legacy sysevent mechanism is still root-only */ 115 116 if ((fmd.d_dr_hdl = sysevent_bind_handle(fmd_dr_event)) == NULL) 117 fmd_error(EFMD_EXIT, "failed to bind handle for DR sysevent"); 118 119 if (sysevent_subscribe_event(fmd.d_dr_hdl, EC_DR, &subclass, 1) == -1) 120 fmd_error(EFMD_EXIT, "failed to subscribe for DR sysevent"); 121 } 122 123 void 124 fmd_dr_fini(void) 125 { 126 if (fmd.d_dr_hdl != NULL) { 127 sysevent_unsubscribe_event(fmd.d_dr_hdl, EC_DR); 128 sysevent_unbind_handle(fmd.d_dr_hdl); 129 } 130 } 131