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/types.h> 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/systm.h> 32 #include <sys/malloc.h> 33 #include <sys/kmem.h> 34 #include <sys/list.h> 35 #include <sys/proc.h> 36 #include <sys/sbuf.h> 37 #include <sys/nvpair.h> 38 #include <sys/sunddi.h> 39 #include <sys/sysevent.h> 40 #include <sys/fm/protocol.h> 41 #include <sys/fm/util.h> 42 #include <sys/bus.h> 43 44 static int 45 log_sysevent(nvlist_t *event) 46 { 47 struct sbuf *sb; 48 const char *type; 49 char typestr[128]; 50 nvpair_t *elem = NULL; 51 52 sb = sbuf_new_auto(); 53 if (sb == NULL) 54 return (ENOMEM); 55 type = NULL; 56 57 while ((elem = nvlist_next_nvpair(event, elem)) != NULL) { 58 switch (nvpair_type(elem)) { 59 case DATA_TYPE_BOOLEAN: 60 { 61 boolean_t value; 62 63 (void) nvpair_value_boolean_value(elem, &value); 64 sbuf_printf(sb, " %s=%s", nvpair_name(elem), 65 value ? "true" : "false"); 66 break; 67 } 68 case DATA_TYPE_UINT8: 69 { 70 uint8_t value; 71 72 (void) nvpair_value_uint8(elem, &value); 73 sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value); 74 break; 75 } 76 case DATA_TYPE_INT32: 77 { 78 int32_t value; 79 80 (void) nvpair_value_int32(elem, &value); 81 sbuf_printf(sb, " %s=%jd", nvpair_name(elem), 82 (intmax_t)value); 83 break; 84 } 85 case DATA_TYPE_UINT32: 86 { 87 uint32_t value; 88 89 (void) nvpair_value_uint32(elem, &value); 90 sbuf_printf(sb, " %s=%ju", nvpair_name(elem), 91 (uintmax_t)value); 92 break; 93 } 94 case DATA_TYPE_INT64: 95 { 96 int64_t value; 97 98 (void) nvpair_value_int64(elem, &value); 99 sbuf_printf(sb, " %s=%jd", nvpair_name(elem), 100 (intmax_t)value); 101 break; 102 } 103 case DATA_TYPE_UINT64: 104 { 105 uint64_t value; 106 107 (void) nvpair_value_uint64(elem, &value); 108 sbuf_printf(sb, " %s=%ju", nvpair_name(elem), 109 (uintmax_t)value); 110 break; 111 } 112 case DATA_TYPE_STRING: 113 { 114 const char *value; 115 116 (void) nvpair_value_string(elem, &value); 117 sbuf_printf(sb, " %s=%s", nvpair_name(elem), value); 118 if (strcmp(FM_CLASS, nvpair_name(elem)) == 0) 119 type = value; 120 break; 121 } 122 case DATA_TYPE_UINT8_ARRAY: 123 { 124 uint8_t *value; 125 uint_t ii, nelem; 126 127 (void) nvpair_value_uint8_array(elem, &value, &nelem); 128 sbuf_printf(sb, " %s=", nvpair_name(elem)); 129 for (ii = 0; ii < nelem; ii++) 130 sbuf_printf(sb, "%02hhx", value[ii]); 131 break; 132 } 133 case DATA_TYPE_UINT16_ARRAY: 134 { 135 uint16_t *value; 136 uint_t ii, nelem; 137 138 (void) nvpair_value_uint16_array(elem, &value, &nelem); 139 sbuf_printf(sb, " %s=", nvpair_name(elem)); 140 for (ii = 0; ii < nelem; ii++) 141 sbuf_printf(sb, "%04hx", value[ii]); 142 break; 143 } 144 case DATA_TYPE_UINT32_ARRAY: 145 { 146 uint32_t *value; 147 uint_t ii, nelem; 148 149 (void) nvpair_value_uint32_array(elem, &value, &nelem); 150 sbuf_printf(sb, " %s=", nvpair_name(elem)); 151 for (ii = 0; ii < nelem; ii++) 152 sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]); 153 break; 154 } 155 case DATA_TYPE_INT64_ARRAY: 156 { 157 int64_t *value; 158 uint_t ii, nelem; 159 160 (void) nvpair_value_int64_array(elem, &value, &nelem); 161 sbuf_printf(sb, " %s=", nvpair_name(elem)); 162 for (ii = 0; ii < nelem; ii++) 163 sbuf_printf(sb, "%016lld", 164 (long long)value[ii]); 165 break; 166 } 167 case DATA_TYPE_UINT64_ARRAY: 168 { 169 uint64_t *value; 170 uint_t ii, nelem; 171 172 (void) nvpair_value_uint64_array(elem, &value, &nelem); 173 sbuf_printf(sb, " %s=", nvpair_name(elem)); 174 for (ii = 0; ii < nelem; ii++) 175 sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]); 176 break; 177 } 178 case DATA_TYPE_STRING_ARRAY: 179 { 180 const char **strarr; 181 uint_t ii, nelem; 182 183 (void) nvpair_value_string_array(elem, &strarr, &nelem); 184 185 for (ii = 0; ii < nelem; ii++) { 186 if (strarr[ii] == NULL) { 187 sbuf_printf(sb, " <NULL>"); 188 continue; 189 } 190 191 sbuf_printf(sb, " %s", strarr[ii]); 192 if (strcmp(FM_CLASS, strarr[ii]) == 0) 193 type = strarr[ii]; 194 } 195 break; 196 } 197 case DATA_TYPE_NVLIST: 198 /* XXX - requires recursing in log_sysevent */ 199 break; 200 default: 201 printf("%s: type %d is not implemented\n", __func__, 202 nvpair_type(elem)); 203 break; 204 } 205 } 206 207 if (sbuf_finish(sb) != 0) { 208 sbuf_delete(sb); 209 return (ENOMEM); 210 } 211 212 if (type == NULL) 213 type = ""; 214 if (strncmp(type, "ESC_ZFS_", 8) == 0) { 215 snprintf(typestr, sizeof (typestr), "misc.fs.zfs.%s", type + 8); 216 type = typestr; 217 } 218 devctl_notify("ZFS", "ZFS", type, sbuf_data(sb)); 219 sbuf_delete(sb); 220 221 return (0); 222 } 223 224 static void 225 sysevent_worker(void *arg __unused) 226 { 227 zfs_zevent_t *ze; 228 nvlist_t *event; 229 uint64_t dropped = 0; 230 uint64_t dst_size; 231 int error; 232 233 zfs_zevent_init(&ze); 234 for (;;) { 235 dst_size = 131072; 236 dropped = 0; 237 event = NULL; 238 error = zfs_zevent_next(ze, &event, 239 &dst_size, &dropped); 240 if (error) { 241 error = zfs_zevent_wait(ze); 242 if (error == ESHUTDOWN) 243 break; 244 } else { 245 VERIFY3P(event, !=, NULL); 246 log_sysevent(event); 247 nvlist_free(event); 248 } 249 } 250 251 /* 252 * We avoid zfs_zevent_destroy() here because we're otherwise racing 253 * against fm_fini() destroying the zevent_lock. zfs_zevent_destroy() 254 * will currently only clear `ze->ze_zevent` from an event list then 255 * free `ze`, so just inline the free() here -- events have already 256 * been drained. 257 */ 258 VERIFY3P(ze->ze_zevent, ==, NULL); 259 kmem_free(ze, sizeof (zfs_zevent_t)); 260 261 kthread_exit(); 262 } 263 264 void 265 ddi_sysevent_init(void) 266 { 267 kproc_kthread_add(sysevent_worker, NULL, &system_proc, NULL, 0, 0, 268 "zfskern", "sysevent"); 269 } 270