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