1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * This file and its contents are supplied under the terms of the 6 * Common Development and Distribution License ("CDDL"), version 1.0. 7 * You may only use this file in accordance with the terms of version 8 * 1.0 of the CDDL. 9 * 10 * A full copy of the text of the CDDL should have accompanied this 11 * source. A copy of the CDDL is also available via the Internet at 12 * http://www.illumos.org/license/CDDL. 13 * 14 * CDDL HEADER END 15 */ 16 17 /* 18 * Copyright (c) 2020 by Delphix. All rights reserved. 19 */ 20 21 #include <assert.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <libzfs.h> 25 #include <sys/nvpair.h> 26 #include <sys/fm/protocol.h> 27 #include <sys/fm/fs/zfs.h> 28 29 #define ZEVENT_NONBLOCK 0x1 30 31 /* 32 * Command to output io and checksum ereport values, one per line. 33 * Used by zpool_events_duplicates.ksh to check for duplicate events. 34 * 35 * example output line: 36 * 37 * checksum "error_pool" 0x856dd01ce52e336 0x000034 0x000400 0x000a402c00 38 * 0x000004 0x000000 0x000000 0x000000 0x000001 39 */ 40 41 /* 42 * Our ereport duplicate criteria 43 * 44 * When the class and all of these values match, then an ereport is 45 * considered to be a duplicate. 46 */ 47 static const char *const criteria_name[] = { 48 FM_EREPORT_PAYLOAD_ZFS_POOL, 49 FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, 50 FM_EREPORT_PAYLOAD_ZFS_ZIO_ERR, 51 FM_EREPORT_PAYLOAD_ZFS_ZIO_SIZE, 52 FM_EREPORT_PAYLOAD_ZFS_ZIO_OFFSET, 53 FM_EREPORT_PAYLOAD_ZFS_ZIO_TYPE, 54 FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, 55 56 /* logical zio criteriai (optional) */ 57 FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJSET, 58 FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJECT, 59 FM_EREPORT_PAYLOAD_ZFS_ZIO_BLKID, 60 FM_EREPORT_PAYLOAD_ZFS_ZIO_LEVEL, 61 }; 62 63 #define CRITERIA_NAMES_COUNT ARRAY_SIZE(criteria_name) 64 65 static void 66 print_ereport_line(nvlist_t *nvl) 67 { 68 const char *class; 69 int last = CRITERIA_NAMES_COUNT - 1; 70 71 /* 72 * For the test case context, we only want to see 'io' and 73 * 'checksum' subclass. We skip 'data' to minimize the output. 74 */ 75 if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0 || 76 strstr(class, "ereport.fs.zfs.") == NULL || 77 strcmp(class, "ereport.fs.zfs.data") == 0) { 78 return; 79 } 80 81 (void) printf("%s\t", class + strlen("ereport.fs.zfs.")); 82 83 for (int i = 0; i < CRITERIA_NAMES_COUNT; i++) { 84 nvpair_t *nvp; 85 uint32_t i32 = 0; 86 uint64_t i64 = 0; 87 const char *str = NULL; 88 89 if (nvlist_lookup_nvpair(nvl, criteria_name[i], &nvp) != 0) { 90 /* print a proxy for optional criteria */ 91 (void) printf("--------"); 92 (void) printf("%c", i == last ? '\n' : '\t'); 93 continue; 94 } 95 96 switch (nvpair_type(nvp)) { 97 case DATA_TYPE_STRING: 98 (void) nvpair_value_string(nvp, &str); 99 (void) printf("\"%s\"", str ? str : "<NULL>"); 100 break; 101 102 case DATA_TYPE_INT32: 103 (void) nvpair_value_int32(nvp, (void *)&i32); 104 (void) printf("0x%06x", i32); 105 break; 106 107 case DATA_TYPE_UINT32: 108 (void) nvpair_value_uint32(nvp, &i32); 109 (void) printf("0x%06x", i32); 110 break; 111 112 case DATA_TYPE_INT64: 113 (void) nvpair_value_int64(nvp, (void *)&i64); 114 (void) printf("0x%06llx", (u_longlong_t)i64); 115 break; 116 117 case DATA_TYPE_UINT64: 118 (void) nvpair_value_uint64(nvp, &i64); 119 if (strcmp(FM_EREPORT_PAYLOAD_ZFS_ZIO_OFFSET, 120 criteria_name[i]) == 0) 121 (void) printf("0x%010llx", (u_longlong_t)i64); 122 else 123 (void) printf("0x%06llx", (u_longlong_t)i64); 124 break; 125 default: 126 (void) printf("<unknown>"); 127 break; 128 } 129 (void) printf("%c", i == last ? '\n' : '\t'); 130 } 131 } 132 133 static void 134 ereports_dump(libzfs_handle_t *zhdl, int zevent_fd) 135 { 136 nvlist_t *nvl; 137 int ret, dropped; 138 139 while (1) { 140 ret = zpool_events_next(zhdl, &nvl, &dropped, ZEVENT_NONBLOCK, 141 zevent_fd); 142 if (ret || nvl == NULL) 143 break; 144 if (dropped > 0) 145 (void) fprintf(stdout, "dropped %d events\n", dropped); 146 print_ereport_line(nvl); 147 (void) fflush(stdout); 148 nvlist_free(nvl); 149 } 150 } 151 152 int 153 main(void) 154 { 155 libzfs_handle_t *hdl; 156 int fd; 157 158 hdl = libzfs_init(); 159 if (hdl == NULL) { 160 (void) fprintf(stderr, "libzfs_init: %s\n", strerror(errno)); 161 exit(2); 162 } 163 fd = open(ZFS_DEV, O_RDWR); 164 if (fd < 0) { 165 (void) fprintf(stderr, "open: %s\n", strerror(errno)); 166 libzfs_fini(hdl); 167 exit(2); 168 } 169 170 ereports_dump(hdl, fd); 171 172 (void) close(fd); 173 libzfs_fini(hdl); 174 175 return (0); 176 } 177