1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1717 wesolows * Common Development and Distribution License (the "License"). 6 1717 wesolows * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 1193 mws 22 0 stevel /* 23 8526 Robert * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #include <sys/types.h> 28 0 stevel #include <sys/fm/protocol.h> 29 7197 stephh #include <fm/topo_hc.h> 30 0 stevel 31 0 stevel #include <unistd.h> 32 0 stevel #include <signal.h> 33 0 stevel #include <limits.h> 34 0 stevel #include <syslog.h> 35 0 stevel #include <alloca.h> 36 4198 eschrock #include <stddef.h> 37 0 stevel 38 0 stevel #include <fmd_module.h> 39 0 stevel #include <fmd_api.h> 40 0 stevel #include <fmd_string.h> 41 0 stevel #include <fmd_subr.h> 42 0 stevel #include <fmd_error.h> 43 0 stevel #include <fmd_event.h> 44 0 stevel #include <fmd_eventq.h> 45 0 stevel #include <fmd_dispq.h> 46 0 stevel #include <fmd_timerq.h> 47 0 stevel #include <fmd_thread.h> 48 0 stevel #include <fmd_ustat.h> 49 0 stevel #include <fmd_case.h> 50 0 stevel #include <fmd_protocol.h> 51 0 stevel #include <fmd_buf.h> 52 0 stevel #include <fmd_asru.h> 53 0 stevel #include <fmd_fmri.h> 54 3062 cindi #include <fmd_topo.h> 55 0 stevel #include <fmd_ckpt.h> 56 1193 mws #include <fmd_xprt.h> 57 0 stevel 58 0 stevel #include <fmd.h> 59 0 stevel 60 0 stevel /* 61 0 stevel * Table of configuration file variable types ops-vector pointers. We use this 62 0 stevel * to convert from the property description array specified by the module to an 63 0 stevel * array of fmd_conf_formal_t's. The order of this array must match the order 64 0 stevel * of #define values specified in <fmd_api.h> (i.e. FMD_TYPE_BOOL must be 0). 65 0 stevel * For now, the fmd_conf_list and fmd_conf_path types are not supported as we 66 0 stevel * do not believe modules need them and they would require more complexity. 67 0 stevel */ 68 0 stevel static const fmd_conf_ops_t *const _fmd_prop_ops[] = { 69 0 stevel &fmd_conf_bool, /* FMD_TYPE_BOOL */ 70 0 stevel &fmd_conf_int32, /* FMD_TYPE_INT32 */ 71 0 stevel &fmd_conf_uint32, /* FMD_TYPE_UINT32 */ 72 0 stevel &fmd_conf_int64, /* FMD_TYPE_INT64 */ 73 0 stevel &fmd_conf_uint64, /* FMD_TYPE_UINT64 */ 74 0 stevel &fmd_conf_string, /* FMD_TYPE_STRING */ 75 0 stevel &fmd_conf_time, /* FMD_TYPE_TIME */ 76 0 stevel &fmd_conf_size, /* FMD_TYPE_SIZE */ 77 0 stevel }; 78 1717 wesolows 79 1717 wesolows static void fmd_api_verror(fmd_module_t *, int, const char *, va_list) 80 1717 wesolows __NORETURN; 81 1717 wesolows static void fmd_api_error(fmd_module_t *, int, const char *, ...) __NORETURN; 82 0 stevel 83 0 stevel /* 84 0 stevel * fmd_api_vxerror() provides the engine underlying the fmd_hdl_[v]error() API 85 0 stevel * calls and the fmd_api_[v]error() utility routine defined below. The routine 86 0 stevel * formats the error, optionally associated with a particular errno code 'err', 87 0 stevel * and logs it as an ereport associated with the calling module. Depending on 88 0 stevel * other optional properties, we also emit a message to stderr and to syslog. 89 0 stevel */ 90 0 stevel static void 91 0 stevel fmd_api_vxerror(fmd_module_t *mp, int err, const char *format, va_list ap) 92 0 stevel { 93 1193 mws int raw_err = err; 94 0 stevel nvlist_t *nvl; 95 0 stevel fmd_event_t *e; 96 0 stevel char *class, *msg; 97 0 stevel size_t len1, len2; 98 0 stevel char c; 99 0 stevel 100 0 stevel /* 101 0 stevel * fmd_api_vxerror() counts as both an error of class EFMD_MODULE 102 0 stevel * as well as an instance of 'err' w.r.t. our internal bean counters. 103 0 stevel */ 104 0 stevel (void) pthread_mutex_lock(&fmd.d_err_lock); 105 0 stevel fmd.d_errstats[EFMD_MODULE - EFMD_UNKNOWN].fmds_value.ui64++; 106 0 stevel 107 0 stevel if (err > EFMD_UNKNOWN && err < EFMD_END) 108 0 stevel fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++; 109 0 stevel 110 0 stevel (void) pthread_mutex_unlock(&fmd.d_err_lock); 111 0 stevel 112 0 stevel /* 113 0 stevel * Format the message using vsnprintf(). As usual, if the format has a 114 0 stevel * newline in it, it is printed alone; otherwise strerror() is added. 115 0 stevel */ 116 0 stevel if (strchr(format, '\n') != NULL) 117 0 stevel err = 0; /* err is not relevant in the message */ 118 0 stevel 119 0 stevel len1 = vsnprintf(&c, 1, format, ap); 120 0 stevel len2 = err != 0 ? snprintf(&c, 1, ": %s\n", fmd_strerror(err)) : 0; 121 0 stevel 122 0 stevel msg = fmd_alloc(len1 + len2 + 1, FMD_SLEEP); 123 0 stevel (void) vsnprintf(msg, len1 + 1, format, ap); 124 0 stevel 125 0 stevel if (err != 0) { 126 0 stevel (void) snprintf(&msg[len1], len2 + 1, 127 0 stevel ": %s\n", fmd_strerror(err)); 128 0 stevel } 129 0 stevel 130 0 stevel /* 131 0 stevel * Create an error event corresponding to the error, insert it into the 132 0 stevel * error log, and dispatch it to the fmd-self-diagnosis engine. 133 0 stevel */ 134 1193 mws if (mp != fmd.d_self && (raw_err != EFMD_HDL_ABORT || fmd.d_running)) { 135 0 stevel if ((c = msg[len1 + len2 - 1]) == '\n') 136 0 stevel msg[len1 + len2 - 1] = '\0'; /* strip \n for event */ 137 0 stevel 138 0 stevel nvl = fmd_protocol_moderror(mp, err, msg); 139 0 stevel 140 0 stevel if (c == '\n') 141 0 stevel msg[len1 + len2 - 1] = c; 142 0 stevel 143 0 stevel (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 144 0 stevel e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 145 0 stevel 146 0 stevel (void) pthread_rwlock_rdlock(&fmd.d_log_lock); 147 0 stevel fmd_log_append(fmd.d_errlog, e, NULL); 148 0 stevel (void) pthread_rwlock_unlock(&fmd.d_log_lock); 149 0 stevel 150 0 stevel fmd_event_transition(e, FMD_EVS_ACCEPTED); 151 0 stevel fmd_event_commit(e); 152 0 stevel 153 0 stevel fmd_dispq_dispatch(fmd.d_disp, e, class); 154 0 stevel } 155 0 stevel 156 0 stevel /* 157 0 stevel * Similar to fmd_vdebug(), if the debugging switches are enabled we 158 0 stevel * echo the module name and message to stderr and/or syslog. Unlike 159 0 stevel * fmd_vdebug(), we also print to stderr if foreground mode is enabled. 160 1193 mws * We also print the message if a built-in module is aborting before 161 1193 mws * fmd has detached from its parent (e.g. default transport failure). 162 0 stevel */ 163 1193 mws if (fmd.d_fg || (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) || ( 164 1193 mws raw_err == EFMD_HDL_ABORT && !fmd.d_running)) { 165 0 stevel (void) pthread_mutex_lock(&fmd.d_err_lock); 166 0 stevel (void) fprintf(stderr, "%s: %s: %s", 167 0 stevel fmd.d_pname, mp->mod_name, msg); 168 0 stevel (void) pthread_mutex_unlock(&fmd.d_err_lock); 169 0 stevel } 170 0 stevel 171 0 stevel if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 172 0 stevel syslog(LOG_ERR | LOG_DAEMON, "%s ERROR: %s: %s", 173 0 stevel fmd.d_pname, mp->mod_name, msg); 174 0 stevel } 175 0 stevel 176 0 stevel fmd_free(msg, len1 + len2 + 1); 177 0 stevel } 178 0 stevel 179 0 stevel /*PRINTFLIKE3*/ 180 0 stevel static void 181 0 stevel fmd_api_xerror(fmd_module_t *mp, int err, const char *format, ...) 182 0 stevel { 183 0 stevel va_list ap; 184 0 stevel 185 0 stevel va_start(ap, format); 186 0 stevel fmd_api_vxerror(mp, err, format, ap); 187 0 stevel va_end(ap); 188 0 stevel } 189 0 stevel 190 0 stevel /* 191 0 stevel * fmd_api_verror() is a wrapper around fmd_api_vxerror() for API subroutines. 192 0 stevel * It calls fmd_module_unlock() on behalf of its caller, logs the error, and 193 0 stevel * then aborts the API call and the surrounding module entry point by doing an 194 0 stevel * fmd_module_abort(), which longjmps to the place where we entered the module. 195 0 stevel */ 196 0 stevel static void 197 0 stevel fmd_api_verror(fmd_module_t *mp, int err, const char *format, va_list ap) 198 0 stevel { 199 0 stevel if (fmd_module_locked(mp)) 200 0 stevel fmd_module_unlock(mp); 201 0 stevel 202 0 stevel fmd_api_vxerror(mp, err, format, ap); 203 0 stevel fmd_module_abort(mp, err); 204 0 stevel } 205 0 stevel 206 0 stevel /*PRINTFLIKE3*/ 207 0 stevel static void 208 0 stevel fmd_api_error(fmd_module_t *mp, int err, const char *format, ...) 209 0 stevel { 210 0 stevel va_list ap; 211 0 stevel 212 0 stevel va_start(ap, format); 213 0 stevel fmd_api_verror(mp, err, format, ap); 214 0 stevel va_end(ap); 215 0 stevel } 216 0 stevel 217 0 stevel /* 218 1193 mws * Common code for fmd_api_module_lock() and fmd_api_transport_impl(). This 219 1193 mws * code verifies that the handle is valid and associated with a proper thread. 220 0 stevel */ 221 0 stevel static fmd_module_t * 222 1193 mws fmd_api_module(fmd_hdl_t *hdl) 223 0 stevel { 224 0 stevel fmd_thread_t *tp; 225 0 stevel fmd_module_t *mp; 226 0 stevel 227 0 stevel /* 228 0 stevel * If our TSD is not present at all, this is either a serious bug or 229 0 stevel * someone has created a thread behind our back and is using fmd's API. 230 0 stevel * We can't call fmd_api_error() because we can't be sure that we can 231 0 stevel * unwind our state back to an enclosing fmd_module_dispatch(), so we 232 0 stevel * must panic instead. This is likely a module design or coding error. 233 0 stevel */ 234 0 stevel if ((tp = pthread_getspecific(fmd.d_key)) == NULL) { 235 0 stevel fmd_panic("fmd module api call made using " 236 0 stevel "client handle %p from unknown thread\n", (void *)hdl); 237 0 stevel } 238 0 stevel 239 1193 mws /* 240 1193 mws * If our TSD refers to the root module and is a door server thread, 241 1193 mws * then it was created asynchronously at the request of a module but 242 1193 mws * is using now the module API as an auxiliary module thread. We reset 243 1193 mws * tp->thr_mod to the module handle so it can act as a module thread. 244 1193 mws */ 245 1193 mws if (tp->thr_mod == fmd.d_rmod && tp->thr_func == &fmd_door_server) 246 1193 mws tp->thr_mod = (fmd_module_t *)hdl; 247 1193 mws 248 0 stevel if ((mp = tp->thr_mod) != (fmd_module_t *)hdl) { 249 0 stevel fmd_api_error(mp, EFMD_HDL_INVAL, 250 0 stevel "client handle %p is not valid\n", (void *)hdl); 251 0 stevel } 252 0 stevel 253 0 stevel if (mp->mod_flags & FMD_MOD_FAIL) { 254 0 stevel fmd_api_error(mp, EFMD_MOD_FAIL, 255 0 stevel "module has experienced an unrecoverable error\n"); 256 0 stevel } 257 1193 mws 258 1193 mws return (mp); 259 1193 mws } 260 1193 mws 261 1193 mws /* 262 1193 mws * fmd_api_module_lock() is used as a wrapper around fmd_module_lock() and a 263 1193 mws * common prologue to each fmd_api.c routine. It verifies that the handle is 264 1193 mws * valid and owned by the current server thread, locks the handle, and then 265 1193 mws * verifies that the caller is performing an operation on a registered handle. 266 1193 mws * If any tests fail, the entire API call is aborted by fmd_api_error(). 267 1193 mws */ 268 1193 mws static fmd_module_t * 269 1193 mws fmd_api_module_lock(fmd_hdl_t *hdl) 270 1193 mws { 271 1193 mws fmd_module_t *mp = fmd_api_module(hdl); 272 0 stevel 273 0 stevel fmd_module_lock(mp); 274 0 stevel 275 0 stevel if (mp->mod_info == NULL) { 276 0 stevel fmd_api_error(mp, EFMD_HDL_NOTREG, 277 0 stevel "client handle %p has not been registered\n", (void *)hdl); 278 0 stevel } 279 0 stevel 280 0 stevel return (mp); 281 0 stevel } 282 0 stevel 283 0 stevel /* 284 0 stevel * Utility function for API entry points that accept fmd_case_t's. We cast cp 285 0 stevel * to fmd_case_impl_t and check to make sure the case is owned by the caller. 286 0 stevel */ 287 0 stevel static fmd_case_impl_t * 288 0 stevel fmd_api_case_impl(fmd_module_t *mp, fmd_case_t *cp) 289 0 stevel { 290 0 stevel fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 291 0 stevel 292 0 stevel if (cip == NULL || cip->ci_mod != mp) { 293 0 stevel fmd_api_error(mp, EFMD_CASE_OWNER, 294 1193 mws "case %p is invalid or not owned by caller\n", (void *)cip); 295 0 stevel } 296 0 stevel 297 0 stevel return (cip); 298 1193 mws } 299 1193 mws 300 1193 mws /* 301 1193 mws * Utility function for API entry points that accept fmd_xprt_t's. We cast xp 302 1193 mws * to fmd_transport_t and check to make sure the case is owned by the caller. 303 1193 mws * Note that we could make this check safer by actually walking mp's transport 304 1193 mws * list, but that requires holding the module lock and this routine needs to be 305 1193 mws * MT-hot w.r.t. auxiliary module threads. Ultimately any loadable module can 306 1193 mws * cause us to crash anyway, so we optimize for scalability over safety here. 307 1193 mws */ 308 1193 mws static fmd_xprt_impl_t * 309 1193 mws fmd_api_transport_impl(fmd_hdl_t *hdl, fmd_xprt_t *xp) 310 1193 mws { 311 1193 mws fmd_module_t *mp = fmd_api_module(hdl); 312 1193 mws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 313 1193 mws 314 1193 mws if (xip == NULL || xip->xi_queue->eq_mod != mp) { 315 1193 mws fmd_api_error(mp, EFMD_XPRT_OWNER, 316 1193 mws "xprt %p is invalid or not owned by caller\n", (void *)xp); 317 1193 mws } 318 1193 mws 319 1193 mws return (xip); 320 0 stevel } 321 0 stevel 322 0 stevel /* 323 0 stevel * fmd_hdl_register() is the one function which cannot use fmd_api_error() to 324 0 stevel * report errors, because that routine causes the module to abort. Failure to 325 0 stevel * register is instead handled by having fmd_hdl_register() return an error to 326 0 stevel * the _fmd_init() function and then detecting no registration when it returns. 327 0 stevel * So we use this routine for fmd_hdl_register() error paths instead. 328 0 stevel */ 329 0 stevel static int 330 0 stevel fmd_hdl_register_error(fmd_module_t *mp, int err) 331 0 stevel { 332 0 stevel if (fmd_module_locked(mp)) 333 0 stevel fmd_module_unlock(mp); 334 0 stevel 335 0 stevel fmd_api_xerror(mp, err, "failed to register"); 336 0 stevel return (fmd_set_errno(err)); 337 0 stevel } 338 0 stevel 339 0 stevel static void 340 0 stevel fmd_hdl_nop(void) 341 0 stevel { 342 0 stevel /* empty function for use with unspecified module entry points */ 343 0 stevel } 344 0 stevel 345 0 stevel int 346 0 stevel fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip) 347 0 stevel { 348 0 stevel fmd_thread_t *tp = pthread_getspecific(fmd.d_key); 349 0 stevel fmd_module_t *mp = tp->thr_mod; 350 0 stevel 351 0 stevel const fmd_prop_t *prop; 352 0 stevel const fmd_conf_path_t *pap; 353 0 stevel fmd_conf_formal_t *cfp; 354 1193 mws fmd_hdl_ops_t ops; 355 0 stevel 356 0 stevel const char *conf = NULL; 357 0 stevel char buf[PATH_MAX]; 358 0 stevel int i; 359 0 stevel 360 0 stevel if (mp != (fmd_module_t *)hdl) 361 0 stevel return (fmd_hdl_register_error(mp, EFMD_HDL_INVAL)); 362 0 stevel 363 0 stevel fmd_module_lock(mp); 364 0 stevel 365 0 stevel /* 366 0 stevel * First perform some sanity checks on our input. The API version must 367 0 stevel * be supported by FMD and the handle can only be registered once by 368 0 stevel * the module thread to which we assigned this client handle. The info 369 0 stevel * provided for the handle must be valid and have the minimal settings. 370 0 stevel */ 371 4198 eschrock if (version > FMD_API_VERSION_4) 372 0 stevel return (fmd_hdl_register_error(mp, EFMD_VER_NEW)); 373 0 stevel 374 0 stevel if (version < FMD_API_VERSION_1) 375 0 stevel return (fmd_hdl_register_error(mp, EFMD_VER_OLD)); 376 0 stevel 377 0 stevel if (mp->mod_conf != NULL) 378 0 stevel return (fmd_hdl_register_error(mp, EFMD_HDL_REG)); 379 0 stevel 380 0 stevel if (pthread_self() != mp->mod_thread->thr_tid) 381 0 stevel return (fmd_hdl_register_error(mp, EFMD_HDL_TID)); 382 0 stevel 383 1193 mws if (mip == NULL || mip->fmdi_desc == NULL || 384 1193 mws mip->fmdi_vers == NULL || mip->fmdi_ops == NULL) 385 0 stevel return (fmd_hdl_register_error(mp, EFMD_HDL_INFO)); 386 1193 mws 387 1193 mws /* 388 1193 mws * Copy the module's ops vector into a local variable to account for 389 1193 mws * changes in the module ABI. Then if any of the optional entry points 390 1193 mws * are NULL, set them to nop so we don't have to check before calling. 391 1193 mws */ 392 1193 mws bzero(&ops, sizeof (ops)); 393 1193 mws 394 1193 mws if (version < FMD_API_VERSION_3) 395 4198 eschrock bcopy(mip->fmdi_ops, &ops, offsetof(fmd_hdl_ops_t, fmdo_send)); 396 4198 eschrock else if (version < FMD_API_VERSION_4) 397 4198 eschrock bcopy(mip->fmdi_ops, &ops, 398 4198 eschrock offsetof(fmd_hdl_ops_t, fmdo_topo)); 399 1193 mws else 400 1193 mws bcopy(mip->fmdi_ops, &ops, sizeof (ops)); 401 1193 mws 402 1193 mws if (ops.fmdo_recv == NULL) 403 1193 mws ops.fmdo_recv = (void (*)())fmd_hdl_nop; 404 1193 mws if (ops.fmdo_timeout == NULL) 405 1193 mws ops.fmdo_timeout = (void (*)())fmd_hdl_nop; 406 1193 mws if (ops.fmdo_close == NULL) 407 1193 mws ops.fmdo_close = (void (*)())fmd_hdl_nop; 408 1193 mws if (ops.fmdo_stats == NULL) 409 1193 mws ops.fmdo_stats = (void (*)())fmd_hdl_nop; 410 1193 mws if (ops.fmdo_gc == NULL) 411 1193 mws ops.fmdo_gc = (void (*)())fmd_hdl_nop; 412 1193 mws if (ops.fmdo_send == NULL) 413 1193 mws ops.fmdo_send = (int (*)())fmd_hdl_nop; 414 4198 eschrock if (ops.fmdo_topo == NULL) 415 4198 eschrock ops.fmdo_topo = (void (*)())fmd_hdl_nop; 416 0 stevel 417 0 stevel /* 418 0 stevel * Make two passes through the property array to initialize the formals 419 0 stevel * to use for processing the module's .conf file. In the first pass, 420 0 stevel * we validate the types and count the number of properties. In the 421 0 stevel * second pass we copy the strings and fill in the appropriate ops. 422 0 stevel */ 423 0 stevel for (prop = mip->fmdi_props, i = 0; prop != NULL && 424 0 stevel prop->fmdp_name != NULL; prop++, i++) { 425 0 stevel if (prop->fmdp_type >= 426 0 stevel sizeof (_fmd_prop_ops) / sizeof (_fmd_prop_ops[0])) { 427 0 stevel fmd_api_xerror(mp, EFMD_HDL_PROP, 428 0 stevel "property %s uses invalid type %u\n", 429 0 stevel prop->fmdp_name, prop->fmdp_type); 430 0 stevel return (fmd_hdl_register_error(mp, EFMD_HDL_PROP)); 431 0 stevel } 432 0 stevel } 433 0 stevel 434 0 stevel mp->mod_argc = i; 435 0 stevel mp->mod_argv = fmd_zalloc(sizeof (fmd_conf_formal_t) * i, FMD_SLEEP); 436 0 stevel 437 0 stevel prop = mip->fmdi_props; 438 0 stevel cfp = mp->mod_argv; 439 0 stevel 440 0 stevel for (i = 0; i < mp->mod_argc; i++, prop++, cfp++) { 441 0 stevel cfp->cf_name = fmd_strdup(prop->fmdp_name, FMD_SLEEP); 442 0 stevel cfp->cf_ops = _fmd_prop_ops[prop->fmdp_type]; 443 0 stevel cfp->cf_default = fmd_strdup(prop->fmdp_defv, FMD_SLEEP); 444 0 stevel } 445 0 stevel 446 0 stevel /* 447 0 stevel * If this module came from an on-disk file, compute the name of the 448 0 stevel * corresponding .conf file and parse properties from it if it exists. 449 0 stevel */ 450 0 stevel if (mp->mod_path != NULL) { 451 0 stevel (void) strlcpy(buf, mp->mod_path, sizeof (buf)); 452 0 stevel (void) fmd_strdirname(buf); 453 0 stevel 454 0 stevel (void) strlcat(buf, "/", sizeof (buf)); 455 0 stevel (void) strlcat(buf, mp->mod_name, sizeof (buf)); 456 0 stevel (void) strlcat(buf, ".conf", sizeof (buf)); 457 0 stevel 458 0 stevel if (access(buf, F_OK) == 0) 459 0 stevel conf = buf; 460 0 stevel } 461 0 stevel 462 0 stevel if ((mp->mod_conf = fmd_conf_open(conf, 463 1193 mws mp->mod_argc, mp->mod_argv, 0)) == NULL) 464 0 stevel return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 465 1193 mws 466 1193 mws fmd_conf_propagate(fmd.d_conf, mp->mod_conf, mp->mod_name); 467 0 stevel 468 0 stevel /* 469 0 stevel * Look up the list of the libdiagcode dictionaries associated with the 470 0 stevel * module. If none were specified, use the value from daemon's config. 471 0 stevel * We only fail if the module specified an explicit dictionary. 472 0 stevel */ 473 0 stevel (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 474 0 stevel if (pap->cpa_argc == 0 && mp->mod_ops == &fmd_bltin_ops) 475 0 stevel (void) fmd_conf_getprop(fmd.d_conf, "self.dict", &pap); 476 0 stevel 477 0 stevel for (i = 0; i < pap->cpa_argc; i++) { 478 0 stevel if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 479 0 stevel fmd_api_xerror(mp, errno, 480 0 stevel "failed to open dictionary %s", pap->cpa_argv[i]); 481 0 stevel return (fmd_hdl_register_error(mp, EFMD_MOD_CONF)); 482 0 stevel } 483 0 stevel } 484 0 stevel 485 0 stevel /* 486 0 stevel * Make a copy of the handle information and store it in mod_info. We 487 0 stevel * do not need to bother copying fmdi_props since they're already read. 488 0 stevel */ 489 0 stevel mp->mod_info = fmd_alloc(sizeof (fmd_hdl_info_t), FMD_SLEEP); 490 0 stevel mp->mod_info->fmdi_desc = fmd_strdup(mip->fmdi_desc, FMD_SLEEP); 491 0 stevel mp->mod_info->fmdi_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP); 492 0 stevel mp->mod_info->fmdi_ops = fmd_alloc(sizeof (fmd_hdl_ops_t), FMD_SLEEP); 493 1193 mws bcopy(&ops, (void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t)); 494 0 stevel mp->mod_info->fmdi_props = NULL; 495 7139 cy152378 496 7139 cy152378 /* 497 7139 cy152378 * Store a copy of module version in mp for fmd_scheme_fmd_present() 498 7139 cy152378 */ 499 7139 cy152378 if (mp->mod_vers == NULL) 500 7139 cy152378 mp->mod_vers = fmd_strdup(mip->fmdi_vers, FMD_SLEEP); 501 0 stevel 502 0 stevel /* 503 0 stevel * Allocate an FMRI representing this module. We'll use this later 504 0 stevel * if the module decides to publish any events (e.g. list.suspects). 505 0 stevel */ 506 0 stevel mp->mod_fmri = fmd_protocol_fmri_module(mp); 507 0 stevel 508 0 stevel /* 509 0 stevel * Any subscriptions specified in the conf file are now stored in the 510 0 stevel * corresponding property. Add all of these to the dispatch queue. 511 0 stevel */ 512 0 stevel (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 513 0 stevel 514 1193 mws for (i = 0; i < pap->cpa_argc; i++) { 515 1193 mws fmd_dispq_insert(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]); 516 1193 mws fmd_xprt_subscribe_all(pap->cpa_argv[i]); 517 1193 mws } 518 0 stevel 519 0 stevel /* 520 0 stevel * Unlock the module and restore any pre-existing module checkpoint. 521 0 stevel * If the checkpoint is missing or corrupt, we just keep going. 522 0 stevel */ 523 0 stevel fmd_module_unlock(mp); 524 0 stevel fmd_ckpt_restore(mp); 525 0 stevel return (0); 526 0 stevel } 527 0 stevel 528 1193 mws /* 529 1193 mws * If an auxiliary thread exists for the specified module at unregistration 530 1193 mws * time, send it an asynchronous cancellation to force it to exit and then 531 1193 mws * join with it (we expect this to either succeed quickly or return ESRCH). 532 1193 mws * Once this is complete we can destroy the associated fmd_thread_t data. 533 1193 mws */ 534 1193 mws static void 535 1193 mws fmd_module_thrcancel(fmd_idspace_t *ids, id_t id, fmd_module_t *mp) 536 1193 mws { 537 1193 mws fmd_thread_t *tp = fmd_idspace_getspecific(ids, id); 538 1193 mws 539 1193 mws fmd_dprintf(FMD_DBG_MOD, "cancelling %s auxiliary thread %u\n", 540 1193 mws mp->mod_name, tp->thr_tid); 541 1193 mws 542 1193 mws ASSERT(tp->thr_tid == id); 543 1193 mws (void) pthread_cancel(tp->thr_tid); 544 1193 mws (void) pthread_join(tp->thr_tid, NULL); 545 1193 mws 546 1193 mws fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); 547 1193 mws } 548 1193 mws 549 0 stevel void 550 0 stevel fmd_module_unregister(fmd_module_t *mp) 551 0 stevel { 552 0 stevel fmd_conf_formal_t *cfp = mp->mod_argv; 553 0 stevel const fmd_conf_path_t *pap; 554 1193 mws fmd_case_t *cp; 555 1193 mws fmd_xprt_t *xp; 556 0 stevel int i; 557 0 stevel 558 0 stevel TRACE((FMD_DBG_MOD, "unregister %p (%s)", (void *)mp, mp->mod_name)); 559 0 stevel ASSERT(fmd_module_locked(mp)); 560 0 stevel 561 1193 mws /* 562 1193 mws * If any transports are still open, they have send threads that are 563 1193 mws * using the module handle: shut them down and join with these threads. 564 1193 mws */ 565 1193 mws while ((xp = fmd_list_next(&mp->mod_transports)) != NULL) 566 1193 mws fmd_xprt_destroy(xp); 567 1193 mws 568 1193 mws /* 569 1193 mws * If any auxiliary threads exist, they may be using our module handle, 570 1193 mws * and therefore could cause a fault as soon as we start destroying it. 571 1193 mws * Module writers should clean up any threads before unregistering: we 572 1193 mws * forcibly cancel any remaining auxiliary threads before proceeding. 573 1193 mws */ 574 1193 mws fmd_idspace_apply(mp->mod_threads, 575 1193 mws (void (*)())fmd_module_thrcancel, mp); 576 1193 mws 577 1283 ayznaga if (mp->mod_error == 0) 578 1283 ayznaga fmd_ckpt_save(mp); /* take one more checkpoint if needed */ 579 1283 ayznaga 580 1193 mws /* 581 1193 mws * Delete any cases associated with the module (UNSOLVED, SOLVED, or 582 1193 mws * CLOSE_WAIT) as if fmdo_close() has finished processing them. 583 1193 mws */ 584 1193 mws while ((cp = fmd_list_next(&mp->mod_cases)) != NULL) 585 1193 mws fmd_case_delete(cp); 586 0 stevel 587 1193 mws fmd_ustat_delete_references(mp->mod_ustat); 588 0 stevel (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_SUBSCRIPTIONS, &pap); 589 0 stevel 590 1193 mws for (i = 0; i < pap->cpa_argc; i++) { 591 1193 mws fmd_xprt_unsubscribe_all(pap->cpa_argv[i]); 592 1193 mws fmd_dispq_delete(fmd.d_disp, mp->mod_queue, pap->cpa_argv[i]); 593 0 stevel } 594 0 stevel 595 0 stevel fmd_conf_close(mp->mod_conf); 596 0 stevel mp->mod_conf = NULL; 597 0 stevel 598 0 stevel for (i = 0; i < mp->mod_argc; i++, cfp++) { 599 0 stevel fmd_strfree((char *)cfp->cf_name); 600 0 stevel fmd_strfree((char *)cfp->cf_default); 601 0 stevel } 602 0 stevel 603 0 stevel fmd_free(mp->mod_argv, sizeof (fmd_conf_formal_t) * mp->mod_argc); 604 0 stevel mp->mod_argv = NULL; 605 0 stevel mp->mod_argc = 0; 606 0 stevel 607 0 stevel nvlist_free(mp->mod_fmri); 608 0 stevel mp->mod_fmri = NULL; 609 0 stevel 610 0 stevel fmd_strfree((char *)mp->mod_info->fmdi_desc); 611 0 stevel fmd_strfree((char *)mp->mod_info->fmdi_vers); 612 0 stevel fmd_free((void *)mp->mod_info->fmdi_ops, sizeof (fmd_hdl_ops_t)); 613 0 stevel fmd_free(mp->mod_info, sizeof (fmd_hdl_info_t)); 614 0 stevel mp->mod_info = NULL; 615 0 stevel 616 0 stevel fmd_eventq_abort(mp->mod_queue); 617 0 stevel } 618 0 stevel 619 0 stevel void 620 0 stevel fmd_hdl_unregister(fmd_hdl_t *hdl) 621 0 stevel { 622 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 623 0 stevel fmd_module_unregister(mp); 624 0 stevel fmd_module_unlock(mp); 625 0 stevel } 626 0 stevel 627 0 stevel void 628 0 stevel fmd_hdl_subscribe(fmd_hdl_t *hdl, const char *class) 629 0 stevel { 630 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 631 0 stevel 632 1193 mws if (fmd_conf_setprop(mp->mod_conf, 633 1193 mws FMD_PROP_SUBSCRIPTIONS, class) == 0) { 634 1193 mws fmd_dispq_insert(fmd.d_disp, mp->mod_queue, class); 635 1193 mws fmd_xprt_subscribe_all(class); 636 1193 mws } 637 0 stevel 638 0 stevel fmd_module_unlock(mp); 639 0 stevel } 640 1193 mws 641 0 stevel 642 0 stevel void 643 0 stevel fmd_hdl_unsubscribe(fmd_hdl_t *hdl, const char *class) 644 0 stevel { 645 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 646 0 stevel 647 1193 mws if (fmd_conf_delprop(mp->mod_conf, 648 1193 mws FMD_PROP_SUBSCRIPTIONS, class) == 0) { 649 1193 mws fmd_xprt_unsubscribe_all(class); 650 1193 mws fmd_dispq_delete(fmd.d_disp, mp->mod_queue, class); 651 1193 mws } 652 0 stevel 653 0 stevel fmd_module_unlock(mp); 654 0 stevel fmd_eventq_cancel(mp->mod_queue, FMD_EVT_PROTOCOL, (void *)class); 655 0 stevel } 656 0 stevel 657 0 stevel void 658 0 stevel fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec) 659 0 stevel { 660 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 661 0 stevel 662 0 stevel mp->mod_spec = spec; 663 0 stevel fmd_module_unlock(mp); 664 0 stevel } 665 0 stevel 666 0 stevel void * 667 0 stevel fmd_hdl_getspecific(fmd_hdl_t *hdl) 668 0 stevel { 669 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 670 0 stevel void *spec = mp->mod_spec; 671 0 stevel 672 0 stevel fmd_module_unlock(mp); 673 0 stevel return (spec); 674 0 stevel } 675 0 stevel 676 0 stevel void 677 0 stevel fmd_hdl_opendict(fmd_hdl_t *hdl, const char *dict) 678 0 stevel { 679 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 680 0 stevel const fmd_conf_path_t *pap; 681 0 stevel int i; 682 0 stevel 683 0 stevel /* 684 0 stevel * Update the dictionary property in order to preserve the list of 685 0 stevel * pathnames and expand any % tokens in the path. Then retrieve the 686 0 stevel * new dictionary names from cpa_argv[] and open them one at a time. 687 0 stevel */ 688 0 stevel (void) fmd_conf_setprop(mp->mod_conf, FMD_PROP_DICTIONARIES, dict); 689 0 stevel (void) fmd_conf_getprop(mp->mod_conf, FMD_PROP_DICTIONARIES, &pap); 690 0 stevel 691 0 stevel ASSERT(pap->cpa_argc > mp->mod_dictc); 692 0 stevel 693 0 stevel for (i = mp->mod_dictc; i < pap->cpa_argc; i++) { 694 0 stevel if (fmd_module_dc_opendict(mp, pap->cpa_argv[i]) != 0) { 695 0 stevel fmd_api_error(mp, EFMD_MOD_DICT, 696 0 stevel "failed to open dictionary %s for module %s", 697 0 stevel pap->cpa_argv[i], mp->mod_name); 698 0 stevel } 699 0 stevel } 700 0 stevel 701 0 stevel fmd_module_unlock(mp); 702 0 stevel } 703 0 stevel 704 1414 cindi topo_hdl_t * 705 4198 eschrock fmd_hdl_topo_hold(fmd_hdl_t *hdl, int v) 706 1414 cindi { 707 1414 cindi fmd_module_t *mp = fmd_api_module_lock(hdl); 708 1414 cindi topo_hdl_t *thp; 709 1414 cindi 710 1414 cindi if (v != TOPO_VERSION) { 711 1414 cindi fmd_api_error(mp, EFMD_MOD_TOPO, "libtopo version mismatch: " 712 1414 cindi "fmd version %d != client version %d\n", TOPO_VERSION, v); 713 1414 cindi } 714 1414 cindi 715 4198 eschrock thp = fmd_module_topo_hold(mp); 716 4198 eschrock ASSERT(thp != NULL); 717 3062 cindi 718 1414 cindi fmd_module_unlock(mp); 719 1414 cindi return (thp); 720 4198 eschrock } 721 4198 eschrock 722 4198 eschrock void 723 4198 eschrock fmd_hdl_topo_rele(fmd_hdl_t *hdl, topo_hdl_t *thp) 724 4198 eschrock { 725 4198 eschrock fmd_module_t *mp = fmd_api_module_lock(hdl); 726 4198 eschrock 727 4198 eschrock if (fmd_module_topo_rele(mp, thp) != 0) 728 4198 eschrock fmd_api_error(mp, EFMD_MOD_TOPO, "failed to release invalid " 729 4198 eschrock "topo handle: %p\n", (void *)thp); 730 4198 eschrock 731 4198 eschrock fmd_module_unlock(mp); 732 1414 cindi } 733 1414 cindi 734 7171 eschrock static void * 735 7171 eschrock fmd_hdl_alloc_locked(fmd_module_t *mp, size_t size, int flags) 736 0 stevel { 737 0 stevel void *data; 738 0 stevel 739 0 stevel if (mp->mod_stats->ms_memlimit.fmds_value.ui64 - 740 0 stevel mp->mod_stats->ms_memtotal.fmds_value.ui64 < size) { 741 0 stevel fmd_api_error(mp, EFMD_HDL_NOMEM, "%s's allocation of %lu " 742 0 stevel "bytes exceeds module memory limit (%llu)\n", 743 0 stevel mp->mod_name, (ulong_t)size, (u_longlong_t) 744 0 stevel mp->mod_stats->ms_memtotal.fmds_value.ui64); 745 0 stevel } 746 0 stevel 747 0 stevel if ((data = fmd_alloc(size, flags)) != NULL) 748 0 stevel mp->mod_stats->ms_memtotal.fmds_value.ui64 += size; 749 7171 eschrock 750 7171 eschrock return (data); 751 7171 eschrock } 752 7171 eschrock 753 7171 eschrock void * 754 7171 eschrock fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags) 755 7171 eschrock { 756 7171 eschrock fmd_module_t *mp = fmd_api_module_lock(hdl); 757 7171 eschrock void *data; 758 7171 eschrock 759 7171 eschrock data = fmd_hdl_alloc_locked(mp, size, flags); 760 0 stevel 761 0 stevel fmd_module_unlock(mp); 762 0 stevel return (data); 763 0 stevel } 764 0 stevel 765 0 stevel void * 766 0 stevel fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags) 767 0 stevel { 768 0 stevel void *data = fmd_hdl_alloc(hdl, size, flags); 769 0 stevel 770 0 stevel if (data != NULL) 771 0 stevel bzero(data, size); 772 0 stevel 773 0 stevel return (data); 774 0 stevel } 775 0 stevel 776 7171 eschrock static void 777 7171 eschrock fmd_hdl_free_locked(fmd_module_t *mp, void *data, size_t size) 778 7171 eschrock { 779 7171 eschrock fmd_free(data, size); 780 7171 eschrock mp->mod_stats->ms_memtotal.fmds_value.ui64 -= size; 781 7171 eschrock } 782 7171 eschrock 783 0 stevel void 784 0 stevel fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size) 785 0 stevel { 786 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 787 0 stevel 788 7171 eschrock fmd_hdl_free_locked(mp, data, size); 789 0 stevel 790 0 stevel fmd_module_unlock(mp); 791 0 stevel } 792 0 stevel 793 0 stevel char * 794 0 stevel fmd_hdl_strdup(fmd_hdl_t *hdl, const char *s, int flags) 795 0 stevel { 796 0 stevel char *p; 797 0 stevel 798 0 stevel if (s != NULL) 799 0 stevel p = fmd_hdl_alloc(hdl, strlen(s) + 1, flags); 800 0 stevel else 801 0 stevel p = NULL; 802 0 stevel 803 0 stevel if (p != NULL) 804 0 stevel (void) strcpy(p, s); 805 0 stevel 806 0 stevel return (p); 807 0 stevel } 808 0 stevel 809 0 stevel void 810 0 stevel fmd_hdl_strfree(fmd_hdl_t *hdl, char *s) 811 0 stevel { 812 0 stevel if (s != NULL) 813 0 stevel fmd_hdl_free(hdl, s, strlen(s) + 1); 814 0 stevel } 815 0 stevel 816 0 stevel void 817 0 stevel fmd_hdl_vabort(fmd_hdl_t *hdl, const char *format, va_list ap) 818 0 stevel { 819 0 stevel fmd_api_verror(fmd_api_module_lock(hdl), EFMD_HDL_ABORT, format, ap); 820 0 stevel } 821 0 stevel 822 0 stevel /*PRINTFLIKE2*/ 823 0 stevel void 824 0 stevel fmd_hdl_abort(fmd_hdl_t *hdl, const char *format, ...) 825 0 stevel { 826 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 827 0 stevel va_list ap; 828 0 stevel 829 0 stevel va_start(ap, format); 830 0 stevel fmd_api_verror(mp, EFMD_HDL_ABORT, format, ap); 831 0 stevel va_end(ap); 832 0 stevel } 833 0 stevel 834 0 stevel void 835 0 stevel fmd_hdl_verror(fmd_hdl_t *hdl, const char *format, va_list ap) 836 0 stevel { 837 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 838 0 stevel fmd_api_vxerror(mp, errno, format, ap); 839 0 stevel fmd_module_unlock(mp); 840 0 stevel } 841 0 stevel 842 0 stevel /*PRINTFLIKE2*/ 843 0 stevel void 844 0 stevel fmd_hdl_error(fmd_hdl_t *hdl, const char *format, ...) 845 0 stevel { 846 0 stevel va_list ap; 847 0 stevel 848 0 stevel va_start(ap, format); 849 0 stevel fmd_hdl_verror(hdl, format, ap); 850 0 stevel va_end(ap); 851 0 stevel } 852 0 stevel 853 0 stevel void 854 0 stevel fmd_hdl_vdebug(fmd_hdl_t *hdl, const char *format, va_list ap) 855 0 stevel { 856 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 857 0 stevel 858 0 stevel char *msg; 859 0 stevel size_t len; 860 0 stevel char c; 861 0 stevel 862 0 stevel if (!(fmd.d_hdl_debug)) { 863 0 stevel mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 864 0 stevel fmd_module_unlock(mp); 865 0 stevel return; 866 0 stevel } 867 0 stevel 868 0 stevel len = vsnprintf(&c, 1, format, ap); 869 0 stevel 870 0 stevel if ((msg = fmd_alloc(len + 2, FMD_NOSLEEP)) == NULL) { 871 0 stevel mp->mod_stats->ms_debugdrop.fmds_value.ui64++; 872 0 stevel fmd_module_unlock(mp); 873 0 stevel return; 874 0 stevel } 875 0 stevel 876 0 stevel (void) vsnprintf(msg, len + 1, format, ap); 877 0 stevel 878 0 stevel if (msg[len - 1] != '\n') 879 0 stevel (void) strcpy(&msg[len], "\n"); 880 0 stevel 881 0 stevel if (fmd.d_hdl_dbout & FMD_DBOUT_STDERR) { 882 0 stevel (void) pthread_mutex_lock(&fmd.d_err_lock); 883 0 stevel (void) fprintf(stderr, "%s DEBUG: %s: %s", 884 0 stevel fmd.d_pname, mp->mod_name, msg); 885 0 stevel (void) pthread_mutex_unlock(&fmd.d_err_lock); 886 0 stevel } 887 0 stevel 888 0 stevel if (fmd.d_hdl_dbout & FMD_DBOUT_SYSLOG) { 889 0 stevel syslog(LOG_DEBUG | LOG_DAEMON, "%s DEBUG: %s: %s", 890 0 stevel fmd.d_pname, mp->mod_name, msg); 891 0 stevel } 892 0 stevel 893 0 stevel fmd_free(msg, len + 2); 894 0 stevel fmd_module_unlock(mp); 895 0 stevel } 896 0 stevel 897 0 stevel /*PRINTFLIKE2*/ 898 0 stevel void 899 0 stevel fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...) 900 0 stevel { 901 0 stevel va_list ap; 902 0 stevel 903 0 stevel va_start(ap, format); 904 0 stevel fmd_hdl_vdebug(hdl, format, ap); 905 0 stevel va_end(ap); 906 0 stevel } 907 0 stevel 908 0 stevel int32_t 909 0 stevel fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name) 910 0 stevel { 911 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 912 0 stevel const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 913 0 stevel int32_t value = 0; 914 0 stevel 915 0 stevel if (ops == &fmd_conf_bool || ops == &fmd_conf_int32 || 916 0 stevel ops == &fmd_conf_uint32) 917 0 stevel (void) fmd_conf_getprop(mp->mod_conf, name, &value); 918 0 stevel else if (ops != NULL) { 919 0 stevel fmd_api_error(mp, EFMD_PROP_TYPE, 920 0 stevel "property %s is not of int32 type\n", name); 921 0 stevel } else { 922 0 stevel fmd_api_error(mp, EFMD_PROP_DEFN, 923 0 stevel "property %s is not defined\n", name); 924 0 stevel } 925 0 stevel 926 0 stevel fmd_module_unlock(mp); 927 0 stevel return (value); 928 0 stevel } 929 0 stevel 930 0 stevel int64_t 931 0 stevel fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name) 932 0 stevel { 933 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 934 0 stevel const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 935 0 stevel int64_t value = 0; 936 0 stevel 937 0 stevel if (ops == &fmd_conf_int64 || ops == &fmd_conf_uint64 || 938 0 stevel ops == &fmd_conf_time || ops == &fmd_conf_size) 939 0 stevel (void) fmd_conf_getprop(mp->mod_conf, name, &value); 940 0 stevel else if (ops != NULL) { 941 0 stevel fmd_api_error(mp, EFMD_PROP_TYPE, 942 0 stevel "property %s is not of int64 type\n", name); 943 0 stevel } else { 944 0 stevel fmd_api_error(mp, EFMD_PROP_DEFN, 945 0 stevel "property %s is not defined\n", name); 946 0 stevel } 947 0 stevel 948 0 stevel fmd_module_unlock(mp); 949 0 stevel return (value); 950 0 stevel } 951 0 stevel 952 0 stevel char * 953 0 stevel fmd_prop_get_string(fmd_hdl_t *hdl, const char *name) 954 0 stevel { 955 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 956 0 stevel const fmd_conf_ops_t *ops = fmd_conf_gettype(mp->mod_conf, name); 957 0 stevel char *value = NULL; 958 0 stevel const char *s; 959 0 stevel 960 0 stevel if (ops == &fmd_conf_string) { 961 0 stevel (void) fmd_conf_getprop(mp->mod_conf, name, &s); 962 0 stevel value = fmd_strdup(s, FMD_SLEEP); 963 0 stevel } else if (ops != NULL) { 964 0 stevel fmd_api_error(mp, EFMD_PROP_TYPE, 965 0 stevel "property %s is not of string type\n", name); 966 0 stevel } else { 967 0 stevel fmd_api_error(mp, EFMD_PROP_DEFN, 968 0 stevel "property %s is not defined\n", name); 969 0 stevel } 970 0 stevel 971 0 stevel fmd_module_unlock(mp); 972 0 stevel return (value); 973 0 stevel } 974 0 stevel 975 0 stevel void 976 0 stevel fmd_prop_free_string(fmd_hdl_t *hdl, char *s) 977 0 stevel { 978 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 979 0 stevel fmd_strfree(s); 980 0 stevel fmd_module_unlock(mp); 981 0 stevel } 982 0 stevel 983 0 stevel fmd_stat_t * 984 0 stevel fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t argc, fmd_stat_t *argv) 985 0 stevel { 986 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 987 0 stevel fmd_stat_t *ep, *sp; 988 0 stevel 989 0 stevel if (flags & ~FMD_STAT_ALLOC) { 990 0 stevel fmd_api_error(mp, EFMD_STAT_FLAGS, 991 0 stevel "invalid flags 0x%x passed to fmd_stat_create\n", flags); 992 0 stevel } 993 0 stevel 994 0 stevel if ((sp = fmd_ustat_insert(mp->mod_ustat, 995 0 stevel flags | FMD_USTAT_VALIDATE, argc, argv, &ep)) == NULL) { 996 0 stevel fmd_api_error(mp, errno, 997 0 stevel "failed to publish stat '%s'", ep->fmds_name); 998 0 stevel } 999 0 stevel 1000 0 stevel fmd_module_unlock(mp); 1001 0 stevel return (sp); 1002 0 stevel } 1003 0 stevel 1004 0 stevel void 1005 0 stevel fmd_stat_destroy(fmd_hdl_t *hdl, uint_t argc, fmd_stat_t *argv) 1006 0 stevel { 1007 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1008 0 stevel fmd_ustat_delete(mp->mod_ustat, argc, argv); 1009 0 stevel fmd_module_unlock(mp); 1010 0 stevel } 1011 0 stevel 1012 0 stevel void 1013 0 stevel fmd_stat_setstr(fmd_hdl_t *hdl, fmd_stat_t *sp, const char *s) 1014 0 stevel { 1015 0 stevel char *str = fmd_strdup(s, FMD_SLEEP); 1016 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1017 0 stevel 1018 0 stevel if (sp->fmds_type != FMD_TYPE_STRING) { 1019 0 stevel fmd_strfree(str); 1020 0 stevel fmd_api_error(mp, EFMD_STAT_TYPE, 1021 0 stevel "stat '%s' is not a string\n", sp->fmds_name); 1022 0 stevel } 1023 0 stevel 1024 0 stevel fmd_strfree(sp->fmds_value.str); 1025 0 stevel sp->fmds_value.str = str; 1026 0 stevel 1027 0 stevel fmd_module_unlock(mp); 1028 0 stevel } 1029 0 stevel 1030 0 stevel fmd_case_t * 1031 0 stevel fmd_case_open(fmd_hdl_t *hdl, void *data) 1032 0 stevel { 1033 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1034 0 stevel fmd_case_t *cp = fmd_case_create(mp, data); 1035 0 stevel fmd_module_unlock(mp); 1036 0 stevel return (cp); 1037 0 stevel } 1038 0 stevel 1039 0 stevel void 1040 0 stevel fmd_case_reset(fmd_hdl_t *hdl, fmd_case_t *cp) 1041 0 stevel { 1042 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1043 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1044 0 stevel 1045 0 stevel if (cip->ci_state >= FMD_CASE_SOLVED) { 1046 0 stevel fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 1047 0 stevel "case is already solved or closed\n", cip->ci_uuid); 1048 0 stevel } 1049 0 stevel 1050 0 stevel fmd_case_reset_suspects(cp); 1051 0 stevel fmd_module_unlock(mp); 1052 0 stevel } 1053 0 stevel 1054 0 stevel void 1055 0 stevel fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp) 1056 0 stevel { 1057 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1058 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1059 0 stevel 1060 0 stevel if (cip->ci_state >= FMD_CASE_SOLVED) { 1061 0 stevel fmd_api_error(mp, EFMD_CASE_STATE, "cannot solve %s: " 1062 0 stevel "case is already solved or closed\n", cip->ci_uuid); 1063 0 stevel } 1064 0 stevel 1065 1193 mws fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1066 0 stevel fmd_module_unlock(mp); 1067 0 stevel } 1068 0 stevel 1069 0 stevel void 1070 0 stevel fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp) 1071 0 stevel { 1072 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1073 0 stevel 1074 0 stevel (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1075 1193 mws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 1076 0 stevel 1077 0 stevel fmd_module_unlock(mp); 1078 0 stevel } 1079 0 stevel 1080 0 stevel const char * 1081 0 stevel fmd_case_uuid(fmd_hdl_t *hdl, fmd_case_t *cp) 1082 0 stevel { 1083 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1084 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1085 0 stevel const char *uuid = cip->ci_uuid; 1086 0 stevel 1087 0 stevel fmd_module_unlock(mp); 1088 0 stevel return (uuid); 1089 0 stevel } 1090 0 stevel 1091 0 stevel fmd_case_t * 1092 0 stevel fmd_case_uulookup(fmd_hdl_t *hdl, const char *uuid) 1093 0 stevel { 1094 0 stevel fmd_module_t *cmp, *mp = fmd_api_module_lock(hdl); 1095 0 stevel fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1096 0 stevel 1097 0 stevel if (cp != NULL) { 1098 0 stevel cmp = ((fmd_case_impl_t *)cp)->ci_mod; 1099 0 stevel fmd_case_rele(cp); 1100 0 stevel } else 1101 0 stevel cmp = NULL; 1102 0 stevel 1103 0 stevel fmd_module_unlock(mp); 1104 0 stevel return (cmp == mp ? cp : NULL); 1105 0 stevel } 1106 0 stevel 1107 0 stevel void 1108 0 stevel fmd_case_uuclose(fmd_hdl_t *hdl, const char *uuid) 1109 0 stevel { 1110 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1111 0 stevel fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1112 0 stevel 1113 1193 mws if (cp != NULL) { 1114 1193 mws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 1115 1193 mws fmd_case_rele(cp); 1116 1193 mws } 1117 0 stevel 1118 0 stevel fmd_module_unlock(mp); 1119 0 stevel } 1120 0 stevel 1121 0 stevel int 1122 0 stevel fmd_case_uuclosed(fmd_hdl_t *hdl, const char *uuid) 1123 0 stevel { 1124 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1125 0 stevel fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1126 0 stevel fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1127 0 stevel int rv = FMD_B_TRUE; 1128 0 stevel 1129 0 stevel if (cip != NULL) { 1130 1193 mws rv = cip->ci_state >= FMD_CASE_CLOSE_WAIT; 1131 0 stevel fmd_case_rele(cp); 1132 0 stevel } 1133 0 stevel 1134 0 stevel fmd_module_unlock(mp); 1135 0 stevel return (rv); 1136 7275 stephh } 1137 7275 stephh 1138 7275 stephh void 1139 7275 stephh fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid) 1140 7275 stephh { 1141 7275 stephh fmd_module_t *mp = fmd_api_module_lock(hdl); 1142 7275 stephh fmd_case_t *cp = fmd_case_hash_lookup(fmd.d_cases, uuid); 1143 7275 stephh 1144 7275 stephh if (cp != NULL) { 1145 9120 Stephen fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1146 9120 Stephen /* 1147 9120 Stephen * For a proxy, we notify the diagnosing side, and then 1148 9120 Stephen * wait for it to send us back a list.resolved. 1149 9120 Stephen */ 1150 9120 Stephen if (cip->ci_xprt != NULL) 1151 9120 Stephen fmd_xprt_uuresolved(cip->ci_xprt, cip->ci_uuid); 1152 9120 Stephen else 1153 9120 Stephen fmd_case_transition(cp, FMD_CASE_RESOLVED, 0); 1154 7275 stephh fmd_case_rele(cp); 1155 7275 stephh } 1156 7275 stephh 1157 7275 stephh fmd_module_unlock(mp); 1158 0 stevel } 1159 0 stevel 1160 0 stevel static int 1161 0 stevel fmd_case_instate(fmd_hdl_t *hdl, fmd_case_t *cp, uint_t state) 1162 0 stevel { 1163 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1164 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1165 0 stevel int rv = cip->ci_state >= state; 1166 0 stevel 1167 0 stevel fmd_module_unlock(mp); 1168 0 stevel return (rv); 1169 0 stevel } 1170 0 stevel 1171 0 stevel int 1172 0 stevel fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp) 1173 0 stevel { 1174 0 stevel return (fmd_case_instate(hdl, cp, FMD_CASE_SOLVED)); 1175 0 stevel } 1176 0 stevel 1177 0 stevel int 1178 0 stevel fmd_case_closed(fmd_hdl_t *hdl, fmd_case_t *cp) 1179 0 stevel { 1180 1193 mws return (fmd_case_instate(hdl, cp, FMD_CASE_CLOSE_WAIT)); 1181 0 stevel } 1182 0 stevel 1183 0 stevel void 1184 0 stevel fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 1185 0 stevel { 1186 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1187 0 stevel 1188 0 stevel (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1189 1414 cindi 1190 1414 cindi if (fmd_case_insert_event(cp, ep)) 1191 1414 cindi mp->mod_stats->ms_accepted.fmds_value.ui64++; 1192 0 stevel 1193 0 stevel fmd_module_unlock(mp); 1194 0 stevel } 1195 0 stevel 1196 0 stevel void 1197 0 stevel fmd_case_add_serd(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1198 0 stevel { 1199 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1200 0 stevel fmd_serd_elem_t *sep; 1201 0 stevel fmd_serd_eng_t *sgp; 1202 0 stevel 1203 0 stevel if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1204 0 stevel fmd_api_error(mp, EFMD_SERD_NAME, 1205 0 stevel "failed to add events from serd engine '%s'", name); 1206 0 stevel } 1207 0 stevel 1208 0 stevel (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1209 0 stevel 1210 0 stevel for (sep = fmd_list_next(&sgp->sg_list); 1211 1414 cindi sep != NULL; sep = fmd_list_next(sep)) { 1212 1414 cindi if (fmd_case_insert_event(cp, sep->se_event)) 1213 1414 cindi mp->mod_stats->ms_accepted.fmds_value.ui64++; 1214 1414 cindi } 1215 0 stevel 1216 0 stevel fmd_module_unlock(mp); 1217 0 stevel } 1218 0 stevel 1219 0 stevel void 1220 0 stevel fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *nvl) 1221 0 stevel { 1222 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1223 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1224 0 stevel char *class; 1225 7197 stephh topo_hdl_t *thp; 1226 7197 stephh int err; 1227 8245 Stephen nvlist_t *rsrc = NULL, *asru_prop = NULL, *asru = NULL, *fru = NULL; 1228 7197 stephh char *loc = NULL, *serial = NULL; 1229 0 stevel 1230 0 stevel if (cip->ci_state >= FMD_CASE_SOLVED) { 1231 0 stevel fmd_api_error(mp, EFMD_CASE_STATE, "cannot add suspect to " 1232 0 stevel "%s: case is already solved or closed\n", cip->ci_uuid); 1233 0 stevel } 1234 0 stevel 1235 0 stevel if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0 || 1236 0 stevel class == NULL || *class == '\0') { 1237 0 stevel fmd_api_error(mp, EFMD_CASE_EVENT, "cannot add suspect to " 1238 0 stevel "%s: suspect event is missing a class\n", cip->ci_uuid); 1239 0 stevel } 1240 7197 stephh 1241 7197 stephh thp = fmd_module_topo_hold(mp); 1242 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc); 1243 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru); 1244 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &fru); 1245 7197 stephh if (rsrc != NULL) { 1246 7197 stephh if (strncmp(class, "defect", 6) == 0) { 1247 7197 stephh if (asru == NULL && topo_fmri_getprop(thp, rsrc, 1248 7197 stephh TOPO_PGROUP_IO, TOPO_IO_MODULE, rsrc, 1249 8245 Stephen &asru_prop, &err) == 0 && 1250 8245 Stephen nvlist_lookup_nvlist(asru_prop, TOPO_PROP_VAL_VAL, 1251 8245 Stephen &asru) == 0) { 1252 7197 stephh (void) nvlist_add_nvlist(nvl, FM_FAULT_ASRU, 1253 7197 stephh asru); 1254 7197 stephh nvlist_free(asru); 1255 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, 1256 7197 stephh &asru); 1257 7197 stephh } 1258 7197 stephh } else { 1259 7197 stephh if (topo_fmri_asru(thp, rsrc, &asru, &err) == 0) { 1260 7197 stephh (void) nvlist_remove(nvl, FM_FAULT_ASRU, 1261 7197 stephh DATA_TYPE_NVLIST); 1262 7197 stephh (void) nvlist_add_nvlist(nvl, FM_FAULT_ASRU, 1263 7197 stephh asru); 1264 7197 stephh nvlist_free(asru); 1265 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, 1266 7197 stephh &asru); 1267 7197 stephh } 1268 7197 stephh if (topo_fmri_fru(thp, rsrc, &fru, &err) == 0) { 1269 7197 stephh (void) nvlist_remove(nvl, FM_FAULT_FRU, 1270 7197 stephh DATA_TYPE_NVLIST); 1271 7197 stephh (void) nvlist_add_nvlist(nvl, FM_FAULT_FRU, 1272 7197 stephh fru); 1273 7197 stephh nvlist_free(fru); 1274 7197 stephh (void) nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, 1275 7197 stephh &fru); 1276 7197 stephh } 1277 7197 stephh } 1278 7197 stephh } 1279 7197 stephh 1280 7197 stephh /* 1281 7197 stephh * Try to find the location label for this resource 1282 7197 stephh */ 1283 7197 stephh if (fru != NULL) 1284 7197 stephh (void) topo_fmri_label(thp, fru, &loc, &err); 1285 7197 stephh else if (rsrc != NULL) 1286 7197 stephh (void) topo_fmri_label(thp, rsrc, &loc, &err); 1287 8245 Stephen if (strncmp(class, "defect", 6) != 0 && loc != NULL) { 1288 7197 stephh (void) nvlist_remove(nvl, FM_FAULT_LOCATION, DATA_TYPE_STRING); 1289 7197 stephh (void) nvlist_add_string(nvl, FM_FAULT_LOCATION, loc); 1290 7197 stephh topo_hdl_strfree(thp, loc); 1291 7197 stephh } 1292 7197 stephh 1293 7197 stephh /* 1294 7197 stephh * In some cases, serial information for the resource will not be 1295 7197 stephh * available at enumeration but may instead be available by invoking 1296 7197 stephh * a dynamic property method on the FRU. In order to ensure the serial 1297 7197 stephh * number is persisted properly in the ASRU cache, we'll fetch the 1298 7197 stephh * property, if it exists, and add it to the resource and fru fmris. 1299 9761 Srihari * If the DE has not listed a fru in the suspect, see if we can 1300 9761 Srihari * retrieve the serial from the resource instead. 1301 7197 stephh */ 1302 7197 stephh if (fru != NULL) { 1303 7197 stephh (void) topo_fmri_serial(thp, fru, &serial, &err); 1304 7197 stephh if (serial != NULL) { 1305 7197 stephh (void) nvlist_add_string(fru, "serial", serial); 1306 7197 stephh topo_hdl_strfree(thp, serial); 1307 7197 stephh } 1308 7197 stephh } 1309 7197 stephh 1310 7197 stephh err = fmd_module_topo_rele(mp, thp); 1311 7197 stephh ASSERT(err == 0); 1312 0 stevel 1313 0 stevel fmd_case_insert_suspect(cp, nvl); 1314 0 stevel fmd_module_unlock(mp); 1315 0 stevel } 1316 0 stevel 1317 0 stevel void 1318 0 stevel fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data) 1319 0 stevel { 1320 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1321 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1322 0 stevel 1323 0 stevel (void) pthread_mutex_lock(&cip->ci_lock); 1324 0 stevel cip->ci_data = data; 1325 0 stevel (void) pthread_mutex_unlock(&cip->ci_lock); 1326 0 stevel 1327 0 stevel fmd_module_unlock(mp); 1328 0 stevel } 1329 0 stevel 1330 0 stevel void * 1331 0 stevel fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp) 1332 0 stevel { 1333 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1334 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1335 0 stevel void *data; 1336 0 stevel 1337 0 stevel (void) pthread_mutex_lock(&cip->ci_lock); 1338 0 stevel data = cip->ci_data; 1339 0 stevel (void) pthread_mutex_unlock(&cip->ci_lock); 1340 0 stevel 1341 0 stevel fmd_module_unlock(mp); 1342 0 stevel return (data); 1343 0 stevel } 1344 0 stevel 1345 0 stevel void 1346 0 stevel fmd_case_setprincipal(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep) 1347 0 stevel { 1348 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1349 0 stevel 1350 0 stevel (void) fmd_api_case_impl(mp, cp); /* validate 'cp' */ 1351 1414 cindi 1352 1414 cindi if (fmd_case_insert_principal(cp, ep)) 1353 1414 cindi mp->mod_stats->ms_accepted.fmds_value.ui64++; 1354 0 stevel 1355 0 stevel fmd_module_unlock(mp); 1356 0 stevel } 1357 0 stevel 1358 0 stevel fmd_event_t * 1359 0 stevel fmd_case_getprincipal(fmd_hdl_t *hdl, fmd_case_t *cp) 1360 0 stevel { 1361 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1362 0 stevel fmd_case_impl_t *cip = fmd_api_case_impl(mp, cp); 1363 0 stevel fmd_event_t *ep; 1364 0 stevel 1365 0 stevel (void) pthread_mutex_lock(&cip->ci_lock); 1366 0 stevel ep = cip->ci_principal; 1367 0 stevel (void) pthread_mutex_unlock(&cip->ci_lock); 1368 0 stevel 1369 0 stevel fmd_module_unlock(mp); 1370 0 stevel return (ep); 1371 0 stevel } 1372 0 stevel 1373 0 stevel fmd_case_t * 1374 0 stevel fmd_case_next(fmd_hdl_t *hdl, fmd_case_t *cp) 1375 0 stevel { 1376 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1377 0 stevel 1378 0 stevel if (cp != NULL) 1379 0 stevel cp = fmd_list_next(fmd_api_case_impl(mp, cp)); 1380 0 stevel else 1381 0 stevel cp = fmd_list_next(&mp->mod_cases); 1382 0 stevel 1383 0 stevel fmd_module_unlock(mp); 1384 0 stevel return (cp); 1385 0 stevel } 1386 0 stevel 1387 0 stevel fmd_case_t * 1388 0 stevel fmd_case_prev(fmd_hdl_t *hdl, fmd_case_t *cp) 1389 0 stevel { 1390 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1391 0 stevel 1392 0 stevel if (cp != NULL) 1393 0 stevel cp = fmd_list_prev(fmd_api_case_impl(mp, cp)); 1394 0 stevel else 1395 0 stevel cp = fmd_list_prev(&mp->mod_cases); 1396 0 stevel 1397 0 stevel fmd_module_unlock(mp); 1398 0 stevel return (cp); 1399 0 stevel } 1400 0 stevel 1401 0 stevel /* 1402 0 stevel * Utility function for fmd_buf_* routines. If a case is specified, use the 1403 0 stevel * case's ci_bufs hash; otherwise use the module's global mod_bufs hash. 1404 0 stevel */ 1405 0 stevel static fmd_buf_hash_t * 1406 0 stevel fmd_buf_gethash(fmd_module_t *mp, fmd_case_t *cp) 1407 0 stevel { 1408 0 stevel return (cp ? &fmd_api_case_impl(mp, cp)->ci_bufs : &mp->mod_bufs); 1409 0 stevel } 1410 0 stevel 1411 0 stevel void 1412 0 stevel fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size) 1413 0 stevel { 1414 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1415 0 stevel fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1416 0 stevel fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1417 0 stevel 1418 0 stevel if (bp == NULL) { 1419 0 stevel if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 1420 0 stevel fmd_api_error(mp, EFMD_BUF_INVAL, "cannot create '%s' " 1421 0 stevel "(size %lu): %s\n", name, (ulong_t)size, 1422 0 stevel fmd_strerror(EFMD_BUF_INVAL)); 1423 0 stevel } 1424 0 stevel 1425 0 stevel if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 1426 0 stevel mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 1427 0 stevel fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot create '%s': " 1428 0 stevel "buf limit exceeded (%llu)\n", name, (u_longlong_t) 1429 0 stevel mp->mod_stats->ms_buflimit.fmds_value.ui64); 1430 0 stevel } 1431 0 stevel 1432 0 stevel mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 1433 0 stevel bp = fmd_buf_insert(bhp, name, size); 1434 0 stevel 1435 0 stevel } else { 1436 0 stevel fmd_api_error(mp, EFMD_BUF_EXISTS, 1437 0 stevel "cannot create '%s': buffer already exists\n", name); 1438 0 stevel } 1439 0 stevel 1440 0 stevel if (cp != NULL) 1441 0 stevel fmd_case_setdirty(cp); 1442 0 stevel else 1443 0 stevel fmd_module_setdirty(mp); 1444 0 stevel 1445 0 stevel fmd_module_unlock(mp); 1446 0 stevel } 1447 0 stevel 1448 0 stevel void 1449 0 stevel fmd_buf_destroy(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1450 0 stevel { 1451 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1452 0 stevel fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1453 0 stevel fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1454 0 stevel 1455 0 stevel if (bp != NULL) { 1456 0 stevel mp->mod_stats->ms_buftotal.fmds_value.ui64 -= bp->buf_size; 1457 0 stevel fmd_buf_delete(bhp, name); 1458 0 stevel 1459 0 stevel if (cp != NULL) 1460 0 stevel fmd_case_setdirty(cp); 1461 0 stevel else 1462 0 stevel fmd_module_setdirty(mp); 1463 0 stevel } 1464 0 stevel 1465 0 stevel fmd_module_unlock(mp); 1466 0 stevel } 1467 0 stevel 1468 0 stevel void 1469 0 stevel fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp, 1470 0 stevel const char *name, void *buf, size_t size) 1471 0 stevel { 1472 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1473 0 stevel fmd_buf_t *bp = fmd_buf_lookup(fmd_buf_gethash(mp, cp), name); 1474 0 stevel 1475 0 stevel if (bp == NULL) { 1476 0 stevel fmd_api_error(mp, EFMD_BUF_NOENT, "no buf named '%s' is " 1477 0 stevel "associated with %s\n", name, cp ? "case" : "module"); 1478 0 stevel } 1479 0 stevel 1480 0 stevel bcopy(bp->buf_data, buf, MIN(bp->buf_size, size)); 1481 0 stevel if (size > bp->buf_size) 1482 0 stevel bzero((char *)buf + bp->buf_size, size - bp->buf_size); 1483 0 stevel 1484 0 stevel fmd_module_unlock(mp); 1485 0 stevel } 1486 0 stevel 1487 0 stevel void 1488 0 stevel fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp, 1489 0 stevel const char *name, const void *buf, size_t size) 1490 0 stevel { 1491 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1492 0 stevel fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1493 0 stevel fmd_buf_t *bp = fmd_buf_lookup(bhp, name); 1494 0 stevel 1495 0 stevel if (bp == NULL) { 1496 0 stevel if (fmd_strbadid(name, FMD_B_TRUE) != NULL || size == 0) { 1497 0 stevel fmd_api_error(mp, EFMD_BUF_INVAL, "cannot write '%s' " 1498 0 stevel "(size %lu): %s\n", name, (ulong_t)size, 1499 0 stevel fmd_strerror(EFMD_BUF_INVAL)); 1500 0 stevel } 1501 0 stevel 1502 0 stevel if (mp->mod_stats->ms_buflimit.fmds_value.ui64 - 1503 0 stevel mp->mod_stats->ms_buftotal.fmds_value.ui64 < size) { 1504 0 stevel fmd_api_error(mp, EFMD_BUF_LIMIT, "cannot write '%s': " 1505 0 stevel "buf limit exceeded (%llu)\n", name, (u_longlong_t) 1506 0 stevel mp->mod_stats->ms_buflimit.fmds_value.ui64); 1507 0 stevel } 1508 0 stevel 1509 0 stevel mp->mod_stats->ms_buftotal.fmds_value.ui64 += size; 1510 0 stevel bp = fmd_buf_insert(bhp, name, size); 1511 0 stevel 1512 0 stevel } else if (size > bp->buf_size) { 1513 0 stevel fmd_api_error(mp, EFMD_BUF_OFLOW, 1514 0 stevel "write to buf '%s' overflows buf size (%lu > %lu)\n", 1515 0 stevel name, (ulong_t)size, (ulong_t)bp->buf_size); 1516 0 stevel } 1517 0 stevel 1518 0 stevel bcopy(buf, bp->buf_data, MIN(bp->buf_size, size)); 1519 0 stevel bp->buf_flags |= FMD_BUF_DIRTY; 1520 0 stevel 1521 0 stevel if (cp != NULL) 1522 0 stevel fmd_case_setdirty(cp); 1523 0 stevel else 1524 0 stevel fmd_module_setdirty(mp); 1525 0 stevel 1526 0 stevel fmd_module_unlock(mp); 1527 0 stevel } 1528 0 stevel 1529 0 stevel size_t 1530 0 stevel fmd_buf_size(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name) 1531 0 stevel { 1532 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1533 0 stevel fmd_buf_hash_t *bhp = fmd_buf_gethash(mp, cp); 1534 0 stevel 1535 0 stevel fmd_buf_t *bp; 1536 0 stevel size_t size; 1537 0 stevel 1538 0 stevel if ((bp = fmd_buf_lookup(bhp, name)) != NULL) 1539 0 stevel size = bp->buf_size; 1540 0 stevel else 1541 0 stevel size = 0; 1542 0 stevel 1543 0 stevel fmd_module_unlock(mp); 1544 0 stevel return (size); 1545 0 stevel } 1546 0 stevel 1547 0 stevel void 1548 0 stevel fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t) 1549 0 stevel { 1550 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1551 0 stevel 1552 0 stevel if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) { 1553 0 stevel fmd_api_error(mp, EFMD_SERD_EXISTS, 1554 0 stevel "failed to create serd engine '%s': %s\n", 1555 0 stevel name, fmd_strerror(EFMD_SERD_EXISTS)); 1556 0 stevel } 1557 0 stevel 1558 0 stevel (void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t); 1559 0 stevel fmd_module_setdirty(mp); 1560 0 stevel fmd_module_unlock(mp); 1561 0 stevel } 1562 0 stevel 1563 0 stevel void 1564 0 stevel fmd_serd_destroy(fmd_hdl_t *hdl, const char *name) 1565 0 stevel { 1566 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1567 0 stevel 1568 0 stevel fmd_serd_eng_delete(&mp->mod_serds, name); 1569 0 stevel fmd_module_setdirty(mp); 1570 0 stevel fmd_module_unlock(mp); 1571 0 stevel } 1572 0 stevel 1573 0 stevel int 1574 0 stevel fmd_serd_exists(fmd_hdl_t *hdl, const char *name) 1575 0 stevel { 1576 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1577 0 stevel int rv = (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL); 1578 0 stevel fmd_module_unlock(mp); 1579 0 stevel 1580 0 stevel return (rv); 1581 0 stevel } 1582 0 stevel 1583 0 stevel void 1584 0 stevel fmd_serd_reset(fmd_hdl_t *hdl, const char *name) 1585 0 stevel { 1586 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1587 0 stevel fmd_serd_eng_t *sgp; 1588 0 stevel 1589 0 stevel if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1590 0 stevel fmd_api_error(mp, EFMD_SERD_NAME, 1591 0 stevel "serd engine '%s' does not exist\n", name); 1592 0 stevel } 1593 0 stevel 1594 0 stevel fmd_serd_eng_reset(sgp); 1595 0 stevel fmd_module_setdirty(mp); 1596 0 stevel fmd_module_unlock(mp); 1597 0 stevel } 1598 0 stevel 1599 0 stevel int 1600 0 stevel fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep) 1601 0 stevel { 1602 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1603 0 stevel fmd_serd_eng_t *sgp; 1604 0 stevel int err; 1605 0 stevel 1606 0 stevel if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1607 0 stevel fmd_api_error(mp, EFMD_SERD_NAME, 1608 0 stevel "failed to add record to serd engine '%s'", name); 1609 0 stevel } 1610 0 stevel 1611 0 stevel err = fmd_serd_eng_record(sgp, ep); 1612 0 stevel 1613 0 stevel if (sgp->sg_flags & FMD_SERD_DIRTY) 1614 0 stevel fmd_module_setdirty(mp); 1615 0 stevel 1616 0 stevel fmd_module_unlock(mp); 1617 0 stevel return (err); 1618 0 stevel } 1619 0 stevel 1620 0 stevel int 1621 0 stevel fmd_serd_fired(fmd_hdl_t *hdl, const char *name) 1622 0 stevel { 1623 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1624 0 stevel fmd_serd_eng_t *sgp; 1625 0 stevel int err; 1626 0 stevel 1627 0 stevel if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1628 0 stevel fmd_api_error(mp, EFMD_SERD_NAME, 1629 0 stevel "serd engine '%s' does not exist\n", name); 1630 0 stevel } 1631 0 stevel 1632 0 stevel err = fmd_serd_eng_fired(sgp); 1633 0 stevel fmd_module_unlock(mp); 1634 0 stevel return (err); 1635 0 stevel } 1636 0 stevel 1637 0 stevel int 1638 0 stevel fmd_serd_empty(fmd_hdl_t *hdl, const char *name) 1639 0 stevel { 1640 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1641 0 stevel fmd_serd_eng_t *sgp; 1642 0 stevel int empty; 1643 0 stevel 1644 0 stevel if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) { 1645 0 stevel fmd_api_error(mp, EFMD_SERD_NAME, 1646 0 stevel "serd engine '%s' does not exist\n", name); 1647 0 stevel } 1648 0 stevel 1649 0 stevel empty = fmd_serd_eng_empty(sgp); 1650 0 stevel fmd_module_unlock(mp); 1651 0 stevel return (empty); 1652 0 stevel } 1653 0 stevel 1654 0 stevel pthread_t 1655 0 stevel fmd_thr_create(fmd_hdl_t *hdl, void (*func)(void *), void *arg) 1656 0 stevel { 1657 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1658 0 stevel fmd_thread_t *tp; 1659 0 stevel pthread_t tid; 1660 0 stevel 1661 0 stevel if (mp->mod_stats->ms_thrtotal.fmds_value.ui32 >= 1662 0 stevel mp->mod_stats->ms_thrlimit.fmds_value.ui32) { 1663 0 stevel fmd_api_error(mp, EFMD_THR_LIMIT, "%s request to create an " 1664 0 stevel "auxiliary thread exceeds module thread limit (%u)\n", 1665 0 stevel mp->mod_name, mp->mod_stats->ms_thrlimit.fmds_value.ui32); 1666 0 stevel } 1667 0 stevel 1668 0 stevel if ((tp = fmd_thread_create(mp, func, arg)) == NULL) { 1669 0 stevel fmd_api_error(mp, EFMD_THR_CREATE, 1670 0 stevel "failed to create auxiliary thread"); 1671 0 stevel } 1672 0 stevel 1673 0 stevel tid = tp->thr_tid; 1674 0 stevel mp->mod_stats->ms_thrtotal.fmds_value.ui32++; 1675 0 stevel (void) fmd_idspace_xalloc(mp->mod_threads, tid, tp); 1676 0 stevel 1677 0 stevel fmd_module_unlock(mp); 1678 0 stevel return (tid); 1679 0 stevel } 1680 0 stevel 1681 0 stevel void 1682 0 stevel fmd_thr_destroy(fmd_hdl_t *hdl, pthread_t tid) 1683 0 stevel { 1684 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1685 0 stevel fmd_thread_t *tp; 1686 0 stevel int err; 1687 0 stevel 1688 0 stevel if (pthread_self() == tid) { 1689 0 stevel fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 1690 0 stevel "destroy itself (tid %u)\n", tid); 1691 0 stevel } 1692 0 stevel 1693 0 stevel if ((tp = fmd_idspace_getspecific(mp->mod_threads, tid)) == NULL) { 1694 0 stevel fmd_api_error(mp, EFMD_THR_INVAL, "auxiliary thread tried to " 1695 0 stevel "destroy an invalid thread (tid %u)\n", tid); 1696 0 stevel } 1697 0 stevel 1698 0 stevel /* 1699 0 stevel * Wait for the specified thread to exit and then join with it. Since 1700 0 stevel * the thread may need to make API calls in order to complete its work 1701 0 stevel * we must sleep with the module lock unheld, and then reacquire it. 1702 0 stevel */ 1703 0 stevel fmd_module_unlock(mp); 1704 0 stevel err = pthread_join(tid, NULL); 1705 0 stevel mp = fmd_api_module_lock(hdl); 1706 0 stevel 1707 0 stevel /* 1708 0 stevel * Since pthread_join() was called without the module lock held, if 1709 0 stevel * multiple callers attempted to destroy the same auxiliary thread 1710 0 stevel * simultaneously, one will succeed and the others will get ESRCH. 1711 0 stevel * Therefore we silently ignore ESRCH but only allow the caller who 1712 0 stevel * succeessfully joined with the auxiliary thread to destroy it. 1713 0 stevel */ 1714 0 stevel if (err != 0 && err != ESRCH) { 1715 0 stevel fmd_api_error(mp, EFMD_THR_JOIN, 1716 0 stevel "failed to join with auxiliary thread %u\n", tid); 1717 0 stevel } 1718 0 stevel 1719 0 stevel if (err == 0) { 1720 0 stevel fmd_thread_destroy(tp, FMD_THREAD_NOJOIN); 1721 0 stevel mp->mod_stats->ms_thrtotal.fmds_value.ui32--; 1722 0 stevel (void) fmd_idspace_free(mp->mod_threads, tid); 1723 0 stevel } 1724 0 stevel 1725 0 stevel fmd_module_unlock(mp); 1726 0 stevel } 1727 0 stevel 1728 0 stevel void 1729 0 stevel fmd_thr_signal(fmd_hdl_t *hdl, pthread_t tid) 1730 0 stevel { 1731 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1732 0 stevel 1733 0 stevel if (tid != mp->mod_thread->thr_tid && 1734 0 stevel fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) { 1735 0 stevel fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid " 1736 0 stevel "thread id for module %s\n", tid, mp->mod_name); 1737 0 stevel } 1738 0 stevel 1739 0 stevel (void) pthread_kill(tid, fmd.d_thr_sig); 1740 0 stevel fmd_module_unlock(mp); 1741 0 stevel } 1742 0 stevel 1743 7850 Vuong void 1744 7850 Vuong fmd_thr_checkpoint(fmd_hdl_t *hdl) 1745 7850 Vuong { 1746 7850 Vuong fmd_module_t *mp = fmd_api_module_lock(hdl); 1747 7850 Vuong pthread_t tid = pthread_self(); 1748 7850 Vuong 1749 7850 Vuong if (tid == mp->mod_thread->thr_tid || 1750 7850 Vuong fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) { 1751 7850 Vuong fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid " 1752 7850 Vuong "auxiliary thread id for module %s\n", tid, mp->mod_name); 1753 7850 Vuong } 1754 7850 Vuong 1755 7850 Vuong fmd_ckpt_save(mp); 1756 7850 Vuong 1757 7850 Vuong fmd_module_unlock(mp); 1758 7850 Vuong } 1759 7850 Vuong 1760 0 stevel id_t 1761 0 stevel fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) 1762 0 stevel { 1763 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1764 0 stevel fmd_modtimer_t *t; 1765 0 stevel id_t id; 1766 0 stevel 1767 0 stevel if (delta < 0) { 1768 0 stevel fmd_api_error(mp, EFMD_TIMER_INVAL, 1769 0 stevel "timer delta %lld is not a valid interval\n", delta); 1770 0 stevel } 1771 0 stevel 1772 0 stevel t = fmd_alloc(sizeof (fmd_modtimer_t), FMD_SLEEP); 1773 0 stevel t->mt_mod = mp; 1774 0 stevel t->mt_arg = arg; 1775 0 stevel t->mt_id = -1; 1776 0 stevel 1777 0 stevel if ((id = fmd_timerq_install(fmd.d_timers, mp->mod_timerids, 1778 0 stevel (fmd_timer_f *)fmd_module_timeout, t, ep, delta)) == -1) { 1779 0 stevel fmd_free(t, sizeof (fmd_modtimer_t)); 1780 0 stevel fmd_api_error(mp, EFMD_TIMER_LIMIT, 1781 0 stevel "failed to install timer +%lld", delta); 1782 0 stevel } 1783 0 stevel 1784 0 stevel fmd_module_unlock(mp); 1785 0 stevel return (id); 1786 0 stevel } 1787 0 stevel 1788 0 stevel void 1789 0 stevel fmd_timer_remove(fmd_hdl_t *hdl, id_t id) 1790 0 stevel { 1791 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1792 0 stevel fmd_modtimer_t *t; 1793 0 stevel 1794 0 stevel if (!fmd_idspace_valid(mp->mod_timerids, id)) { 1795 0 stevel fmd_api_error(mp, EFMD_TIMER_INVAL, 1796 0 stevel "id %ld is not a valid timer id\n", id); 1797 0 stevel } 1798 0 stevel 1799 3323 cindi /* 1800 3323 cindi * If the timer has not fired (t != NULL), remove it from the timer 1801 3323 cindi * queue. If the timer has fired (t == NULL), we could be in one of 1802 3323 cindi * two situations: a) we are processing the timer callback or b) 1803 3323 cindi * the timer event is on the module queue awaiting dispatch. For a), 1804 3323 cindi * fmd_timerq_remove() will wait for the timer callback function 1805 3323 cindi * to complete and queue an event for dispatch. For a) and b), 1806 3323 cindi * we cancel the outstanding timer event from the module's dispatch 1807 3323 cindi * queue. 1808 3323 cindi */ 1809 3323 cindi if ((t = fmd_timerq_remove(fmd.d_timers, mp->mod_timerids, id)) != NULL) 1810 3323 cindi fmd_free(t, sizeof (fmd_modtimer_t)); 1811 0 stevel fmd_module_unlock(mp); 1812 0 stevel 1813 3323 cindi fmd_eventq_cancel(mp->mod_queue, FMD_EVT_TIMEOUT, (void *)id); 1814 0 stevel } 1815 0 stevel 1816 0 stevel nvlist_t * 1817 0 stevel fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, 1818 0 stevel uint8_t certainty, nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc) 1819 0 stevel { 1820 3323 cindi fmd_module_t *mp; 1821 0 stevel nvlist_t *nvl; 1822 0 stevel 1823 3323 cindi mp = fmd_api_module_lock(hdl); 1824 0 stevel if (class == NULL || class[0] == '\0') 1825 0 stevel fmd_api_error(mp, EFMD_NVL_INVAL, "invalid fault class\n"); 1826 4198 eschrock 1827 7197 stephh nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc, NULL); 1828 4198 eschrock 1829 4198 eschrock fmd_module_unlock(mp); 1830 3323 cindi 1831 0 stevel return (nvl); 1832 0 stevel } 1833 0 stevel 1834 0 stevel int 1835 0 stevel fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern) 1836 0 stevel { 1837 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1838 0 stevel char *class; 1839 0 stevel int rv; 1840 0 stevel 1841 0 stevel rv = (nvl != NULL && nvlist_lookup_string(nvl, 1842 0 stevel FM_CLASS, &class) == 0 && fmd_strmatch(class, pattern)); 1843 0 stevel 1844 0 stevel fmd_module_unlock(mp); 1845 0 stevel return (rv); 1846 0 stevel } 1847 0 stevel 1848 0 stevel int 1849 0 stevel fmd_nvl_fmri_expand(fmd_hdl_t *hdl, nvlist_t *nvl) 1850 0 stevel { 1851 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1852 0 stevel int rv; 1853 0 stevel 1854 0 stevel if (nvl == NULL) { 1855 0 stevel fmd_api_error(mp, EFMD_NVL_INVAL, 1856 0 stevel "invalid nvlist %p\n", (void *)nvl); 1857 0 stevel } 1858 0 stevel 1859 0 stevel rv = fmd_fmri_expand(nvl); 1860 0 stevel fmd_module_unlock(mp); 1861 0 stevel return (rv); 1862 0 stevel } 1863 0 stevel 1864 0 stevel int 1865 0 stevel fmd_nvl_fmri_present(fmd_hdl_t *hdl, nvlist_t *nvl) 1866 0 stevel { 1867 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1868 0 stevel int rv; 1869 0 stevel 1870 0 stevel if (nvl == NULL) { 1871 0 stevel fmd_api_error(mp, EFMD_NVL_INVAL, 1872 0 stevel "invalid nvlist %p\n", (void *)nvl); 1873 0 stevel } 1874 0 stevel 1875 0 stevel rv = fmd_fmri_present(nvl); 1876 0 stevel fmd_module_unlock(mp); 1877 0 stevel 1878 0 stevel if (rv < 0) { 1879 0 stevel fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1880 0 stevel "fmd_nvl_fmri_present\n"); 1881 0 stevel } 1882 0 stevel 1883 0 stevel return (rv); 1884 0 stevel } 1885 0 stevel 1886 0 stevel int 1887 7275 stephh fmd_nvl_fmri_replaced(fmd_hdl_t *hdl, nvlist_t *nvl) 1888 7275 stephh { 1889 7275 stephh fmd_module_t *mp = fmd_api_module_lock(hdl); 1890 7275 stephh int rv; 1891 7275 stephh 1892 7275 stephh if (nvl == NULL) { 1893 7275 stephh fmd_api_error(mp, EFMD_NVL_INVAL, 1894 7275 stephh "invalid nvlist %p\n", (void *)nvl); 1895 7275 stephh } 1896 7275 stephh 1897 7275 stephh rv = fmd_fmri_replaced(nvl); 1898 7275 stephh fmd_module_unlock(mp); 1899 7275 stephh 1900 7275 stephh return (rv); 1901 7275 stephh } 1902 7275 stephh 1903 7275 stephh int 1904 0 stevel fmd_nvl_fmri_unusable(fmd_hdl_t *hdl, nvlist_t *nvl) 1905 0 stevel { 1906 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 1907 0 stevel int rv; 1908 0 stevel 1909 0 stevel if (nvl == NULL) { 1910 0 stevel fmd_api_error(mp, EFMD_NVL_INVAL, 1911 0 stevel "invalid nvlist %p\n", (void *)nvl); 1912 0 stevel } 1913 0 stevel 1914 0 stevel rv = fmd_fmri_unusable(nvl); 1915 0 stevel fmd_module_unlock(mp); 1916 0 stevel 1917 0 stevel if (rv < 0) { 1918 0 stevel fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1919 0 stevel "fmd_nvl_fmri_unusable\n"); 1920 0 stevel } 1921 0 stevel 1922 0 stevel return (rv); 1923 0 stevel } 1924 0 stevel 1925 0 stevel int 1926 7532 Sean fmd_nvl_fmri_retire(fmd_hdl_t *hdl, nvlist_t *nvl) 1927 7532 Sean { 1928 7532 Sean fmd_module_t *mp = fmd_api_module_lock(hdl); 1929 7532 Sean int rv; 1930 7532 Sean 1931 7532 Sean if (nvl == NULL) { 1932 7532 Sean fmd_api_error(mp, EFMD_NVL_INVAL, 1933 7532 Sean "invalid nvlist %p\n", (void *)nvl); 1934 7532 Sean } 1935 7532 Sean 1936 7532 Sean rv = fmd_fmri_retire(nvl); 1937 7532 Sean fmd_module_unlock(mp); 1938 7532 Sean 1939 7532 Sean return (rv); 1940 7532 Sean } 1941 7532 Sean 1942 7532 Sean int 1943 7532 Sean fmd_nvl_fmri_unretire(fmd_hdl_t *hdl, nvlist_t *nvl) 1944 7532 Sean { 1945 7532 Sean fmd_module_t *mp = fmd_api_module_lock(hdl); 1946 7532 Sean int rv; 1947 7532 Sean 1948 7532 Sean if (nvl == NULL) { 1949 7532 Sean fmd_api_error(mp, EFMD_NVL_INVAL, 1950 7532 Sean "invalid nvlist %p\n", (void *)nvl); 1951 7532 Sean } 1952 7532 Sean 1953 7532 Sean rv = fmd_fmri_unretire(nvl); 1954 7532 Sean fmd_module_unlock(mp); 1955 7532 Sean 1956 7532 Sean return (rv); 1957 7532 Sean } 1958 7532 Sean 1959 7532 Sean int 1960 7275 stephh fmd_nvl_fmri_service_state(fmd_hdl_t *hdl, nvlist_t *nvl) 1961 1414 cindi { 1962 1414 cindi fmd_module_t *mp = fmd_api_module_lock(hdl); 1963 7275 stephh int rv; 1964 1414 cindi 1965 1414 cindi if (nvl == NULL) { 1966 1414 cindi fmd_api_error(mp, EFMD_NVL_INVAL, 1967 1414 cindi "invalid nvlist %p\n", (void *)nvl); 1968 1414 cindi } 1969 1414 cindi 1970 7275 stephh rv = fmd_fmri_service_state(nvl); 1971 7275 stephh if (rv < 0) 1972 7275 stephh rv = fmd_fmri_unusable(nvl) ? FMD_SERVICE_STATE_UNUSABLE : 1973 7275 stephh FMD_SERVICE_STATE_OK; 1974 7275 stephh fmd_module_unlock(mp); 1975 7275 stephh 1976 7275 stephh if (rv < 0) { 1977 7275 stephh fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 1978 7275 stephh "fmd_nvl_fmri_service_state\n"); 1979 1414 cindi } 1980 1414 cindi 1981 7275 stephh return (rv); 1982 7275 stephh } 1983 7275 stephh 1984 7275 stephh typedef struct { 1985 7275 stephh const char *class; 1986 7275 stephh int *rvp; 1987 7275 stephh } fmd_has_fault_arg_t; 1988 7275 stephh 1989 7275 stephh static void 1990 7275 stephh fmd_rsrc_has_fault(fmd_asru_link_t *alp, void *arg) 1991 7275 stephh { 1992 7275 stephh fmd_has_fault_arg_t *fhfp = (fmd_has_fault_arg_t *)arg; 1993 7275 stephh char *class; 1994 7275 stephh 1995 7275 stephh if (fhfp->class == NULL) { 1996 7275 stephh if (alp->al_flags & FMD_ASRU_FAULTY) 1997 7275 stephh *fhfp->rvp = 1; 1998 7275 stephh } else { 1999 7275 stephh if ((alp->al_flags & FMD_ASRU_FAULTY) && 2000 7275 stephh alp->al_event != NULL && nvlist_lookup_string(alp->al_event, 2001 7275 stephh FM_CLASS, &class) == 0 && fmd_strmatch(class, fhfp->class)) 2002 7275 stephh *fhfp->rvp = 1; 2003 7275 stephh } 2004 7275 stephh } 2005 7275 stephh 2006 7275 stephh int 2007 7275 stephh fmd_nvl_fmri_has_fault(fmd_hdl_t *hdl, nvlist_t *nvl, int type, char *class) 2008 7275 stephh { 2009 7275 stephh fmd_module_t *mp = fmd_api_module_lock(hdl); 2010 7275 stephh fmd_asru_hash_t *ahp = fmd.d_asrus; 2011 7275 stephh int rv = 0; 2012 7275 stephh char *name; 2013 7275 stephh int namelen; 2014 7275 stephh fmd_has_fault_arg_t fhf; 2015 7275 stephh 2016 7275 stephh if (nvl == NULL) { 2017 7275 stephh fmd_api_error(mp, EFMD_NVL_INVAL, 2018 7275 stephh "invalid nvlist %p\n", (void *)nvl); 2019 7275 stephh } 2020 7275 stephh if ((namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) == -1) 2021 7275 stephh fmd_api_error(mp, EFMD_NVL_INVAL, 2022 7275 stephh "invalid nvlist: %p\n", (void *)nvl); 2023 7275 stephh name = fmd_alloc(namelen + 1, FMD_SLEEP); 2024 7275 stephh if (fmd_fmri_nvl2str(nvl, name, namelen + 1) == -1) { 2025 7275 stephh if (name != NULL) 2026 7275 stephh fmd_free(name, namelen + 1); 2027 7275 stephh fmd_api_error(mp, EFMD_NVL_INVAL, 2028 7275 stephh "invalid nvlist: %p\n", (void *)nvl); 2029 7275 stephh } 2030 7275 stephh 2031 7275 stephh fhf.class = class; 2032 7275 stephh fhf.rvp = &rv; 2033 7275 stephh if (type == FMD_HAS_FAULT_RESOURCE) 2034 7275 stephh fmd_asru_hash_apply_by_rsrc(ahp, name, fmd_rsrc_has_fault, 2035 7275 stephh &fhf); 2036 7275 stephh else if (type == FMD_HAS_FAULT_ASRU) 2037 7275 stephh fmd_asru_hash_apply_by_asru(ahp, name, fmd_rsrc_has_fault, 2038 7275 stephh &fhf); 2039 7275 stephh else if (type == FMD_HAS_FAULT_FRU) 2040 7275 stephh fmd_asru_hash_apply_by_fru(ahp, name, fmd_rsrc_has_fault, 2041 7275 stephh &fhf); 2042 7275 stephh 2043 7275 stephh if (name != NULL) 2044 7275 stephh fmd_free(name, namelen + 1); 2045 1414 cindi fmd_module_unlock(mp); 2046 1414 cindi return (rv); 2047 1414 cindi } 2048 1414 cindi 2049 1414 cindi int 2050 0 stevel fmd_nvl_fmri_contains(fmd_hdl_t *hdl, nvlist_t *n1, nvlist_t *n2) 2051 0 stevel { 2052 0 stevel fmd_module_t *mp = fmd_api_module_lock(hdl); 2053 0 stevel int rv; 2054 0 stevel 2055 0 stevel if (n1 == NULL || n2 == NULL) { 2056 0 stevel fmd_api_error(mp, EFMD_NVL_INVAL, 2057 0 stevel "invalid nvlist(s): %p, %p\n", (void *)n1, (void *)n2); 2058 0 stevel } 2059 0 stevel 2060 0 stevel rv = fmd_fmri_contains(n1, n2); 2061 0 stevel fmd_module_unlock(mp); 2062 0 stevel 2063 0 stevel if (rv < 0) { 2064 0 stevel fmd_api_error(mp, EFMD_FMRI_OP, "invalid fmri for " 2065 0 stevel "fmd_nvl_fmri_contains\n"); 2066 0 stevel } 2067 0 stevel 2068 0 stevel return (rv); 2069 0 stevel } 2070 1193 mws 2071 1193 mws nvlist_t * 2072 1193 mws fmd_nvl_fmri_translate(fmd_hdl_t *hdl, nvlist_t *fmri, nvlist_t *auth) 2073 1193 mws { 2074 1193 mws fmd_module_t *mp = fmd_api_module_lock(hdl); 2075 1193 mws nvlist_t *xfmri; 2076 1193 mws 2077 1193 mws if (fmri == NULL || auth == NULL) { 2078 1193 mws fmd_api_error(mp, EFMD_NVL_INVAL, 2079 1193 mws "invalid nvlist(s): %p, %p\n", (void *)fmri, (void *)auth); 2080 1193 mws } 2081 1193 mws 2082 1193 mws xfmri = fmd_fmri_translate(fmri, auth); 2083 1193 mws fmd_module_unlock(mp); 2084 1193 mws return (xfmri); 2085 1193 mws } 2086 1193 mws 2087 7171 eschrock static int 2088 7171 eschrock fmd_nvl_op_init(nv_alloc_t *ops, va_list ap) 2089 7171 eschrock { 2090 7171 eschrock fmd_module_t *mp = va_arg(ap, fmd_module_t *); 2091 7171 eschrock 2092 7171 eschrock ops->nva_arg = mp; 2093 7171 eschrock 2094 7171 eschrock return (0); 2095 7171 eschrock } 2096 7171 eschrock 2097 7171 eschrock static void * 2098 7171 eschrock fmd_nvl_op_alloc_sleep(nv_alloc_t *ops, size_t size) 2099 7171 eschrock { 2100 7171 eschrock fmd_module_t *mp = ops->nva_arg; 2101 7171 eschrock 2102 7171 eschrock return (fmd_hdl_alloc_locked(mp, size, FMD_SLEEP)); 2103 7171 eschrock } 2104 7171 eschrock 2105 7171 eschrock static void * 2106 7171 eschrock fmd_nvl_op_alloc_nosleep(nv_alloc_t *ops, size_t size) 2107 7171 eschrock { 2108 7171 eschrock fmd_module_t *mp = ops->nva_arg; 2109 7171 eschrock 2110 7171 eschrock return (fmd_hdl_alloc_locked(mp, size, FMD_NOSLEEP)); 2111 7171 eschrock } 2112 7171 eschrock 2113 7171 eschrock static void 2114 7171 eschrock fmd_nvl_op_free(nv_alloc_t *ops, void *data, size_t size) 2115 7171 eschrock { 2116 7171 eschrock fmd_module_t *mp = ops->nva_arg; 2117 7171 eschrock 2118 7171 eschrock fmd_hdl_free_locked(mp, data, size); 2119 7171 eschrock } 2120 7171 eschrock 2121 7171 eschrock nv_alloc_ops_t fmd_module_nva_ops_sleep = { 2122 7171 eschrock fmd_nvl_op_init, 2123 7171 eschrock NULL, 2124 7171 eschrock fmd_nvl_op_alloc_sleep, 2125 7171 eschrock fmd_nvl_op_free, 2126 7171 eschrock NULL 2127 7171 eschrock }; 2128 7171 eschrock 2129 7171 eschrock nv_alloc_ops_t fmd_module_nva_ops_nosleep = { 2130 7171 eschrock fmd_nvl_op_init, 2131 7171 eschrock NULL, 2132 7171 eschrock fmd_nvl_op_alloc_nosleep, 2133 7171 eschrock fmd_nvl_op_free, 2134 7171 eschrock NULL 2135 7171 eschrock }; 2136 7171 eschrock 2137 7171 eschrock nvlist_t * 2138 7171 eschrock fmd_nvl_alloc(fmd_hdl_t *hdl, int flags) 2139 7171 eschrock { 2140 7171 eschrock fmd_module_t *mp = fmd_api_module_lock(hdl); 2141 7171 eschrock nv_alloc_t *nva; 2142 7171 eschrock nvlist_t *nvl; 2143 7171 eschrock int ret; 2144 7171 eschrock 2145 7171 eschrock if (flags == FMD_SLEEP) 2146 7171 eschrock nva = &mp->mod_nva_sleep; 2147 7171 eschrock else 2148 7171 eschrock nva = &mp->mod_nva_nosleep; 2149 7171 eschrock 2150 7171 eschrock ret = nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nva); 2151 7171 eschrock 2152 7171 eschrock fmd_module_unlock(mp); 2153 7171 eschrock 2154 7171 eschrock if (ret != 0) 2155 7171 eschrock return (NULL); 2156 7171 eschrock else 2157 7171 eschrock return (nvl); 2158 7171 eschrock } 2159 7171 eschrock 2160 7171 eschrock nvlist_t * 2161 7171 eschrock fmd_nvl_dup(fmd_hdl_t *hdl, nvlist_t *src, int flags) 2162 7171 eschrock { 2163 7171 eschrock fmd_module_t *mp = fmd_api_module_lock(hdl); 2164 7171 eschrock nv_alloc_t *nva; 2165 7171 eschrock nvlist_t *nvl; 2166 7171 eschrock int ret; 2167 7171 eschrock 2168 7171 eschrock if (flags == FMD_SLEEP) 2169 7171 eschrock nva = &mp->mod_nva_sleep; 2170 7171 eschrock else 2171 7171 eschrock nva = &mp->mod_nva_nosleep; 2172 7171 eschrock 2173 7171 eschrock ret = nvlist_xdup(src, &nvl, nva); 2174 7171 eschrock 2175 7171 eschrock fmd_module_unlock(mp); 2176 7171 eschrock 2177 7171 eschrock if (ret != 0) 2178 7171 eschrock return (NULL); 2179 7171 eschrock else 2180 7171 eschrock return (nvl); 2181 7171 eschrock } 2182 7171 eschrock 2183 8526 Robert /*ARGSUSED*/ 2184 8526 Robert void 2185 8526 Robert fmd_repair_fru(fmd_hdl_t *hdl, const char *fmri) 2186 8526 Robert { 2187 8526 Robert int err; 2188 9874 Stephen fmd_asru_rep_arg_t fara; 2189 8526 Robert 2190 9874 Stephen fara.fara_reason = FMD_ASRU_REPAIRED; 2191 9874 Stephen fara.fara_bywhat = FARA_BY_FRU; 2192 9874 Stephen fara.fara_rval = &err; 2193 8526 Robert fmd_asru_hash_apply_by_fru(fmd.d_asrus, (char *)fmri, 2194 9874 Stephen fmd_asru_repaired, &fara); 2195 8526 Robert } 2196 8526 Robert 2197 10784 sinanallur /*ARGSUSED*/ 2198 10784 sinanallur int 2199 10784 sinanallur fmd_repair_asru(fmd_hdl_t *hdl, const char *fmri) 2200 10784 sinanallur { 2201 10784 sinanallur int err = FARA_ERR_RSRCNOTF; 2202 10784 sinanallur fmd_asru_rep_arg_t fara; 2203 10784 sinanallur 2204 10784 sinanallur fara.fara_reason = FMD_ASRU_REPAIRED; 2205 10784 sinanallur fara.fara_rval = &err; 2206 10784 sinanallur fara.fara_uuid = NULL; 2207 10784 sinanallur fara.fara_bywhat = FARA_BY_ASRU; 2208 10784 sinanallur fmd_asru_hash_apply_by_asru(fmd.d_asrus, fmri, 2209 10784 sinanallur fmd_asru_repaired, &fara); 2210 10784 sinanallur return (err); 2211 10784 sinanallur } 2212 10784 sinanallur 2213 1193 mws int 2214 1193 mws fmd_event_local(fmd_hdl_t *hdl, fmd_event_t *ep) 2215 1193 mws { 2216 1193 mws if (hdl == NULL || ep == NULL) { 2217 1193 mws fmd_api_error(fmd_api_module_lock(hdl), EFMD_EVENT_INVAL, 2218 1193 mws "NULL parameter specified to fmd_event_local\n"); 2219 1193 mws } 2220 1193 mws 2221 1193 mws return (((fmd_event_impl_t *)ep)->ev_flags & FMD_EVF_LOCAL); 2222 4198 eschrock } 2223 4198 eschrock 2224 4198 eschrock /*ARGSUSED*/ 2225 4198 eschrock uint64_t 2226 4198 eschrock fmd_event_ena_create(fmd_hdl_t *hdl) 2227 4198 eschrock { 2228 4198 eschrock return (fmd_ena()); 2229 1193 mws } 2230 1193 mws 2231 1193 mws fmd_xprt_t * 2232 1193 mws fmd_xprt_open(fmd_hdl_t *hdl, uint_t flags, nvlist_t *auth, void *data) 2233 1193 mws { 2234 1193 mws fmd_module_t *mp = fmd_api_module_lock(hdl); 2235 1193 mws fmd_xprt_t *xp; 2236 1193 mws 2237 1193 mws if (flags & ~FMD_XPRT_CMASK) { 2238 1193 mws fmd_api_error(mp, EFMD_XPRT_INVAL, 2239 1193 mws "invalid transport flags 0x%x\n", flags); 2240 1193 mws } 2241 1193 mws 2242 1193 mws if ((flags & FMD_XPRT_RDWR) != FMD_XPRT_RDWR && 2243 1193 mws (flags & FMD_XPRT_RDWR) != FMD_XPRT_RDONLY) { 2244 1193 mws fmd_api_error(mp, EFMD_XPRT_INVAL, 2245 1193 mws "cannot open write-only transport\n"); 2246 1193 mws } 2247 1193 mws 2248 1193 mws if (mp->mod_stats->ms_xprtopen.fmds_value.ui32 >= 2249 1193 mws mp->mod_stats->ms_xprtlimit.fmds_value.ui32) { 2250 1193 mws fmd_api_error(mp, EFMD_XPRT_LIMIT, "%s request to create a " 2251 1193 mws "transport exceeds module transport limit (%u)\n", 2252 1193 mws mp->mod_name, mp->mod_stats->ms_xprtlimit.fmds_value.ui32); 2253 1193 mws } 2254 1193 mws 2255 1193 mws if ((xp = fmd_xprt_create(mp, flags, auth, data)) == NULL) 2256 1193 mws fmd_api_error(mp, errno, "cannot create transport"); 2257 1193 mws 2258 1193 mws fmd_module_unlock(mp); 2259 1193 mws return (xp); 2260 1193 mws } 2261 1193 mws 2262 1193 mws void 2263 1193 mws fmd_xprt_close(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2264 1193 mws { 2265 1193 mws fmd_module_t *mp = fmd_api_module_lock(hdl); 2266 1193 mws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2267 1193 mws 2268 1193 mws /* 2269 1193 mws * Although this could be supported, it doesn't seem necessary or worth 2270 1193 mws * the trouble. For now, just detect this and trigger a module abort. 2271 1193 mws * If it is needed, transports should grow reference counts and a new 2272 1193 mws * event type will need to be enqueued for the main thread to reap it. 2273 1193 mws */ 2274 1193 mws if (xip->xi_thread != NULL && 2275 1193 mws xip->xi_thread->thr_tid == pthread_self()) { 2276 1193 mws fmd_api_error(mp, EFMD_XPRT_INVAL, 2277 1193 mws "fmd_xprt_close() cannot be called from fmdo_send()\n"); 2278 1193 mws } 2279 1193 mws 2280 1193 mws fmd_xprt_destroy(xp); 2281 1193 mws fmd_module_unlock(mp); 2282 1193 mws } 2283 1193 mws 2284 1193 mws void 2285 1193 mws fmd_xprt_post(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt) 2286 1193 mws { 2287 7419 Eric nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl); 2288 7419 Eric fmd_module_t *mp = fmd_api_module(hdl); 2289 1193 mws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2290 7419 Eric nvlist_t *tmp; 2291 7419 Eric 2292 7419 Eric /* 2293 7419 Eric * If this event was allocated using the module-specific nvlist ops, we 2294 7419 Eric * need to create a copy using the standard fmd nvlist ops. Otherwise, 2295 7419 Eric * the event may persist after the module has been unloaded and we'll 2296 7419 Eric * die when attempting to free the nvlist. 2297 7419 Eric */ 2298 7419 Eric if (nva == &mp->mod_nva_sleep || nva == &mp->mod_nva_nosleep) { 2299 7419 Eric (void) nvlist_xdup(nvl, &tmp, &fmd.d_nva); 2300 7419 Eric nvlist_free(nvl); 2301 7419 Eric nvl = tmp; 2302 7419 Eric } 2303 1193 mws 2304 1193 mws /* 2305 1193 mws * fmd_xprt_recv() must block during startup waiting for fmd to globally 2306 1193 mws * clear FMD_XPRT_DSUSPENDED. As such, we can't allow it to be called 2307 1193 mws * from a module's _fmd_init() routine, because that would block 2308 1193 mws * fmd from completing initial module loading, resulting in a deadlock. 2309 1193 mws */ 2310 1193 mws if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) && 2311 1193 mws (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) { 2312 1193 mws fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL, 2313 1193 mws "fmd_xprt_post() cannot be called from _fmd_init()\n"); 2314 1193 mws } 2315 1193 mws 2316 7850 Vuong fmd_xprt_recv(xp, nvl, hrt, FMD_B_FALSE); 2317 7850 Vuong } 2318 7850 Vuong 2319 7850 Vuong void 2320 7850 Vuong fmd_xprt_log(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt) 2321 7850 Vuong { 2322 7850 Vuong fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2323 7850 Vuong 2324 7850 Vuong /* 2325 7850 Vuong * fmd_xprt_recv() must block during startup waiting for fmd to globally 2326 7850 Vuong * clear FMD_XPRT_DSUSPENDED. As such, we can't allow it to be called 2327 7850 Vuong * from a module's _fmd_init() routine, because that would block 2328 7850 Vuong * fmd from completing initial module loading, resulting in a deadlock. 2329 7850 Vuong */ 2330 7850 Vuong if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) && 2331 7850 Vuong (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) { 2332 7850 Vuong fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL, 2333 7850 Vuong "fmd_xprt_log() cannot be called from _fmd_init()\n"); 2334 7850 Vuong } 2335 7850 Vuong 2336 7850 Vuong fmd_xprt_recv(xp, nvl, hrt, FMD_B_TRUE); 2337 1193 mws } 2338 1193 mws 2339 1193 mws void 2340 1193 mws fmd_xprt_suspend(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2341 1193 mws { 2342 1193 mws (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */ 2343 1193 mws fmd_xprt_xsuspend(xp, FMD_XPRT_SUSPENDED); 2344 1193 mws } 2345 1193 mws 2346 1193 mws void 2347 1193 mws fmd_xprt_resume(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2348 1193 mws { 2349 1193 mws (void) fmd_api_transport_impl(hdl, xp); /* validate 'xp' */ 2350 1193 mws fmd_xprt_xresume(xp, FMD_XPRT_SUSPENDED); 2351 1193 mws } 2352 1193 mws 2353 1193 mws int 2354 1193 mws fmd_xprt_error(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2355 1193 mws { 2356 1193 mws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2357 1193 mws return (xip->xi_state == _fmd_xprt_state_err); 2358 1193 mws } 2359 1193 mws 2360 1193 mws /* 2361 1193 mws * Translate all FMRIs in the specified name-value pair list for the specified 2362 1193 mws * FMRI authority, and return a new name-value pair list for the translation. 2363 1193 mws * This function is the recursive engine used by fmd_xprt_translate(), below. 2364 1193 mws */ 2365 1193 mws static nvlist_t * 2366 1193 mws fmd_xprt_xtranslate(nvlist_t *nvl, nvlist_t *auth) 2367 1193 mws { 2368 1193 mws uint_t i, j, n; 2369 1193 mws nvpair_t *nvp, **nvps; 2370 1193 mws uint_t nvpslen = 0; 2371 1193 mws char *name; 2372 1193 mws size_t namelen = 0; 2373 1193 mws 2374 1193 mws nvlist_t **a, **b; 2375 1193 mws nvlist_t *l, *r; 2376 1193 mws data_type_t type; 2377 1193 mws char *s; 2378 1193 mws int err; 2379 1193 mws 2380 1193 mws (void) nvlist_xdup(nvl, &nvl, &fmd.d_nva); 2381 1193 mws 2382 1193 mws /* 2383 1193 mws * Count up the number of name-value pairs in 'nvl' and compute the 2384 1193 mws * maximum length of a name used in this list for use below. 2385 1193 mws */ 2386 1193 mws for (nvp = nvlist_next_nvpair(nvl, NULL); 2387 1193 mws nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp), nvpslen++) { 2388 1193 mws size_t len = strlen(nvpair_name(nvp)); 2389 1193 mws namelen = MAX(namelen, len); 2390 1193 mws } 2391 1193 mws 2392 1193 mws nvps = alloca(sizeof (nvpair_t *) * nvpslen); 2393 1193 mws name = alloca(namelen + 1); 2394 1193 mws 2395 1193 mws /* 2396 1193 mws * Store a snapshot of the name-value pairs in 'nvl' into nvps[] so 2397 1193 mws * that we can iterate over the original pairs in the loop below while 2398 1193 mws * performing arbitrary insert and delete operations on 'nvl' itself. 2399 1193 mws */ 2400 1193 mws for (i = 0, nvp = nvlist_next_nvpair(nvl, NULL); 2401 1193 mws nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) 2402 1193 mws nvps[i++] = nvp; 2403 1193 mws 2404 1193 mws /* 2405 1193 mws * Now iterate over the snapshot of the name-value pairs. If we find a 2406 1193 mws * value that is of type NVLIST or NVLIST_ARRAY, we translate that 2407 1193 mws * object by either calling ourself recursively on it, or calling into 2408 1193 mws * fmd_fmri_translate() if the object is an FMRI. We then rip out the 2409 1193 mws * original name-value pair and replace it with the translated one. 2410 1193 mws */ 2411 1193 mws for (i = 0; i < nvpslen; i++) { 2412 1193 mws nvp = nvps[i]; 2413 1193 mws type = nvpair_type(nvp); 2414 1193 mws 2415 1193 mws switch (type) { 2416 1193 mws case DATA_TYPE_NVLIST_ARRAY: 2417 1193 mws if (nvpair_value_nvlist_array(nvp, &a, &n) != 0 || 2418 1193 mws a == NULL || n == 0) 2419 1193 mws continue; /* array is zero-sized; skip it */ 2420 1193 mws 2421 1193 mws b = fmd_alloc(sizeof (nvlist_t *) * n, FMD_SLEEP); 2422 1193 mws 2423 1193 mws /* 2424 1193 mws * If the first array nvlist element looks like an FMRI 2425 1193 mws * then assume the other elements are FMRIs as well. 2426 1193 mws * If any b[j]'s can't be translated, then EINVAL will 2427 1193 mws * be returned from nvlist_add_nvlist_array() below. 2428 1193 mws */ 2429 1193 mws if (nvlist_lookup_string(*a, FM_FMRI_SCHEME, &s) == 0) { 2430 1193 mws for (j = 0; j < n; j++) 2431 1193 mws b[j] = fmd_fmri_translate(a[j], auth); 2432 1193 mws } else { 2433 1193 mws for (j = 0; j < n; j++) 2434 1193 mws b[j] = fmd_xprt_xtranslate(a[j], auth); 2435 1193 mws } 2436 1193 mws 2437 1193 mws (void) strcpy(name, nvpair_name(nvp)); 2438 1193 mws (void) nvlist_remove(nvl, name, type); 2439 1193 mws err = nvlist_add_nvlist_array(nvl, name, b, n); 2440 1193 mws 2441 1193 mws for (j = 0; j < n; j++) 2442 1193 mws nvlist_free(b[j]); 2443 1193 mws 2444 1193 mws fmd_free(b, sizeof (nvlist_t *) * n); 2445 1193 mws 2446 1193 mws if (err != 0) { 2447 1193 mws nvlist_free(nvl); 2448 1193 mws errno = err; 2449 1193 mws return (NULL); 2450 1193 mws } 2451 1193 mws break; 2452 1193 mws 2453 1193 mws case DATA_TYPE_NVLIST: 2454 1193 mws if (nvpair_value_nvlist(nvp, &l) == 0 && 2455 1193 mws nvlist_lookup_string(l, FM_FMRI_SCHEME, &s) == 0) 2456 1193 mws r = fmd_fmri_translate(l, auth); 2457 1193 mws else 2458 1193 mws r = fmd_xprt_xtranslate(l, auth); 2459 1193 mws 2460 1193 mws if (r == NULL) { 2461 1193 mws nvlist_free(nvl); 2462 1193 mws return (NULL); 2463 1193 mws } 2464 1193 mws 2465 1193 mws (void) strcpy(name, nvpair_name(nvp)); 2466 1193 mws (void) nvlist_remove(nvl, name, type); 2467 1193 mws (void) nvlist_add_nvlist(nvl, name, r); 2468 1193 mws 2469 1193 mws nvlist_free(r); 2470 1193 mws break; 2471 1193 mws } 2472 1193 mws } 2473 1193 mws 2474 1193 mws return (nvl); 2475 1193 mws } 2476 1193 mws 2477 1193 mws nvlist_t * 2478 1193 mws fmd_xprt_translate(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep) 2479 1193 mws { 2480 1193 mws fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp); 2481 1193 mws 2482 1193 mws if (xip->xi_auth == NULL) { 2483 1193 mws fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL, 2484 1193 mws "no authority defined for transport %p\n", (void *)xp); 2485 1193 mws } 2486 1193 mws 2487 1193 mws return (fmd_xprt_xtranslate(FMD_EVENT_NVL(ep), xip->xi_auth)); 2488 1193 mws } 2489 1193 mws 2490 9120 Stephen /*ARGSUSED*/ 2491 9120 Stephen void 2492 9120 Stephen fmd_xprt_add_domain(fmd_hdl_t *hdl, nvlist_t *nvl, char *domain) 2493 9120 Stephen { 2494 9120 Stephen nvpair_t *nvp, *nvp2; 2495 9120 Stephen nvlist_t *nvl2, *nvl3; 2496 9120 Stephen char *class; 2497 9120 Stephen 2498 9120 Stephen if (nvl == NULL || domain == NULL) 2499 9120 Stephen return; 2500 9120 Stephen for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2501 9120 Stephen nvp = nvlist_next_nvpair(nvl, nvp)) { 2502 9120 Stephen if (strcmp(nvpair_name(nvp), FM_CLASS) == 0) { 2503 9120 Stephen (void) nvpair_value_string(nvp, &class); 2504 9120 Stephen if (strcmp(class, FM_LIST_SUSPECT_CLASS) != 0) 2505 9120 Stephen return; 2506 9120 Stephen } 2507 9120 Stephen } 2508 9120 Stephen for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2509 9120 Stephen nvp = nvlist_next_nvpair(nvl, nvp)) { 2510 9120 Stephen if (strcmp(nvpair_name(nvp), FM_SUSPECT_DE) == 0) { 2511 9120 Stephen (void) nvpair_value_nvlist(nvp, &nvl2); 2512 9120 Stephen for (nvp2 = nvlist_next_nvpair(nvl2, NULL); 2513 9120 Stephen nvp2 != NULL; 2514 9120 Stephen nvp2 = nvlist_next_nvpair(nvl2, nvp2)) { 2515 9120 Stephen if (strcmp(nvpair_name(nvp2), 2516 9120 Stephen FM_FMRI_AUTHORITY) == 0) { 2517 9120 Stephen (void) nvpair_value_nvlist(nvp2, &nvl3); 2518 9120 Stephen (void) nvlist_add_string(nvl3, 2519 9120 Stephen FM_FMRI_AUTH_DOMAIN, domain); 2520 9120 Stephen break; 2521 9120 Stephen } 2522 9120 Stephen } 2523 9120 Stephen break; 2524 9120 Stephen } 2525 9120 Stephen } 2526 9120 Stephen } 2527 9120 Stephen 2528 1193 mws void 2529 1193 mws fmd_xprt_setspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp, void *data) 2530 1193 mws { 2531 1193 mws fmd_api_transport_impl(hdl, xp)->xi_data = data; 2532 1193 mws } 2533 1193 mws 2534 1193 mws void * 2535 1193 mws fmd_xprt_getspecific(fmd_hdl_t *hdl, fmd_xprt_t *xp) 2536 1193 mws { 2537 1193 mws return (fmd_api_transport_impl(hdl, xp)->xi_data); 2538 1193 mws } 2539