]> git.proxmox.com Git - mirror_zfs.git/blob - module/zfs/fm.c
Fix typo/etc in module/zfs/zfs_ctldir.c
[mirror_zfs.git] / module / zfs / fm.c
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * Fault Management Architecture (FMA) Resource and Protocol Support
27 *
28 * The routines contained herein provide services to support kernel subsystems
29 * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089).
30 *
31 * Name-Value Pair Lists
32 *
33 * The embodiment of an FMA protocol element (event, fmri or authority) is a
34 * name-value pair list (nvlist_t). FMA-specific nvlist construtor and
35 * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used
36 * to create an nvpair list using custom allocators. Callers may choose to
37 * allocate either from the kernel memory allocator, or from a preallocated
38 * buffer, useful in constrained contexts like high-level interrupt routines.
39 *
40 * Protocol Event and FMRI Construction
41 *
42 * Convenience routines are provided to construct nvlist events according to
43 * the FMA Event Protocol and Naming Schema specification for ereports and
44 * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes.
45 *
46 * ENA Manipulation
47 *
48 * Routines to generate ENA formats 0, 1 and 2 are available as well as
49 * routines to increment formats 1 and 2. Individual fields within the
50 * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(),
51 * fm_ena_format_get() and fm_ena_gen_get().
52 */
53
54 #include <sys/types.h>
55 #include <sys/time.h>
56 #include <sys/list.h>
57 #include <sys/nvpair.h>
58 #include <sys/cmn_err.h>
59 #include <sys/sysmacros.h>
60 #include <sys/sunddi.h>
61 #include <sys/systeminfo.h>
62 #include <sys/fm/util.h>
63 #include <sys/fm/protocol.h>
64 #include <sys/kstat.h>
65 #include <sys/zfs_context.h>
66 #ifdef _KERNEL
67 #include <sys/atomic.h>
68 #include <sys/condvar.h>
69 #include <sys/console.h>
70 #include <sys/kobj.h>
71 #include <sys/time.h>
72 #include <sys/zfs_ioctl.h>
73
74 int zfs_zevent_len_max = 0;
75 int zfs_zevent_cols = 80;
76 int zfs_zevent_console = 0;
77
78 static int zevent_len_cur = 0;
79 static int zevent_waiters = 0;
80 static int zevent_flags = 0;
81
82 /* Num events rate limited since the last time zfs_zevent_next() was called */
83 static uint64_t ratelimit_dropped = 0;
84
85 /*
86 * The EID (Event IDentifier) is used to uniquely tag a zevent when it is
87 * posted. The posted EIDs are monotonically increasing but not persistent.
88 * They will be reset to the initial value (1) each time the kernel module is
89 * loaded.
90 */
91 static uint64_t zevent_eid = 0;
92
93 static kmutex_t zevent_lock;
94 static list_t zevent_list;
95 static kcondvar_t zevent_cv;
96 #endif /* _KERNEL */
97
98
99 /*
100 * Common fault management kstats to record event generation failures
101 */
102
103 struct erpt_kstat {
104 kstat_named_t erpt_dropped; /* num erpts dropped on post */
105 kstat_named_t erpt_set_failed; /* num erpt set failures */
106 kstat_named_t fmri_set_failed; /* num fmri set failures */
107 kstat_named_t payload_set_failed; /* num payload set failures */
108 };
109
110 static struct erpt_kstat erpt_kstat_data = {
111 { "erpt-dropped", KSTAT_DATA_UINT64 },
112 { "erpt-set-failed", KSTAT_DATA_UINT64 },
113 { "fmri-set-failed", KSTAT_DATA_UINT64 },
114 { "payload-set-failed", KSTAT_DATA_UINT64 }
115 };
116
117 kstat_t *fm_ksp;
118
119 #ifdef _KERNEL
120
121 /*
122 * Formatting utility function for fm_nvprintr. We attempt to wrap chunks of
123 * output so they aren't split across console lines, and return the end column.
124 */
125 /*PRINTFLIKE4*/
126 static int
127 fm_printf(int depth, int c, int cols, const char *format, ...)
128 {
129 va_list ap;
130 int width;
131 char c1;
132
133 va_start(ap, format);
134 width = vsnprintf(&c1, sizeof (c1), format, ap);
135 va_end(ap);
136
137 if (c + width >= cols) {
138 console_printf("\n");
139 c = 0;
140 if (format[0] != ' ' && depth > 0) {
141 console_printf(" ");
142 c++;
143 }
144 }
145
146 va_start(ap, format);
147 console_vprintf(format, ap);
148 va_end(ap);
149
150 return ((c + width) % cols);
151 }
152
153 /*
154 * Recursively print an nvlist in the specified column width and return the
155 * column we end up in. This function is called recursively by fm_nvprint(),
156 * below. We generically format the entire nvpair using hexadecimal
157 * integers and strings, and elide any integer arrays. Arrays are basically
158 * used for cache dumps right now, so we suppress them so as not to overwhelm
159 * the amount of console output we produce at panic time. This can be further
160 * enhanced as FMA technology grows based upon the needs of consumers. All
161 * FMA telemetry is logged using the dump device transport, so the console
162 * output serves only as a fallback in case this procedure is unsuccessful.
163 */
164 static int
165 fm_nvprintr(nvlist_t *nvl, int d, int c, int cols)
166 {
167 nvpair_t *nvp;
168
169 for (nvp = nvlist_next_nvpair(nvl, NULL);
170 nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
171
172 data_type_t type = nvpair_type(nvp);
173 const char *name = nvpair_name(nvp);
174
175 boolean_t b;
176 uint8_t i8;
177 uint16_t i16;
178 uint32_t i32;
179 uint64_t i64;
180 char *str;
181 nvlist_t *cnv;
182
183 if (strcmp(name, FM_CLASS) == 0)
184 continue; /* already printed by caller */
185
186 c = fm_printf(d, c, cols, " %s=", name);
187
188 switch (type) {
189 case DATA_TYPE_BOOLEAN:
190 c = fm_printf(d + 1, c, cols, " 1");
191 break;
192
193 case DATA_TYPE_BOOLEAN_VALUE:
194 (void) nvpair_value_boolean_value(nvp, &b);
195 c = fm_printf(d + 1, c, cols, b ? "1" : "0");
196 break;
197
198 case DATA_TYPE_BYTE:
199 (void) nvpair_value_byte(nvp, &i8);
200 c = fm_printf(d + 1, c, cols, "0x%x", i8);
201 break;
202
203 case DATA_TYPE_INT8:
204 (void) nvpair_value_int8(nvp, (void *)&i8);
205 c = fm_printf(d + 1, c, cols, "0x%x", i8);
206 break;
207
208 case DATA_TYPE_UINT8:
209 (void) nvpair_value_uint8(nvp, &i8);
210 c = fm_printf(d + 1, c, cols, "0x%x", i8);
211 break;
212
213 case DATA_TYPE_INT16:
214 (void) nvpair_value_int16(nvp, (void *)&i16);
215 c = fm_printf(d + 1, c, cols, "0x%x", i16);
216 break;
217
218 case DATA_TYPE_UINT16:
219 (void) nvpair_value_uint16(nvp, &i16);
220 c = fm_printf(d + 1, c, cols, "0x%x", i16);
221 break;
222
223 case DATA_TYPE_INT32:
224 (void) nvpair_value_int32(nvp, (void *)&i32);
225 c = fm_printf(d + 1, c, cols, "0x%x", i32);
226 break;
227
228 case DATA_TYPE_UINT32:
229 (void) nvpair_value_uint32(nvp, &i32);
230 c = fm_printf(d + 1, c, cols, "0x%x", i32);
231 break;
232
233 case DATA_TYPE_INT64:
234 (void) nvpair_value_int64(nvp, (void *)&i64);
235 c = fm_printf(d + 1, c, cols, "0x%llx",
236 (u_longlong_t)i64);
237 break;
238
239 case DATA_TYPE_UINT64:
240 (void) nvpair_value_uint64(nvp, &i64);
241 c = fm_printf(d + 1, c, cols, "0x%llx",
242 (u_longlong_t)i64);
243 break;
244
245 case DATA_TYPE_HRTIME:
246 (void) nvpair_value_hrtime(nvp, (void *)&i64);
247 c = fm_printf(d + 1, c, cols, "0x%llx",
248 (u_longlong_t)i64);
249 break;
250
251 case DATA_TYPE_STRING:
252 (void) nvpair_value_string(nvp, &str);
253 c = fm_printf(d + 1, c, cols, "\"%s\"",
254 str ? str : "<NULL>");
255 break;
256
257 case DATA_TYPE_NVLIST:
258 c = fm_printf(d + 1, c, cols, "[");
259 (void) nvpair_value_nvlist(nvp, &cnv);
260 c = fm_nvprintr(cnv, d + 1, c, cols);
261 c = fm_printf(d + 1, c, cols, " ]");
262 break;
263
264 case DATA_TYPE_NVLIST_ARRAY: {
265 nvlist_t **val;
266 uint_t i, nelem;
267
268 c = fm_printf(d + 1, c, cols, "[");
269 (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
270 for (i = 0; i < nelem; i++) {
271 c = fm_nvprintr(val[i], d + 1, c, cols);
272 }
273 c = fm_printf(d + 1, c, cols, " ]");
274 }
275 break;
276
277 case DATA_TYPE_INT8_ARRAY: {
278 int8_t *val;
279 uint_t i, nelem;
280
281 c = fm_printf(d + 1, c, cols, "[ ");
282 (void) nvpair_value_int8_array(nvp, &val, &nelem);
283 for (i = 0; i < nelem; i++)
284 c = fm_printf(d + 1, c, cols, "0x%llx ",
285 (u_longlong_t)val[i]);
286
287 c = fm_printf(d + 1, c, cols, "]");
288 break;
289 }
290
291 case DATA_TYPE_UINT8_ARRAY: {
292 uint8_t *val;
293 uint_t i, nelem;
294
295 c = fm_printf(d + 1, c, cols, "[ ");
296 (void) nvpair_value_uint8_array(nvp, &val, &nelem);
297 for (i = 0; i < nelem; i++)
298 c = fm_printf(d + 1, c, cols, "0x%llx ",
299 (u_longlong_t)val[i]);
300
301 c = fm_printf(d + 1, c, cols, "]");
302 break;
303 }
304
305 case DATA_TYPE_INT16_ARRAY: {
306 int16_t *val;
307 uint_t i, nelem;
308
309 c = fm_printf(d + 1, c, cols, "[ ");
310 (void) nvpair_value_int16_array(nvp, &val, &nelem);
311 for (i = 0; i < nelem; i++)
312 c = fm_printf(d + 1, c, cols, "0x%llx ",
313 (u_longlong_t)val[i]);
314
315 c = fm_printf(d + 1, c, cols, "]");
316 break;
317 }
318
319 case DATA_TYPE_UINT16_ARRAY: {
320 uint16_t *val;
321 uint_t i, nelem;
322
323 c = fm_printf(d + 1, c, cols, "[ ");
324 (void) nvpair_value_uint16_array(nvp, &val, &nelem);
325 for (i = 0; i < nelem; i++)
326 c = fm_printf(d + 1, c, cols, "0x%llx ",
327 (u_longlong_t)val[i]);
328
329 c = fm_printf(d + 1, c, cols, "]");
330 break;
331 }
332
333 case DATA_TYPE_INT32_ARRAY: {
334 int32_t *val;
335 uint_t i, nelem;
336
337 c = fm_printf(d + 1, c, cols, "[ ");
338 (void) nvpair_value_int32_array(nvp, &val, &nelem);
339 for (i = 0; i < nelem; i++)
340 c = fm_printf(d + 1, c, cols, "0x%llx ",
341 (u_longlong_t)val[i]);
342
343 c = fm_printf(d + 1, c, cols, "]");
344 break;
345 }
346
347 case DATA_TYPE_UINT32_ARRAY: {
348 uint32_t *val;
349 uint_t i, nelem;
350
351 c = fm_printf(d + 1, c, cols, "[ ");
352 (void) nvpair_value_uint32_array(nvp, &val, &nelem);
353 for (i = 0; i < nelem; i++)
354 c = fm_printf(d + 1, c, cols, "0x%llx ",
355 (u_longlong_t)val[i]);
356
357 c = fm_printf(d + 1, c, cols, "]");
358 break;
359 }
360
361 case DATA_TYPE_INT64_ARRAY: {
362 int64_t *val;
363 uint_t i, nelem;
364
365 c = fm_printf(d + 1, c, cols, "[ ");
366 (void) nvpair_value_int64_array(nvp, &val, &nelem);
367 for (i = 0; i < nelem; i++)
368 c = fm_printf(d + 1, c, cols, "0x%llx ",
369 (u_longlong_t)val[i]);
370
371 c = fm_printf(d + 1, c, cols, "]");
372 break;
373 }
374
375 case DATA_TYPE_UINT64_ARRAY: {
376 uint64_t *val;
377 uint_t i, nelem;
378
379 c = fm_printf(d + 1, c, cols, "[ ");
380 (void) nvpair_value_uint64_array(nvp, &val, &nelem);
381 for (i = 0; i < nelem; i++)
382 c = fm_printf(d + 1, c, cols, "0x%llx ",
383 (u_longlong_t)val[i]);
384
385 c = fm_printf(d + 1, c, cols, "]");
386 break;
387 }
388
389 case DATA_TYPE_STRING_ARRAY:
390 case DATA_TYPE_BOOLEAN_ARRAY:
391 case DATA_TYPE_BYTE_ARRAY:
392 c = fm_printf(d + 1, c, cols, "[...]");
393 break;
394
395 case DATA_TYPE_UNKNOWN:
396 case DATA_TYPE_DONTCARE:
397 c = fm_printf(d + 1, c, cols, "<unknown>");
398 break;
399 }
400 }
401
402 return (c);
403 }
404
405 void
406 fm_nvprint(nvlist_t *nvl)
407 {
408 char *class;
409 int c = 0;
410
411 console_printf("\n");
412
413 if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0)
414 c = fm_printf(0, c, zfs_zevent_cols, "%s", class);
415
416 if (fm_nvprintr(nvl, 0, c, zfs_zevent_cols) != 0)
417 console_printf("\n");
418
419 console_printf("\n");
420 }
421
422 static zevent_t *
423 zfs_zevent_alloc(void)
424 {
425 zevent_t *ev;
426
427 ev = kmem_zalloc(sizeof (zevent_t), KM_SLEEP);
428
429 list_create(&ev->ev_ze_list, sizeof (zfs_zevent_t),
430 offsetof(zfs_zevent_t, ze_node));
431 list_link_init(&ev->ev_node);
432
433 return (ev);
434 }
435
436 static void
437 zfs_zevent_free(zevent_t *ev)
438 {
439 /* Run provided cleanup callback */
440 ev->ev_cb(ev->ev_nvl, ev->ev_detector);
441
442 list_destroy(&ev->ev_ze_list);
443 kmem_free(ev, sizeof (zevent_t));
444 }
445
446 static void
447 zfs_zevent_drain(zevent_t *ev)
448 {
449 zfs_zevent_t *ze;
450
451 ASSERT(MUTEX_HELD(&zevent_lock));
452 list_remove(&zevent_list, ev);
453
454 /* Remove references to this event in all private file data */
455 while ((ze = list_head(&ev->ev_ze_list)) != NULL) {
456 list_remove(&ev->ev_ze_list, ze);
457 ze->ze_zevent = NULL;
458 ze->ze_dropped++;
459 }
460
461 zfs_zevent_free(ev);
462 }
463
464 void
465 zfs_zevent_drain_all(int *count)
466 {
467 zevent_t *ev;
468
469 mutex_enter(&zevent_lock);
470 while ((ev = list_head(&zevent_list)) != NULL)
471 zfs_zevent_drain(ev);
472
473 *count = zevent_len_cur;
474 zevent_len_cur = 0;
475 mutex_exit(&zevent_lock);
476 }
477
478 /*
479 * New zevents are inserted at the head. If the maximum queue
480 * length is exceeded a zevent will be drained from the tail.
481 * As part of this any user space processes which currently have
482 * a reference to this zevent_t in their private data will have
483 * this reference set to NULL.
484 */
485 static void
486 zfs_zevent_insert(zevent_t *ev)
487 {
488 ASSERT(MUTEX_HELD(&zevent_lock));
489 list_insert_head(&zevent_list, ev);
490
491 if (zevent_len_cur >= zfs_zevent_len_max)
492 zfs_zevent_drain(list_tail(&zevent_list));
493 else
494 zevent_len_cur++;
495 }
496
497 /*
498 * Post a zevent. The cb will be called when nvl and detector are no longer
499 * needed, i.e.:
500 * - An error happened and a zevent can't be posted. In this case, cb is called
501 * before zfs_zevent_post() returns.
502 * - The event is being drained and freed.
503 */
504 int
505 zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
506 {
507 inode_timespec_t tv;
508 int64_t tv_array[2];
509 uint64_t eid;
510 size_t nvl_size = 0;
511 zevent_t *ev;
512 int error;
513
514 ASSERT(cb != NULL);
515
516 gethrestime(&tv);
517 tv_array[0] = tv.tv_sec;
518 tv_array[1] = tv.tv_nsec;
519
520 error = nvlist_add_int64_array(nvl, FM_EREPORT_TIME, tv_array, 2);
521 if (error) {
522 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
523 goto out;
524 }
525
526 eid = atomic_inc_64_nv(&zevent_eid);
527 error = nvlist_add_uint64(nvl, FM_EREPORT_EID, eid);
528 if (error) {
529 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
530 goto out;
531 }
532
533 error = nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE);
534 if (error) {
535 atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
536 goto out;
537 }
538
539 if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) {
540 atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
541 error = EOVERFLOW;
542 goto out;
543 }
544
545 if (zfs_zevent_console)
546 fm_nvprint(nvl);
547
548 ev = zfs_zevent_alloc();
549 if (ev == NULL) {
550 atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
551 error = ENOMEM;
552 goto out;
553 }
554
555 ev->ev_nvl = nvl;
556 ev->ev_detector = detector;
557 ev->ev_cb = cb;
558 ev->ev_eid = eid;
559
560 mutex_enter(&zevent_lock);
561 zfs_zevent_insert(ev);
562 cv_broadcast(&zevent_cv);
563 mutex_exit(&zevent_lock);
564
565 out:
566 if (error)
567 cb(nvl, detector);
568
569 return (error);
570 }
571
572 static int
573 zfs_zevent_minor_to_state(minor_t minor, zfs_zevent_t **ze)
574 {
575 *ze = zfsdev_get_state(minor, ZST_ZEVENT);
576 if (*ze == NULL)
577 return (SET_ERROR(EBADF));
578
579 return (0);
580 }
581
582 int
583 zfs_zevent_fd_hold(int fd, minor_t *minorp, zfs_zevent_t **ze)
584 {
585 file_t *fp;
586 int error;
587
588 fp = getf(fd);
589 if (fp == NULL)
590 return (SET_ERROR(EBADF));
591
592 error = zfsdev_getminor(fp->f_file, minorp);
593 if (error == 0)
594 error = zfs_zevent_minor_to_state(*minorp, ze);
595
596 if (error)
597 zfs_zevent_fd_rele(fd);
598
599 return (error);
600 }
601
602 void
603 zfs_zevent_fd_rele(int fd)
604 {
605 releasef(fd);
606 }
607
608 /*
609 * Get the next zevent in the stream and place a copy in 'event'. This
610 * may fail with ENOMEM if the encoded nvlist size exceeds the passed
611 * 'event_size'. In this case the stream pointer is not advanced and
612 * and 'event_size' is set to the minimum required buffer size.
613 */
614 int
615 zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *event_size,
616 uint64_t *dropped)
617 {
618 zevent_t *ev;
619 size_t size;
620 int error = 0;
621
622 mutex_enter(&zevent_lock);
623 if (ze->ze_zevent == NULL) {
624 /* New stream start at the beginning/tail */
625 ev = list_tail(&zevent_list);
626 if (ev == NULL) {
627 error = ENOENT;
628 goto out;
629 }
630 } else {
631 /*
632 * Existing stream continue with the next element and remove
633 * ourselves from the wait queue for the previous element
634 */
635 ev = list_prev(&zevent_list, ze->ze_zevent);
636 if (ev == NULL) {
637 error = ENOENT;
638 goto out;
639 }
640 }
641
642 VERIFY(nvlist_size(ev->ev_nvl, &size, NV_ENCODE_NATIVE) == 0);
643 if (size > *event_size) {
644 *event_size = size;
645 error = ENOMEM;
646 goto out;
647 }
648
649 if (ze->ze_zevent)
650 list_remove(&ze->ze_zevent->ev_ze_list, ze);
651
652 ze->ze_zevent = ev;
653 list_insert_head(&ev->ev_ze_list, ze);
654 (void) nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
655 *dropped = ze->ze_dropped;
656
657 #ifdef _KERNEL
658 /* Include events dropped due to rate limiting */
659 *dropped += ratelimit_dropped;
660 ratelimit_dropped = 0;
661 #endif
662 ze->ze_dropped = 0;
663 out:
664 mutex_exit(&zevent_lock);
665
666 return (error);
667 }
668
669 /*
670 * Wait in an interruptible state for any new events.
671 */
672 int
673 zfs_zevent_wait(zfs_zevent_t *ze)
674 {
675 int error = EAGAIN;
676
677 mutex_enter(&zevent_lock);
678 zevent_waiters++;
679
680 while (error == EAGAIN) {
681 if (zevent_flags & ZEVENT_SHUTDOWN) {
682 error = SET_ERROR(ESHUTDOWN);
683 break;
684 }
685
686 error = cv_timedwait_sig(&zevent_cv, &zevent_lock,
687 ddi_get_lbolt() + MSEC_TO_TICK(10));
688 if (signal_pending(current)) {
689 error = SET_ERROR(EINTR);
690 break;
691 } else if (!list_is_empty(&zevent_list)) {
692 error = 0;
693 continue;
694 } else {
695 error = EAGAIN;
696 }
697 }
698
699 zevent_waiters--;
700 mutex_exit(&zevent_lock);
701
702 return (error);
703 }
704
705 /*
706 * The caller may seek to a specific EID by passing that EID. If the EID
707 * is still available in the posted list of events the cursor is positioned
708 * there. Otherwise ENOENT is returned and the cursor is not moved.
709 *
710 * There are two reserved EIDs which may be passed and will never fail.
711 * ZEVENT_SEEK_START positions the cursor at the start of the list, and
712 * ZEVENT_SEEK_END positions the cursor at the end of the list.
713 */
714 int
715 zfs_zevent_seek(zfs_zevent_t *ze, uint64_t eid)
716 {
717 zevent_t *ev;
718 int error = 0;
719
720 mutex_enter(&zevent_lock);
721
722 if (eid == ZEVENT_SEEK_START) {
723 if (ze->ze_zevent)
724 list_remove(&ze->ze_zevent->ev_ze_list, ze);
725
726 ze->ze_zevent = NULL;
727 goto out;
728 }
729
730 if (eid == ZEVENT_SEEK_END) {
731 if (ze->ze_zevent)
732 list_remove(&ze->ze_zevent->ev_ze_list, ze);
733
734 ev = list_head(&zevent_list);
735 if (ev) {
736 ze->ze_zevent = ev;
737 list_insert_head(&ev->ev_ze_list, ze);
738 } else {
739 ze->ze_zevent = NULL;
740 }
741
742 goto out;
743 }
744
745 for (ev = list_tail(&zevent_list); ev != NULL;
746 ev = list_prev(&zevent_list, ev)) {
747 if (ev->ev_eid == eid) {
748 if (ze->ze_zevent)
749 list_remove(&ze->ze_zevent->ev_ze_list, ze);
750
751 ze->ze_zevent = ev;
752 list_insert_head(&ev->ev_ze_list, ze);
753 break;
754 }
755 }
756
757 if (ev == NULL)
758 error = ENOENT;
759
760 out:
761 mutex_exit(&zevent_lock);
762
763 return (error);
764 }
765
766 void
767 zfs_zevent_init(zfs_zevent_t **zep)
768 {
769 zfs_zevent_t *ze;
770
771 ze = *zep = kmem_zalloc(sizeof (zfs_zevent_t), KM_SLEEP);
772 list_link_init(&ze->ze_node);
773 }
774
775 void
776 zfs_zevent_destroy(zfs_zevent_t *ze)
777 {
778 mutex_enter(&zevent_lock);
779 if (ze->ze_zevent)
780 list_remove(&ze->ze_zevent->ev_ze_list, ze);
781 mutex_exit(&zevent_lock);
782
783 kmem_free(ze, sizeof (zfs_zevent_t));
784 }
785 #endif /* _KERNEL */
786
787 /*
788 * Wrapppers for FM nvlist allocators
789 */
790 /* ARGSUSED */
791 static void *
792 i_fm_alloc(nv_alloc_t *nva, size_t size)
793 {
794 return (kmem_zalloc(size, KM_SLEEP));
795 }
796
797 /* ARGSUSED */
798 static void
799 i_fm_free(nv_alloc_t *nva, void *buf, size_t size)
800 {
801 kmem_free(buf, size);
802 }
803
804 const nv_alloc_ops_t fm_mem_alloc_ops = {
805 .nv_ao_init = NULL,
806 .nv_ao_fini = NULL,
807 .nv_ao_alloc = i_fm_alloc,
808 .nv_ao_free = i_fm_free,
809 .nv_ao_reset = NULL
810 };
811
812 /*
813 * Create and initialize a new nv_alloc_t for a fixed buffer, buf. A pointer
814 * to the newly allocated nv_alloc_t structure is returned upon success or NULL
815 * is returned to indicate that the nv_alloc structure could not be created.
816 */
817 nv_alloc_t *
818 fm_nva_xcreate(char *buf, size_t bufsz)
819 {
820 nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
821
822 if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) {
823 kmem_free(nvhdl, sizeof (nv_alloc_t));
824 return (NULL);
825 }
826
827 return (nvhdl);
828 }
829
830 /*
831 * Destroy a previously allocated nv_alloc structure. The fixed buffer
832 * associated with nva must be freed by the caller.
833 */
834 void
835 fm_nva_xdestroy(nv_alloc_t *nva)
836 {
837 nv_alloc_fini(nva);
838 kmem_free(nva, sizeof (nv_alloc_t));
839 }
840
841 /*
842 * Create a new nv list. A pointer to a new nv list structure is returned
843 * upon success or NULL is returned to indicate that the structure could
844 * not be created. The newly created nv list is created and managed by the
845 * operations installed in nva. If nva is NULL, the default FMA nva
846 * operations are installed and used.
847 *
848 * When called from the kernel and nva == NULL, this function must be called
849 * from passive kernel context with no locks held that can prevent a
850 * sleeping memory allocation from occurring. Otherwise, this function may
851 * be called from other kernel contexts as long a valid nva created via
852 * fm_nva_create() is supplied.
853 */
854 nvlist_t *
855 fm_nvlist_create(nv_alloc_t *nva)
856 {
857 int hdl_alloced = 0;
858 nvlist_t *nvl;
859 nv_alloc_t *nvhdl;
860
861 if (nva == NULL) {
862 nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
863
864 if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) {
865 kmem_free(nvhdl, sizeof (nv_alloc_t));
866 return (NULL);
867 }
868 hdl_alloced = 1;
869 } else {
870 nvhdl = nva;
871 }
872
873 if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) {
874 if (hdl_alloced) {
875 nv_alloc_fini(nvhdl);
876 kmem_free(nvhdl, sizeof (nv_alloc_t));
877 }
878 return (NULL);
879 }
880
881 return (nvl);
882 }
883
884 /*
885 * Destroy a previously allocated nvlist structure. flag indicates whether
886 * or not the associated nva structure should be freed (FM_NVA_FREE) or
887 * retained (FM_NVA_RETAIN). Retaining the nv alloc structure allows
888 * it to be re-used for future nvlist creation operations.
889 */
890 void
891 fm_nvlist_destroy(nvlist_t *nvl, int flag)
892 {
893 nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
894
895 nvlist_free(nvl);
896
897 if (nva != NULL) {
898 if (flag == FM_NVA_FREE)
899 fm_nva_xdestroy(nva);
900 }
901 }
902
903 int
904 i_fm_payload_set(nvlist_t *payload, const char *name, va_list ap)
905 {
906 int nelem, ret = 0;
907 data_type_t type;
908
909 while (ret == 0 && name != NULL) {
910 type = va_arg(ap, data_type_t);
911 switch (type) {
912 case DATA_TYPE_BYTE:
913 ret = nvlist_add_byte(payload, name,
914 va_arg(ap, uint_t));
915 break;
916 case DATA_TYPE_BYTE_ARRAY:
917 nelem = va_arg(ap, int);
918 ret = nvlist_add_byte_array(payload, name,
919 va_arg(ap, uchar_t *), nelem);
920 break;
921 case DATA_TYPE_BOOLEAN_VALUE:
922 ret = nvlist_add_boolean_value(payload, name,
923 va_arg(ap, boolean_t));
924 break;
925 case DATA_TYPE_BOOLEAN_ARRAY:
926 nelem = va_arg(ap, int);
927 ret = nvlist_add_boolean_array(payload, name,
928 va_arg(ap, boolean_t *), nelem);
929 break;
930 case DATA_TYPE_INT8:
931 ret = nvlist_add_int8(payload, name,
932 va_arg(ap, int));
933 break;
934 case DATA_TYPE_INT8_ARRAY:
935 nelem = va_arg(ap, int);
936 ret = nvlist_add_int8_array(payload, name,
937 va_arg(ap, int8_t *), nelem);
938 break;
939 case DATA_TYPE_UINT8:
940 ret = nvlist_add_uint8(payload, name,
941 va_arg(ap, uint_t));
942 break;
943 case DATA_TYPE_UINT8_ARRAY:
944 nelem = va_arg(ap, int);
945 ret = nvlist_add_uint8_array(payload, name,
946 va_arg(ap, uint8_t *), nelem);
947 break;
948 case DATA_TYPE_INT16:
949 ret = nvlist_add_int16(payload, name,
950 va_arg(ap, int));
951 break;
952 case DATA_TYPE_INT16_ARRAY:
953 nelem = va_arg(ap, int);
954 ret = nvlist_add_int16_array(payload, name,
955 va_arg(ap, int16_t *), nelem);
956 break;
957 case DATA_TYPE_UINT16:
958 ret = nvlist_add_uint16(payload, name,
959 va_arg(ap, uint_t));
960 break;
961 case DATA_TYPE_UINT16_ARRAY:
962 nelem = va_arg(ap, int);
963 ret = nvlist_add_uint16_array(payload, name,
964 va_arg(ap, uint16_t *), nelem);
965 break;
966 case DATA_TYPE_INT32:
967 ret = nvlist_add_int32(payload, name,
968 va_arg(ap, int32_t));
969 break;
970 case DATA_TYPE_INT32_ARRAY:
971 nelem = va_arg(ap, int);
972 ret = nvlist_add_int32_array(payload, name,
973 va_arg(ap, int32_t *), nelem);
974 break;
975 case DATA_TYPE_UINT32:
976 ret = nvlist_add_uint32(payload, name,
977 va_arg(ap, uint32_t));
978 break;
979 case DATA_TYPE_UINT32_ARRAY:
980 nelem = va_arg(ap, int);
981 ret = nvlist_add_uint32_array(payload, name,
982 va_arg(ap, uint32_t *), nelem);
983 break;
984 case DATA_TYPE_INT64:
985 ret = nvlist_add_int64(payload, name,
986 va_arg(ap, int64_t));
987 break;
988 case DATA_TYPE_INT64_ARRAY:
989 nelem = va_arg(ap, int);
990 ret = nvlist_add_int64_array(payload, name,
991 va_arg(ap, int64_t *), nelem);
992 break;
993 case DATA_TYPE_UINT64:
994 ret = nvlist_add_uint64(payload, name,
995 va_arg(ap, uint64_t));
996 break;
997 case DATA_TYPE_UINT64_ARRAY:
998 nelem = va_arg(ap, int);
999 ret = nvlist_add_uint64_array(payload, name,
1000 va_arg(ap, uint64_t *), nelem);
1001 break;
1002 case DATA_TYPE_STRING:
1003 ret = nvlist_add_string(payload, name,
1004 va_arg(ap, char *));
1005 break;
1006 case DATA_TYPE_STRING_ARRAY:
1007 nelem = va_arg(ap, int);
1008 ret = nvlist_add_string_array(payload, name,
1009 va_arg(ap, char **), nelem);
1010 break;
1011 case DATA_TYPE_NVLIST:
1012 ret = nvlist_add_nvlist(payload, name,
1013 va_arg(ap, nvlist_t *));
1014 break;
1015 case DATA_TYPE_NVLIST_ARRAY:
1016 nelem = va_arg(ap, int);
1017 ret = nvlist_add_nvlist_array(payload, name,
1018 va_arg(ap, nvlist_t **), nelem);
1019 break;
1020 default:
1021 ret = EINVAL;
1022 }
1023
1024 name = va_arg(ap, char *);
1025 }
1026 return (ret);
1027 }
1028
1029 void
1030 fm_payload_set(nvlist_t *payload, ...)
1031 {
1032 int ret;
1033 const char *name;
1034 va_list ap;
1035
1036 va_start(ap, payload);
1037 name = va_arg(ap, char *);
1038 ret = i_fm_payload_set(payload, name, ap);
1039 va_end(ap);
1040
1041 if (ret)
1042 atomic_inc_64(&erpt_kstat_data.payload_set_failed.value.ui64);
1043 }
1044
1045 /*
1046 * Set-up and validate the members of an ereport event according to:
1047 *
1048 * Member name Type Value
1049 * ====================================================
1050 * class string ereport
1051 * version uint8_t 0
1052 * ena uint64_t <ena>
1053 * detector nvlist_t <detector>
1054 * ereport-payload nvlist_t <var args>
1055 *
1056 * We don't actually add a 'version' member to the payload. Really,
1057 * the version quoted to us by our caller is that of the category 1
1058 * "ereport" event class (and we require FM_EREPORT_VERS0) but
1059 * the payload version of the actual leaf class event under construction
1060 * may be something else. Callers should supply a version in the varargs,
1061 * or (better) we could take two version arguments - one for the
1062 * ereport category 1 classification (expect FM_EREPORT_VERS0) and one
1063 * for the leaf class.
1064 */
1065 void
1066 fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
1067 uint64_t ena, const nvlist_t *detector, ...)
1068 {
1069 char ereport_class[FM_MAX_CLASS];
1070 const char *name;
1071 va_list ap;
1072 int ret;
1073
1074 if (version != FM_EREPORT_VERS0) {
1075 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
1076 return;
1077 }
1078
1079 (void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s",
1080 FM_EREPORT_CLASS, erpt_class);
1081 if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) {
1082 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
1083 return;
1084 }
1085
1086 if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) {
1087 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
1088 }
1089
1090 if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR,
1091 (nvlist_t *)detector) != 0) {
1092 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
1093 }
1094
1095 va_start(ap, detector);
1096 name = va_arg(ap, const char *);
1097 ret = i_fm_payload_set(ereport, name, ap);
1098 va_end(ap);
1099
1100 if (ret)
1101 atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
1102 }
1103
1104 /*
1105 * Set-up and validate the members of an hc fmri according to;
1106 *
1107 * Member name Type Value
1108 * ===================================================
1109 * version uint8_t 0
1110 * auth nvlist_t <auth>
1111 * hc-name string <name>
1112 * hc-id string <id>
1113 *
1114 * Note that auth and hc-id are optional members.
1115 */
1116
1117 #define HC_MAXPAIRS 20
1118 #define HC_MAXNAMELEN 50
1119
1120 static int
1121 fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth)
1122 {
1123 if (version != FM_HC_SCHEME_VERSION) {
1124 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1125 return (0);
1126 }
1127
1128 if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 ||
1129 nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) {
1130 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1131 return (0);
1132 }
1133
1134 if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
1135 (nvlist_t *)auth) != 0) {
1136 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1137 return (0);
1138 }
1139
1140 return (1);
1141 }
1142
1143 void
1144 fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
1145 nvlist_t *snvl, int npairs, ...)
1146 {
1147 nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
1148 nvlist_t *pairs[HC_MAXPAIRS];
1149 va_list ap;
1150 int i;
1151
1152 if (!fm_fmri_hc_set_common(fmri, version, auth))
1153 return;
1154
1155 npairs = MIN(npairs, HC_MAXPAIRS);
1156
1157 va_start(ap, npairs);
1158 for (i = 0; i < npairs; i++) {
1159 const char *name = va_arg(ap, const char *);
1160 uint32_t id = va_arg(ap, uint32_t);
1161 char idstr[11];
1162
1163 (void) snprintf(idstr, sizeof (idstr), "%u", id);
1164
1165 pairs[i] = fm_nvlist_create(nva);
1166 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
1167 nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
1168 atomic_inc_64(
1169 &erpt_kstat_data.fmri_set_failed.value.ui64);
1170 }
1171 }
1172 va_end(ap);
1173
1174 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0)
1175 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1176
1177 for (i = 0; i < npairs; i++)
1178 fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
1179
1180 if (snvl != NULL) {
1181 if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
1182 atomic_inc_64(
1183 &erpt_kstat_data.fmri_set_failed.value.ui64);
1184 }
1185 }
1186 }
1187
1188 void
1189 fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
1190 nvlist_t *snvl, nvlist_t *bboard, int npairs, ...)
1191 {
1192 nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
1193 nvlist_t *pairs[HC_MAXPAIRS];
1194 nvlist_t **hcl;
1195 uint_t n;
1196 int i, j;
1197 va_list ap;
1198 char *hcname, *hcid;
1199
1200 if (!fm_fmri_hc_set_common(fmri, version, auth))
1201 return;
1202
1203 /*
1204 * copy the bboard nvpairs to the pairs array
1205 */
1206 if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n)
1207 != 0) {
1208 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1209 return;
1210 }
1211
1212 for (i = 0; i < n; i++) {
1213 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
1214 &hcname) != 0) {
1215 atomic_inc_64(
1216 &erpt_kstat_data.fmri_set_failed.value.ui64);
1217 return;
1218 }
1219 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) {
1220 atomic_inc_64(
1221 &erpt_kstat_data.fmri_set_failed.value.ui64);
1222 return;
1223 }
1224
1225 pairs[i] = fm_nvlist_create(nva);
1226 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 ||
1227 nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) {
1228 for (j = 0; j <= i; j++) {
1229 if (pairs[j] != NULL)
1230 fm_nvlist_destroy(pairs[j],
1231 FM_NVA_RETAIN);
1232 }
1233 atomic_inc_64(
1234 &erpt_kstat_data.fmri_set_failed.value.ui64);
1235 return;
1236 }
1237 }
1238
1239 /*
1240 * create the pairs from passed in pairs
1241 */
1242 npairs = MIN(npairs, HC_MAXPAIRS);
1243
1244 va_start(ap, npairs);
1245 for (i = n; i < npairs + n; i++) {
1246 const char *name = va_arg(ap, const char *);
1247 uint32_t id = va_arg(ap, uint32_t);
1248 char idstr[11];
1249 (void) snprintf(idstr, sizeof (idstr), "%u", id);
1250 pairs[i] = fm_nvlist_create(nva);
1251 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
1252 nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
1253 for (j = 0; j <= i; j++) {
1254 if (pairs[j] != NULL)
1255 fm_nvlist_destroy(pairs[j],
1256 FM_NVA_RETAIN);
1257 }
1258 atomic_inc_64(
1259 &erpt_kstat_data.fmri_set_failed.value.ui64);
1260 return;
1261 }
1262 }
1263 va_end(ap);
1264
1265 /*
1266 * Create the fmri hc list
1267 */
1268 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs,
1269 npairs + n) != 0) {
1270 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1271 return;
1272 }
1273
1274 for (i = 0; i < npairs + n; i++) {
1275 fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
1276 }
1277
1278 if (snvl != NULL) {
1279 if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
1280 atomic_inc_64(
1281 &erpt_kstat_data.fmri_set_failed.value.ui64);
1282 return;
1283 }
1284 }
1285 }
1286
1287 /*
1288 * Set-up and validate the members of an dev fmri according to:
1289 *
1290 * Member name Type Value
1291 * ====================================================
1292 * version uint8_t 0
1293 * auth nvlist_t <auth>
1294 * devpath string <devpath>
1295 * [devid] string <devid>
1296 * [target-port-l0id] string <target-port-lun0-id>
1297 *
1298 * Note that auth and devid are optional members.
1299 */
1300 void
1301 fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
1302 const char *devpath, const char *devid, const char *tpl0)
1303 {
1304 int err = 0;
1305
1306 if (version != DEV_SCHEME_VERSION0) {
1307 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1308 return;
1309 }
1310
1311 err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version);
1312 err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV);
1313
1314 if (auth != NULL) {
1315 err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY,
1316 (nvlist_t *)auth);
1317 }
1318
1319 err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath);
1320
1321 if (devid != NULL)
1322 err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid);
1323
1324 if (tpl0 != NULL)
1325 err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0);
1326
1327 if (err)
1328 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1329
1330 }
1331
1332 /*
1333 * Set-up and validate the members of an cpu fmri according to:
1334 *
1335 * Member name Type Value
1336 * ====================================================
1337 * version uint8_t 0
1338 * auth nvlist_t <auth>
1339 * cpuid uint32_t <cpu_id>
1340 * cpumask uint8_t <cpu_mask>
1341 * serial uint64_t <serial_id>
1342 *
1343 * Note that auth, cpumask, serial are optional members.
1344 *
1345 */
1346 void
1347 fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
1348 uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp)
1349 {
1350 uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
1351
1352 if (version < CPU_SCHEME_VERSION1) {
1353 atomic_inc_64(failedp);
1354 return;
1355 }
1356
1357 if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
1358 atomic_inc_64(failedp);
1359 return;
1360 }
1361
1362 if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
1363 FM_FMRI_SCHEME_CPU) != 0) {
1364 atomic_inc_64(failedp);
1365 return;
1366 }
1367
1368 if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
1369 (nvlist_t *)auth) != 0)
1370 atomic_inc_64(failedp);
1371
1372 if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
1373 atomic_inc_64(failedp);
1374
1375 if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
1376 *cpu_maskp) != 0)
1377 atomic_inc_64(failedp);
1378
1379 if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
1380 FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
1381 atomic_inc_64(failedp);
1382 }
1383
1384 /*
1385 * Set-up and validate the members of a mem according to:
1386 *
1387 * Member name Type Value
1388 * ====================================================
1389 * version uint8_t 0
1390 * auth nvlist_t <auth> [optional]
1391 * unum string <unum>
1392 * serial string <serial> [optional*]
1393 * offset uint64_t <offset> [optional]
1394 *
1395 * * serial is required if offset is present
1396 */
1397 void
1398 fm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth,
1399 const char *unum, const char *serial, uint64_t offset)
1400 {
1401 if (version != MEM_SCHEME_VERSION0) {
1402 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1403 return;
1404 }
1405
1406 if (!serial && (offset != (uint64_t)-1)) {
1407 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1408 return;
1409 }
1410
1411 if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
1412 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1413 return;
1414 }
1415
1416 if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) {
1417 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1418 return;
1419 }
1420
1421 if (auth != NULL) {
1422 if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
1423 (nvlist_t *)auth) != 0) {
1424 atomic_inc_64(
1425 &erpt_kstat_data.fmri_set_failed.value.ui64);
1426 }
1427 }
1428
1429 if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) {
1430 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1431 }
1432
1433 if (serial != NULL) {
1434 if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
1435 (char **)&serial, 1) != 0) {
1436 atomic_inc_64(
1437 &erpt_kstat_data.fmri_set_failed.value.ui64);
1438 }
1439 if (offset != (uint64_t)-1 && nvlist_add_uint64(fmri,
1440 FM_FMRI_MEM_OFFSET, offset) != 0) {
1441 atomic_inc_64(
1442 &erpt_kstat_data.fmri_set_failed.value.ui64);
1443 }
1444 }
1445 }
1446
1447 void
1448 fm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid,
1449 uint64_t vdev_guid)
1450 {
1451 if (version != ZFS_SCHEME_VERSION0) {
1452 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1453 return;
1454 }
1455
1456 if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
1457 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1458 return;
1459 }
1460
1461 if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) {
1462 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1463 return;
1464 }
1465
1466 if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) {
1467 atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
1468 }
1469
1470 if (vdev_guid != 0) {
1471 if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) {
1472 atomic_inc_64(
1473 &erpt_kstat_data.fmri_set_failed.value.ui64);
1474 }
1475 }
1476 }
1477
1478 uint64_t
1479 fm_ena_increment(uint64_t ena)
1480 {
1481 uint64_t new_ena;
1482
1483 switch (ENA_FORMAT(ena)) {
1484 case FM_ENA_FMT1:
1485 new_ena = ena + (1 << ENA_FMT1_GEN_SHFT);
1486 break;
1487 case FM_ENA_FMT2:
1488 new_ena = ena + (1 << ENA_FMT2_GEN_SHFT);
1489 break;
1490 default:
1491 new_ena = 0;
1492 }
1493
1494 return (new_ena);
1495 }
1496
1497 uint64_t
1498 fm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format)
1499 {
1500 uint64_t ena = 0;
1501
1502 switch (format) {
1503 case FM_ENA_FMT1:
1504 if (timestamp) {
1505 ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1506 ((cpuid << ENA_FMT1_CPUID_SHFT) &
1507 ENA_FMT1_CPUID_MASK) |
1508 ((timestamp << ENA_FMT1_TIME_SHFT) &
1509 ENA_FMT1_TIME_MASK));
1510 } else {
1511 ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1512 ((cpuid << ENA_FMT1_CPUID_SHFT) &
1513 ENA_FMT1_CPUID_MASK) |
1514 ((gethrtime() << ENA_FMT1_TIME_SHFT) &
1515 ENA_FMT1_TIME_MASK));
1516 }
1517 break;
1518 case FM_ENA_FMT2:
1519 ena = (uint64_t)((format & ENA_FORMAT_MASK) |
1520 ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK));
1521 break;
1522 default:
1523 break;
1524 }
1525
1526 return (ena);
1527 }
1528
1529 uint64_t
1530 fm_ena_generate(uint64_t timestamp, uchar_t format)
1531 {
1532 uint64_t ena;
1533
1534 kpreempt_disable();
1535 ena = fm_ena_generate_cpu(timestamp, getcpuid(), format);
1536 kpreempt_enable();
1537
1538 return (ena);
1539 }
1540
1541 uint64_t
1542 fm_ena_generation_get(uint64_t ena)
1543 {
1544 uint64_t gen;
1545
1546 switch (ENA_FORMAT(ena)) {
1547 case FM_ENA_FMT1:
1548 gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT;
1549 break;
1550 case FM_ENA_FMT2:
1551 gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT;
1552 break;
1553 default:
1554 gen = 0;
1555 break;
1556 }
1557
1558 return (gen);
1559 }
1560
1561 uchar_t
1562 fm_ena_format_get(uint64_t ena)
1563 {
1564
1565 return (ENA_FORMAT(ena));
1566 }
1567
1568 uint64_t
1569 fm_ena_id_get(uint64_t ena)
1570 {
1571 uint64_t id;
1572
1573 switch (ENA_FORMAT(ena)) {
1574 case FM_ENA_FMT1:
1575 id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT;
1576 break;
1577 case FM_ENA_FMT2:
1578 id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT;
1579 break;
1580 default:
1581 id = 0;
1582 }
1583
1584 return (id);
1585 }
1586
1587 uint64_t
1588 fm_ena_time_get(uint64_t ena)
1589 {
1590 uint64_t time;
1591
1592 switch (ENA_FORMAT(ena)) {
1593 case FM_ENA_FMT1:
1594 time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT;
1595 break;
1596 case FM_ENA_FMT2:
1597 time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT;
1598 break;
1599 default:
1600 time = 0;
1601 }
1602
1603 return (time);
1604 }
1605
1606 #ifdef _KERNEL
1607 /*
1608 * Helper function to increment ereport dropped count. Used by the event
1609 * rate limiting code to give feedback to the user about how many events were
1610 * rate limited by including them in the 'dropped' count.
1611 */
1612 void
1613 fm_erpt_dropped_increment(void)
1614 {
1615 atomic_inc_64(&ratelimit_dropped);
1616 }
1617 #endif
1618
1619 #ifdef _KERNEL
1620 void
1621 fm_init(void)
1622 {
1623 zevent_len_cur = 0;
1624 zevent_flags = 0;
1625
1626 if (zfs_zevent_len_max == 0)
1627 zfs_zevent_len_max = ERPT_MAX_ERRS * MAX(max_ncpus, 4);
1628
1629 /* Initialize zevent allocation and generation kstats */
1630 fm_ksp = kstat_create("zfs", 0, "fm", "misc", KSTAT_TYPE_NAMED,
1631 sizeof (struct erpt_kstat) / sizeof (kstat_named_t),
1632 KSTAT_FLAG_VIRTUAL);
1633
1634 if (fm_ksp != NULL) {
1635 fm_ksp->ks_data = &erpt_kstat_data;
1636 kstat_install(fm_ksp);
1637 } else {
1638 cmn_err(CE_NOTE, "failed to create fm/misc kstat\n");
1639 }
1640
1641 mutex_init(&zevent_lock, NULL, MUTEX_DEFAULT, NULL);
1642 list_create(&zevent_list, sizeof (zevent_t),
1643 offsetof(zevent_t, ev_node));
1644 cv_init(&zevent_cv, NULL, CV_DEFAULT, NULL);
1645 }
1646
1647 void
1648 fm_fini(void)
1649 {
1650 int count;
1651
1652 zfs_zevent_drain_all(&count);
1653
1654 mutex_enter(&zevent_lock);
1655 cv_broadcast(&zevent_cv);
1656
1657 zevent_flags |= ZEVENT_SHUTDOWN;
1658 while (zevent_waiters > 0) {
1659 mutex_exit(&zevent_lock);
1660 schedule();
1661 mutex_enter(&zevent_lock);
1662 }
1663 mutex_exit(&zevent_lock);
1664
1665 cv_destroy(&zevent_cv);
1666 list_destroy(&zevent_list);
1667 mutex_destroy(&zevent_lock);
1668
1669 if (fm_ksp != NULL) {
1670 kstat_delete(fm_ksp);
1671 fm_ksp = NULL;
1672 }
1673 }
1674
1675 module_param(zfs_zevent_len_max, int, 0644);
1676 MODULE_PARM_DESC(zfs_zevent_len_max, "Max event queue length");
1677
1678 module_param(zfs_zevent_cols, int, 0644);
1679 MODULE_PARM_DESC(zfs_zevent_cols, "Max event column width");
1680
1681 module_param(zfs_zevent_console, int, 0644);
1682 MODULE_PARM_DESC(zfs_zevent_console, "Log events to the console");
1683
1684 #endif /* _KERNEL */