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