1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2024, Klara Inc. 25 */ 26 27 #include <sys/fs/zfs.h> 28 #include <sys/types.h> 29 #include <sys/sysmacros.h> 30 #include <sys/string.h> 31 #include <sys/debug.h> 32 #include "zfs_valstr.h" 33 34 /* 35 * Each bit in a bitfield has three possible string representations: 36 * - single char 37 * - two-char pair 38 * - full name 39 */ 40 typedef struct { 41 const char vb_bit; 42 43 /* 2 byte name + 1 byte NULL terminator to make GCC happy */ 44 const char vb_pair[3]; 45 const char *vb_name; 46 } valstr_bit_t; 47 48 /* 49 * Emits a character for each bit in `bits`, up to the number of elements 50 * in the table. Set bits get the character in vb_bit, clear bits get a 51 * space. This results in all strings having the same width, for easier 52 * visual comparison. 53 */ 54 static size_t 55 valstr_bitfield_bits(const valstr_bit_t *table, const size_t nelems, 56 uint64_t bits, char *out, size_t outlen) 57 { 58 ASSERT(out); 59 size_t n = 0; 60 for (int b = 0; b < nelems; b++) { 61 if (n == outlen) 62 break; 63 uint64_t mask = (1ULL << b); 64 out[n++] = (bits & mask) ? table[b].vb_bit : ' '; 65 } 66 if (n < outlen) 67 out[n++] = '\0'; 68 return (n); 69 } 70 71 /* 72 * Emits a two-char pair for each bit set in `bits`, taken from vb_pair, and 73 * separated by a `|` character. This gives a concise representation of the 74 * whole value. 75 */ 76 static size_t 77 valstr_bitfield_pairs(const valstr_bit_t *table, const size_t nelems, 78 uint64_t bits, char *out, size_t outlen) 79 { 80 ASSERT(out); 81 size_t n = 0; 82 for (int b = 0; b < nelems; b++) { 83 ASSERT3U(n, <=, outlen); 84 if (n == outlen) 85 break; 86 uint64_t mask = (1ULL << b); 87 if (bits & mask) { 88 size_t len = (n > 0) ? 3 : 2; 89 if (n > outlen-len) 90 break; 91 if (n > 0) 92 out[n++] = '|'; 93 out[n++] = table[b].vb_pair[0]; 94 out[n++] = table[b].vb_pair[1]; 95 } 96 } 97 if (n < outlen) 98 out[n++] = '\0'; 99 return (n); 100 } 101 102 /* 103 * Emits the full name for each bit set in `bits`, taken from vb_name, and 104 * separated by a space. This unambiguously shows the entire set of bits, but 105 * can get very long. 106 */ 107 static size_t 108 valstr_bitfield_str(const valstr_bit_t *table, const size_t nelems, 109 uint64_t bits, char *out, size_t outlen) 110 { 111 ASSERT(out); 112 size_t n = 0; 113 for (int b = 0; b < nelems; b++) { 114 ASSERT3U(n, <=, outlen); 115 if (n == outlen) 116 break; 117 uint64_t mask = (1ULL << b); 118 if (bits & mask) { 119 size_t len = strlen(table[b].vb_name); 120 if (n > 0) 121 len++; 122 if (n > outlen-len) 123 break; 124 if (n > 0) { 125 out[n++] = ' '; 126 len--; 127 } 128 memcpy(&out[n], table[b].vb_name, len); 129 n += len; 130 } 131 } 132 if (n < outlen) 133 out[n++] = '\0'; 134 return (n); 135 } 136 137 /* 138 * Emits the name of the given enum value in the table. 139 */ 140 static size_t 141 valstr_enum_str(const char **table, const size_t nelems, 142 int v, char *out, size_t outlen) 143 { 144 ASSERT(out); 145 ASSERT3U(v, <, nelems); 146 if (v >= nelems) 147 return (0); 148 return (MIN(strlcpy(out, table[v], outlen), outlen)); 149 } 150 151 /* 152 * These macros create the string tables for the given name, and implement 153 * the public functions described in zfs_valstr.h. 154 */ 155 #define _VALSTR_BITFIELD_IMPL(name, ...) \ 156 static const valstr_bit_t valstr_ ## name ## _table[] = { __VA_ARGS__ };\ 157 size_t \ 158 zfs_valstr_ ## name ## _bits(uint64_t bits, char *out, size_t outlen) \ 159 { \ 160 return (valstr_bitfield_bits(valstr_ ## name ## _table, \ 161 ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \ 162 } \ 163 \ 164 size_t \ 165 zfs_valstr_ ## name ## _pairs(uint64_t bits, char *out, size_t outlen) \ 166 { \ 167 return (valstr_bitfield_pairs(valstr_ ## name ## _table, \ 168 ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \ 169 } \ 170 \ 171 size_t \ 172 zfs_valstr_ ## name(uint64_t bits, char *out, size_t outlen) \ 173 { \ 174 return (valstr_bitfield_str(valstr_ ## name ## _table, \ 175 ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \ 176 } \ 177 178 #define _VALSTR_ENUM_IMPL(name, ...) \ 179 static const char *valstr_ ## name ## _table[] = { __VA_ARGS__ }; \ 180 size_t \ 181 zfs_valstr_ ## name(int v, char *out, size_t outlen) \ 182 { \ 183 return (valstr_enum_str(valstr_ ## name ## _table, \ 184 ARRAY_SIZE(valstr_ ## name ## _table), v, out, outlen)); \ 185 } \ 186 187 188 /* String tables */ 189 190 /* ZIO flags: zio_flag_t, typically zio->io_flags */ 191 _VALSTR_BITFIELD_IMPL(zio_flag, 192 { '.', "DA", "DONT_AGGREGATE" }, 193 { '.', "RP", "IO_REPAIR" }, 194 { '.', "SH", "SELF_HEAL" }, 195 { '.', "RS", "RESILVER" }, 196 { '.', "SC", "SCRUB" }, 197 { '.', "ST", "SCAN_THREAD" }, 198 { '.', "PH", "PHYSICAL" }, 199 { '.', "CF", "CANFAIL" }, 200 { '.', "SP", "SPECULATIVE" }, 201 { '.', "CW", "CONFIG_WRITER" }, 202 { '.', "DR", "DONT_RETRY" }, 203 { '?', "??", "[UNUSED 11]" }, 204 { '.', "ND", "NODATA" }, 205 { '.', "ID", "INDUCE_DAMAGE" }, 206 { '.', "AL", "IO_ALLOCATING" }, 207 { '.', "RE", "IO_RETRY" }, 208 { '.', "PR", "PROBE" }, 209 { '.', "TH", "TRYHARD" }, 210 { '.', "OP", "OPTIONAL" }, 211 { '.', "RD", "DIO_READ" }, 212 { '.', "DQ", "DONT_QUEUE" }, 213 { '.', "DP", "DONT_PROPAGATE" }, 214 { '.', "BY", "IO_BYPASS" }, 215 { '.', "RW", "IO_REWRITE" }, 216 { '.', "CM", "RAW_COMPRESS" }, 217 { '.', "EN", "RAW_ENCRYPT" }, 218 { '.', "GG", "GANG_CHILD" }, 219 { '.', "DD", "DDT_CHILD" }, 220 { '.', "GF", "GODFATHER" }, 221 { '.', "NP", "NOPWRITE" }, 222 { '.', "EX", "REEXECUTED" }, 223 { '.', "DG", "DELEGATED" }, 224 { '.', "DC", "DIO_CHKSUM_ERR" }, 225 { '.', "PA", "PREALLOCATED" }, 226 ) 227 228 /* 229 * ZIO pipeline stage(s): enum zio_stage, typically zio->io_stage or 230 * zio->io_pipeline. 231 */ 232 _VALSTR_BITFIELD_IMPL(zio_stage, 233 { 'O', "O ", "OPEN" }, 234 { 'I', "RI", "READ_BP_INIT" }, 235 { 'I', "WI", "WRITE_BP_INIT" }, 236 { 'I', "FI", "FREE_BP_INIT" }, 237 { 'A', "IA", "ISSUE_ASYNC" }, 238 { 'W', "WC", "WRITE_COMPRESS" }, 239 { 'E', "EN", "ENCRYPT" }, 240 { 'C', "CG", "CHECKSUM_GENERATE" }, 241 { 'N', "NW", "NOP_WRITE" }, 242 { 'B', "BF", "BRT_FREE" }, 243 { 'd', "dS", "DDT_READ_START" }, 244 { 'd', "dD", "DDT_READ_DONE" }, 245 { 'd', "dW", "DDT_WRITE" }, 246 { 'd', "dF", "DDT_FREE" }, 247 { 'G', "GA", "GANG_ASSEMBLE" }, 248 { 'G', "GI", "GANG_ISSUE" }, 249 { 'D', "DT", "DVA_THROTTLE" }, 250 { 'D', "DA", "DVA_ALLOCATE" }, 251 { 'D', "DF", "DVA_FREE" }, 252 { 'D', "DC", "DVA_CLAIM" }, 253 { 'R', "R ", "READY" }, 254 { 'V', "VS", "VDEV_IO_START" }, 255 { 'V', "VD", "VDEV_IO_DONE" }, 256 { 'V', "VA", "VDEV_IO_ASSESS" }, 257 { 'C', "CV", "CHECKSUM_VERIFY" }, 258 { 'C', "DC", "DIO_CHECKSUM_VERIFY" }, 259 { 'X', "X ", "DONE" }, 260 ) 261 262 /* ZIO type: zio_type_t, typically zio->io_type */ 263 _VALSTR_ENUM_IMPL(zio_type, 264 "NULL", 265 "READ", 266 "WRITE", 267 "FREE", 268 "CLAIM", 269 "FLUSH", 270 "TRIM", 271 ) 272 273 /* ZIO priority: zio_priority_t, typically zio->io_priority */ 274 _VALSTR_ENUM_IMPL(zio_priority, 275 "SYNC_READ", 276 "SYNC_WRITE", 277 "ASYNC_READ", 278 "ASYNC_WRITE", 279 "SCRUB", 280 "REMOVAL", 281 "INITIALIZING", 282 "TRIM", 283 "REBUILD", 284 "[NUM_QUEUEABLE]", 285 "NOW", 286 ) 287 288 #undef _VALSTR_BITFIELD_IMPL 289 #undef _VALSTR_ENUM_IMPL 290