1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3eda14cbcSMatt Macy * Copyright (c) 2020 iXsystems, Inc.
4eda14cbcSMatt Macy * All rights reserved.
5eda14cbcSMatt Macy *
6eda14cbcSMatt Macy * Redistribution and use in source and binary forms, with or without
7eda14cbcSMatt Macy * modification, are permitted provided that the following conditions
8eda14cbcSMatt Macy * are met:
9eda14cbcSMatt Macy * 1. Redistributions of source code must retain the above copyright
10eda14cbcSMatt Macy * notice, this list of conditions and the following disclaimer.
11eda14cbcSMatt Macy * 2. Redistributions in binary form must reproduce the above copyright
12eda14cbcSMatt Macy * notice, this list of conditions and the following disclaimer in the
13eda14cbcSMatt Macy * documentation and/or other materials provided with the distribution.
14eda14cbcSMatt Macy *
15eda14cbcSMatt Macy * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16eda14cbcSMatt Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17eda14cbcSMatt Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18eda14cbcSMatt Macy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19eda14cbcSMatt Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20eda14cbcSMatt Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21eda14cbcSMatt Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22eda14cbcSMatt Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23eda14cbcSMatt Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24eda14cbcSMatt Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25eda14cbcSMatt Macy * SUCH DAMAGE.
26eda14cbcSMatt Macy */
27eda14cbcSMatt Macy
28eda14cbcSMatt Macy #include <sys/types.h>
29eda14cbcSMatt Macy #include <sys/param.h>
30eda14cbcSMatt Macy #include <sys/kernel.h>
31eda14cbcSMatt Macy #include <sys/systm.h>
32eda14cbcSMatt Macy #include <sys/malloc.h>
33eda14cbcSMatt Macy #include <sys/kmem.h>
34eda14cbcSMatt Macy #include <sys/list.h>
35eda14cbcSMatt Macy #include <sys/proc.h>
36eda14cbcSMatt Macy #include <sys/sbuf.h>
37eda14cbcSMatt Macy #include <sys/nvpair.h>
38eda14cbcSMatt Macy #include <sys/sunddi.h>
39eda14cbcSMatt Macy #include <sys/sysevent.h>
40eda14cbcSMatt Macy #include <sys/fm/protocol.h>
41eda14cbcSMatt Macy #include <sys/fm/util.h>
42eda14cbcSMatt Macy #include <sys/bus.h>
43eda14cbcSMatt Macy
44eda14cbcSMatt Macy static int
log_sysevent(nvlist_t * event)45eda14cbcSMatt Macy log_sysevent(nvlist_t *event)
46eda14cbcSMatt Macy {
47eda14cbcSMatt Macy struct sbuf *sb;
48eda14cbcSMatt Macy const char *type;
49eda14cbcSMatt Macy char typestr[128];
50eda14cbcSMatt Macy nvpair_t *elem = NULL;
51eda14cbcSMatt Macy
52eda14cbcSMatt Macy sb = sbuf_new_auto();
53eda14cbcSMatt Macy if (sb == NULL)
54eda14cbcSMatt Macy return (ENOMEM);
55eda14cbcSMatt Macy type = NULL;
56eda14cbcSMatt Macy
57eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(event, elem)) != NULL) {
58eda14cbcSMatt Macy switch (nvpair_type(elem)) {
59eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN:
60eda14cbcSMatt Macy {
61eda14cbcSMatt Macy boolean_t value;
62eda14cbcSMatt Macy
63eda14cbcSMatt Macy (void) nvpair_value_boolean_value(elem, &value);
64eda14cbcSMatt Macy sbuf_printf(sb, " %s=%s", nvpair_name(elem),
65eda14cbcSMatt Macy value ? "true" : "false");
66eda14cbcSMatt Macy break;
67eda14cbcSMatt Macy }
68eda14cbcSMatt Macy case DATA_TYPE_UINT8:
69eda14cbcSMatt Macy {
70eda14cbcSMatt Macy uint8_t value;
71eda14cbcSMatt Macy
72eda14cbcSMatt Macy (void) nvpair_value_uint8(elem, &value);
73eda14cbcSMatt Macy sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
74eda14cbcSMatt Macy break;
75eda14cbcSMatt Macy }
76eda14cbcSMatt Macy case DATA_TYPE_INT32:
77eda14cbcSMatt Macy {
78eda14cbcSMatt Macy int32_t value;
79eda14cbcSMatt Macy
80eda14cbcSMatt Macy (void) nvpair_value_int32(elem, &value);
81eda14cbcSMatt Macy sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
82eda14cbcSMatt Macy (intmax_t)value);
83eda14cbcSMatt Macy break;
84eda14cbcSMatt Macy }
85eda14cbcSMatt Macy case DATA_TYPE_UINT32:
86eda14cbcSMatt Macy {
87eda14cbcSMatt Macy uint32_t value;
88eda14cbcSMatt Macy
89eda14cbcSMatt Macy (void) nvpair_value_uint32(elem, &value);
90eda14cbcSMatt Macy sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
91eda14cbcSMatt Macy (uintmax_t)value);
92eda14cbcSMatt Macy break;
93eda14cbcSMatt Macy }
94eda14cbcSMatt Macy case DATA_TYPE_INT64:
95eda14cbcSMatt Macy {
96eda14cbcSMatt Macy int64_t value;
97eda14cbcSMatt Macy
98eda14cbcSMatt Macy (void) nvpair_value_int64(elem, &value);
99eda14cbcSMatt Macy sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
100eda14cbcSMatt Macy (intmax_t)value);
101eda14cbcSMatt Macy break;
102eda14cbcSMatt Macy }
103eda14cbcSMatt Macy case DATA_TYPE_UINT64:
104eda14cbcSMatt Macy {
105eda14cbcSMatt Macy uint64_t value;
106eda14cbcSMatt Macy
107eda14cbcSMatt Macy (void) nvpair_value_uint64(elem, &value);
108eda14cbcSMatt Macy sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
109eda14cbcSMatt Macy (uintmax_t)value);
110eda14cbcSMatt Macy break;
111eda14cbcSMatt Macy }
112eda14cbcSMatt Macy case DATA_TYPE_STRING:
113eda14cbcSMatt Macy {
114*2a58b312SMartin Matuska const char *value;
115eda14cbcSMatt Macy
116eda14cbcSMatt Macy (void) nvpair_value_string(elem, &value);
117eda14cbcSMatt Macy sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
118eda14cbcSMatt Macy if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
119eda14cbcSMatt Macy type = value;
120eda14cbcSMatt Macy break;
121eda14cbcSMatt Macy }
122eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY:
123eda14cbcSMatt Macy {
124eda14cbcSMatt Macy uint8_t *value;
125eda14cbcSMatt Macy uint_t ii, nelem;
126eda14cbcSMatt Macy
127eda14cbcSMatt Macy (void) nvpair_value_uint8_array(elem, &value, &nelem);
128eda14cbcSMatt Macy sbuf_printf(sb, " %s=", nvpair_name(elem));
129eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++)
130eda14cbcSMatt Macy sbuf_printf(sb, "%02hhx", value[ii]);
131eda14cbcSMatt Macy break;
132eda14cbcSMatt Macy }
133eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY:
134eda14cbcSMatt Macy {
135eda14cbcSMatt Macy uint16_t *value;
136eda14cbcSMatt Macy uint_t ii, nelem;
137eda14cbcSMatt Macy
138eda14cbcSMatt Macy (void) nvpair_value_uint16_array(elem, &value, &nelem);
139eda14cbcSMatt Macy sbuf_printf(sb, " %s=", nvpair_name(elem));
140eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++)
141eda14cbcSMatt Macy sbuf_printf(sb, "%04hx", value[ii]);
142eda14cbcSMatt Macy break;
143eda14cbcSMatt Macy }
144eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY:
145eda14cbcSMatt Macy {
146eda14cbcSMatt Macy uint32_t *value;
147eda14cbcSMatt Macy uint_t ii, nelem;
148eda14cbcSMatt Macy
149eda14cbcSMatt Macy (void) nvpair_value_uint32_array(elem, &value, &nelem);
150eda14cbcSMatt Macy sbuf_printf(sb, " %s=", nvpair_name(elem));
151eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++)
152eda14cbcSMatt Macy sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
153eda14cbcSMatt Macy break;
154eda14cbcSMatt Macy }
155eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY:
156eda14cbcSMatt Macy {
157eda14cbcSMatt Macy int64_t *value;
158eda14cbcSMatt Macy uint_t ii, nelem;
159eda14cbcSMatt Macy
160eda14cbcSMatt Macy (void) nvpair_value_int64_array(elem, &value, &nelem);
161eda14cbcSMatt Macy sbuf_printf(sb, " %s=", nvpair_name(elem));
162eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++)
163eda14cbcSMatt Macy sbuf_printf(sb, "%016lld",
164eda14cbcSMatt Macy (long long)value[ii]);
165eda14cbcSMatt Macy break;
166eda14cbcSMatt Macy }
167eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY:
168eda14cbcSMatt Macy {
169eda14cbcSMatt Macy uint64_t *value;
170eda14cbcSMatt Macy uint_t ii, nelem;
171eda14cbcSMatt Macy
172eda14cbcSMatt Macy (void) nvpair_value_uint64_array(elem, &value, &nelem);
173eda14cbcSMatt Macy sbuf_printf(sb, " %s=", nvpair_name(elem));
174eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++)
175eda14cbcSMatt Macy sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
176eda14cbcSMatt Macy break;
177eda14cbcSMatt Macy }
178eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY:
179eda14cbcSMatt Macy {
180*2a58b312SMartin Matuska const char **strarr;
181eda14cbcSMatt Macy uint_t ii, nelem;
182eda14cbcSMatt Macy
183eda14cbcSMatt Macy (void) nvpair_value_string_array(elem, &strarr, &nelem);
184eda14cbcSMatt Macy
185eda14cbcSMatt Macy for (ii = 0; ii < nelem; ii++) {
186eda14cbcSMatt Macy if (strarr[ii] == NULL) {
187eda14cbcSMatt Macy sbuf_printf(sb, " <NULL>");
188eda14cbcSMatt Macy continue;
189eda14cbcSMatt Macy }
190eda14cbcSMatt Macy
191eda14cbcSMatt Macy sbuf_printf(sb, " %s", strarr[ii]);
192eda14cbcSMatt Macy if (strcmp(FM_CLASS, strarr[ii]) == 0)
193eda14cbcSMatt Macy type = strarr[ii];
194eda14cbcSMatt Macy }
195eda14cbcSMatt Macy break;
196eda14cbcSMatt Macy }
197eda14cbcSMatt Macy case DATA_TYPE_NVLIST:
198eda14cbcSMatt Macy /* XXX - requires recursing in log_sysevent */
199eda14cbcSMatt Macy break;
200eda14cbcSMatt Macy default:
201eda14cbcSMatt Macy printf("%s: type %d is not implemented\n", __func__,
202eda14cbcSMatt Macy nvpair_type(elem));
203eda14cbcSMatt Macy break;
204eda14cbcSMatt Macy }
205eda14cbcSMatt Macy }
206eda14cbcSMatt Macy
207eda14cbcSMatt Macy if (sbuf_finish(sb) != 0) {
208eda14cbcSMatt Macy sbuf_delete(sb);
209eda14cbcSMatt Macy return (ENOMEM);
210eda14cbcSMatt Macy }
211eda14cbcSMatt Macy
212eda14cbcSMatt Macy if (type == NULL)
213eda14cbcSMatt Macy type = "";
214eda14cbcSMatt Macy if (strncmp(type, "ESC_ZFS_", 8) == 0) {
215eda14cbcSMatt Macy snprintf(typestr, sizeof (typestr), "misc.fs.zfs.%s", type + 8);
216eda14cbcSMatt Macy type = typestr;
217eda14cbcSMatt Macy }
218eda14cbcSMatt Macy devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
219eda14cbcSMatt Macy sbuf_delete(sb);
220eda14cbcSMatt Macy
221eda14cbcSMatt Macy return (0);
222eda14cbcSMatt Macy }
223eda14cbcSMatt Macy
224eda14cbcSMatt Macy static void
sysevent_worker(void * arg __unused)225eda14cbcSMatt Macy sysevent_worker(void *arg __unused)
226eda14cbcSMatt Macy {
227eda14cbcSMatt Macy zfs_zevent_t *ze;
228eda14cbcSMatt Macy nvlist_t *event;
229eda14cbcSMatt Macy uint64_t dropped = 0;
230eda14cbcSMatt Macy uint64_t dst_size;
231eda14cbcSMatt Macy int error;
232eda14cbcSMatt Macy
233eda14cbcSMatt Macy zfs_zevent_init(&ze);
234eda14cbcSMatt Macy for (;;) {
235eda14cbcSMatt Macy dst_size = 131072;
236eda14cbcSMatt Macy dropped = 0;
237eda14cbcSMatt Macy event = NULL;
238eda14cbcSMatt Macy error = zfs_zevent_next(ze, &event,
239eda14cbcSMatt Macy &dst_size, &dropped);
240eda14cbcSMatt Macy if (error) {
241eda14cbcSMatt Macy error = zfs_zevent_wait(ze);
242eda14cbcSMatt Macy if (error == ESHUTDOWN)
243eda14cbcSMatt Macy break;
244eda14cbcSMatt Macy } else {
24516038816SMartin Matuska VERIFY3P(event, !=, NULL);
246eda14cbcSMatt Macy log_sysevent(event);
247eda14cbcSMatt Macy nvlist_free(event);
248eda14cbcSMatt Macy }
249eda14cbcSMatt Macy }
250da5137abSMartin Matuska
251da5137abSMartin Matuska /*
252da5137abSMartin Matuska * We avoid zfs_zevent_destroy() here because we're otherwise racing
253da5137abSMartin Matuska * against fm_fini() destroying the zevent_lock. zfs_zevent_destroy()
254da5137abSMartin Matuska * will currently only clear `ze->ze_zevent` from an event list then
255da5137abSMartin Matuska * free `ze`, so just inline the free() here -- events have already
256da5137abSMartin Matuska * been drained.
257da5137abSMartin Matuska */
258da5137abSMartin Matuska VERIFY3P(ze->ze_zevent, ==, NULL);
259da5137abSMartin Matuska kmem_free(ze, sizeof (zfs_zevent_t));
260da5137abSMartin Matuska
261eda14cbcSMatt Macy kthread_exit();
262eda14cbcSMatt Macy }
263eda14cbcSMatt Macy
264eda14cbcSMatt Macy void
ddi_sysevent_init(void)265eda14cbcSMatt Macy ddi_sysevent_init(void)
266eda14cbcSMatt Macy {
267eda14cbcSMatt Macy kproc_kthread_add(sysevent_worker, NULL, &system_proc, NULL, 0, 0,
268eda14cbcSMatt Macy "zfskern", "sysevent");
269eda14cbcSMatt Macy }
270