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