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