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