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