xref: /freebsd-src/sys/contrib/openzfs/module/os/freebsd/spl/spl_sysevent.c (revision a2b560cc69eb254c92caf2027a69cadf9865d273)
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