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