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