--- /dev/null
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or https://opensource.org/licenses/CDDL-1.0.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2024, Klara Inc.
+ */
+
+#ifndef _ZFS_VALSTR_H
+#define _ZFS_VALSTR_H extern __attribute__((visibility("default")))
+
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * These macros create function prototypes for pretty-printing or stringifying
+ * certain kinds of numeric types.
+ *
+ * _ZFS_VALSTR_DECLARE_BITFIELD(name) creates:
+ *
+ * size_t zfs_valstr_<name>_bits(uint64_t bits, char *out, size_t outlen);
+ * expands single char for each set bit, and space for each clear bit
+ *
+ * size_t zfs_valstr_<name>_pairs(uint64_t bits, char *out, size_t outlen);
+ * expands two-char mnemonic for each bit set in `bits`, separated by `|`
+ *
+ * size_t zfs_valstr_<name>(uint64_t bits, char *out, size_t outlen);
+ * expands full name of each bit set in `bits`, separated by spaces
+ *
+ * _ZFS_VALSTR_DECLARE_ENUM(name) creates:
+ *
+ * size_t zfs_valstr_<name>(int v, char *out, size_t outlen);
+ * expands full name of enum value
+ *
+ * Each _ZFS_VALSTR_DECLARE_xxx needs a corresponding _VALSTR_xxx_IMPL string
+ * table in vfs_valstr.c.
+ */
+
+#define _ZFS_VALSTR_DECLARE_BITFIELD(name) \
+ _ZFS_VALSTR_H size_t zfs_valstr_ ## name ## _bits( \
+ uint64_t bits, char *out, size_t outlen); \
+ _ZFS_VALSTR_H size_t zfs_valstr_ ## name ## _pairs( \
+ uint64_t bits, char *out, size_t outlen); \
+ _ZFS_VALSTR_H size_t zfs_valstr_ ## name( \
+ uint64_t bits, char *out, size_t outlen); \
+
+#define _ZFS_VALSTR_DECLARE_ENUM(name) \
+ _ZFS_VALSTR_H size_t zfs_valstr_ ## name( \
+ int v, char *out, size_t outlen); \
+
+_ZFS_VALSTR_DECLARE_BITFIELD(zio_flag)
+_ZFS_VALSTR_DECLARE_BITFIELD(zio_stage)
+
+_ZFS_VALSTR_DECLARE_ENUM(zio_priority)
+
+#undef _ZFS_VALSTR_DECLARE_BITFIELD
+#undef _ZFS_VALSTR_DECLARE_ENUM
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_VALSTR_H */
<elf-symbol name='zfs_userns' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_userspace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_valid_proplist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_flag' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_flag_bits' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_flag_pairs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_priority' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_stage' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_stage_bits' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_valstr_zio_stage_pairs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_kernel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_nvlist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<return type-id='c19b74c3'/>
</function-decl>
</abi-instr>
+ <abi-instr address-size='64' path='module/zcommon/zfs_valstr.c' language='LANG_C99'>
+ <function-decl name='zfs_valstr_zio_flag' mangled-name='zfs_valstr_zio_flag' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_flag'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_flag_bits' mangled-name='zfs_valstr_zio_flag_bits' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_flag_bits'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_flag_pairs' mangled-name='zfs_valstr_zio_flag_pairs' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_flag_pairs'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_stage' mangled-name='zfs_valstr_zio_stage' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_stage'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_stage_bits' mangled-name='zfs_valstr_zio_stage_bits' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_stage_bits'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_stage_pairs' mangled-name='zfs_valstr_zio_stage_pairs' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_stage_pairs'>
+ <parameter type-id='9c313c2d' name='bits'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ <function-decl name='zfs_valstr_zio_priority' mangled-name='zfs_valstr_zio_priority' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_valstr_zio_priority'>
+ <parameter type-id='95e97e5e' name='v'/>
+ <parameter type-id='26a90f95' name='out'/>
+ <parameter type-id='b59d7dce' name='outlen'/>
+ <return type-id='b59d7dce'/>
+ </function-decl>
+ </abi-instr>
<abi-instr address-size='64' path='module/zcommon/zpool_prop.c' language='LANG_C99'>
<function-decl name='zpool_prop_string_to_index' mangled-name='zpool_prop_string_to_index' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_prop_string_to_index'>
<parameter type-id='5d0c23fb' name='prop'/>
--- /dev/null
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or https://opensource.org/licenses/CDDL-1.0.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2024, Klara Inc.
+ */
+
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/string.h>
+#include <sys/debug.h>
+#include "zfs_valstr.h"
+
+/*
+ * Each bit in a bitfield has three possible string representations:
+ * - single char
+ * - two-char pair
+ * - full name
+ */
+typedef struct {
+ const char vb_bit;
+ const char vb_pair[2];
+ const char *vb_name;
+} valstr_bit_t;
+
+/*
+ * Emits a character for each bit in `bits`, up to the number of elements
+ * in the table. Set bits get the character in vb_bit, clear bits get a
+ * space. This results in all strings having the same width, for easier
+ * visual comparison.
+ */
+static size_t
+valstr_bitfield_bits(const valstr_bit_t *table, const size_t nelems,
+ uint64_t bits, char *out, size_t outlen)
+{
+ ASSERT(out);
+ size_t n = 0;
+ for (int b = 0; b < nelems; b++) {
+ if (n == outlen)
+ break;
+ uint64_t mask = (1ULL << b);
+ out[n++] = (bits & mask) ? table[b].vb_bit : ' ';
+ }
+ if (n < outlen)
+ out[n++] = '\0';
+ return (n);
+}
+
+/*
+ * Emits a two-char pair for each bit set in `bits`, taken from vb_pair, and
+ * separated by a `|` character. This gives a concise representation of the
+ * whole value.
+ */
+static size_t
+valstr_bitfield_pairs(const valstr_bit_t *table, const size_t nelems,
+ uint64_t bits, char *out, size_t outlen)
+{
+ ASSERT(out);
+ size_t n = 0;
+ for (int b = 0; b < nelems; b++) {
+ ASSERT3U(n, <=, outlen);
+ if (n == outlen)
+ break;
+ uint64_t mask = (1ULL << b);
+ if (bits & mask) {
+ size_t len = (n > 0) ? 3 : 2;
+ if (n > outlen-len)
+ break;
+ if (n > 0)
+ out[n++] = '|';
+ out[n++] = table[b].vb_pair[0];
+ out[n++] = table[b].vb_pair[1];
+ }
+ }
+ if (n < outlen)
+ out[n++] = '\0';
+ return (n);
+}
+
+/*
+ * Emits the full name for each bit set in `bits`, taken from vb_name, and
+ * separated by a space. This unambiguously shows the entire set of bits, but
+ * can get very long.
+ */
+static size_t
+valstr_bitfield_str(const valstr_bit_t *table, const size_t nelems,
+ uint64_t bits, char *out, size_t outlen)
+{
+ ASSERT(out);
+ size_t n = 0;
+ for (int b = 0; b < nelems; b++) {
+ ASSERT3U(n, <=, outlen);
+ if (n == outlen)
+ break;
+ uint64_t mask = (1ULL << b);
+ if (bits & mask) {
+ size_t len = strlen(table[b].vb_name);
+ if (n > 0)
+ len++;
+ if (n > outlen-len)
+ break;
+ if (n > 0) {
+ out[n++] = ' ';
+ len--;
+ }
+ memcpy(&out[n], table[b].vb_name, len);
+ n += len;
+ }
+ }
+ if (n < outlen)
+ out[n++] = '\0';
+ return (n);
+}
+
+/*
+ * Emits the name of the given enum value in the table.
+ */
+static size_t
+valstr_enum_str(const char **table, const size_t nelems,
+ int v, char *out, size_t outlen)
+{
+ ASSERT(out);
+ ASSERT3U(v, <, nelems);
+ if (v >= nelems)
+ return (0);
+ return (MIN(strlcpy(out, table[v], outlen), outlen));
+}
+
+/*
+ * These macros create the string tables for the given name, and implement
+ * the public functions described in zfs_valstr.h.
+ */
+#define _VALSTR_BITFIELD_IMPL(name, ...) \
+static const valstr_bit_t valstr_ ## name ## _table[] = { __VA_ARGS__ };\
+size_t \
+zfs_valstr_ ## name ## _bits(uint64_t bits, char *out, size_t outlen) \
+{ \
+ return (valstr_bitfield_bits(valstr_ ## name ## _table, \
+ ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \
+} \
+ \
+size_t \
+zfs_valstr_ ## name ## _pairs(uint64_t bits, char *out, size_t outlen) \
+{ \
+ return (valstr_bitfield_pairs(valstr_ ## name ## _table, \
+ ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \
+} \
+ \
+size_t \
+zfs_valstr_ ## name(uint64_t bits, char *out, size_t outlen) \
+{ \
+ return (valstr_bitfield_str(valstr_ ## name ## _table, \
+ ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen)); \
+} \
+
+#define _VALSTR_ENUM_IMPL(name, ...) \
+static const char *valstr_ ## name ## _table[] = { __VA_ARGS__ }; \
+size_t \
+zfs_valstr_ ## name(int v, char *out, size_t outlen) \
+{ \
+ return (valstr_enum_str(valstr_ ## name ## _table, \
+ ARRAY_SIZE(valstr_ ## name ## _table), v, out, outlen)); \
+} \
+
+
+/* String tables */
+
+/* ZIO flags: zio_flag_t, typically zio->io_flags */
+/* BEGIN CSTYLED */
+_VALSTR_BITFIELD_IMPL(zio_flag,
+ { '.', "DA", "DONT_AGGREGATE" },
+ { '.', "RP", "IO_REPAIR" },
+ { '.', "SH", "SELF_HEAL" },
+ { '.', "RS", "RESILVER" },
+ { '.', "SC", "SCRUB" },
+ { '.', "ST", "SCAN_THREAD" },
+ { '.', "PH", "PHYSICAL" },
+ { '.', "CF", "CANFAIL" },
+ { '.', "SP", "SPECULATIVE" },
+ { '.', "CW", "CONFIG_WRITER" },
+ { '.', "DR", "DONT_RETRY" },
+ { '?', "??", "[UNUSED 11]" },
+ { '.', "ND", "NODATA" },
+ { '.', "ID", "INDUCE_DAMAGE" },
+ { '.', "AL", "IO_ALLOCATING" },
+ { '.', "RE", "IO_RETRY" },
+ { '.', "PR", "PROBE" },
+ { '.', "TH", "TRYHARD" },
+ { '.', "OP", "OPTIONAL" },
+ { '.', "DQ", "DONT_QUEUE" },
+ { '.', "DP", "DONT_PROPAGATE" },
+ { '.', "BY", "IO_BYPASS" },
+ { '.', "RW", "IO_REWRITE" },
+ { '.', "CM", "RAW_COMPRESS" },
+ { '.', "EN", "RAW_ENCRYPT" },
+ { '.', "GG", "GANG_CHILD" },
+ { '.', "DD", "DDT_CHILD" },
+ { '.', "GF", "GODFATHER" },
+ { '.', "NP", "NOPWRITE" },
+ { '.', "EX", "REEXECUTED" },
+ { '.', "DG", "DELEGATED" },
+)
+/* END CSTYLED */
+
+/*
+ * ZIO pipeline stage(s): enum zio_stage, typically zio->io_stage or
+ * zio->io_pipeline.
+ */
+/* BEGIN CSTYLED */
+_VALSTR_BITFIELD_IMPL(zio_stage,
+ { 'O', "O ", "OPEN" },
+ { 'I', "RI", "READ_BP_INIT" },
+ { 'I', "WI", "WRITE_BP_INIT" },
+ { 'I', "FI", "FREE_BP_INIT" },
+ { 'A', "IA", "ISSUE_ASYNC" },
+ { 'W', "WC", "WRITE_COMPRESS" },
+ { 'E', "EN", "ENCRYPT" },
+ { 'C', "CG", "CHECKSUM_GENERATE" },
+ { 'N', "NW", "NOP_WRITE" },
+ { 'B', "BF", "BRT_FREE" },
+ { 'd', "dS", "DDT_READ_START" },
+ { 'd', "dD", "DDT_READ_DONE" },
+ { 'd', "dW", "DDT_WRITE" },
+ { 'd', "dF", "DDT_FREE" },
+ { 'G', "GA", "GANG_ASSEMBLE" },
+ { 'G', "GI", "GANG_ISSUE" },
+ { 'D', "DT", "DVA_THROTTLE" },
+ { 'D', "DA", "DVA_ALLOCATE" },
+ { 'D', "DF", "DVA_FREE" },
+ { 'D', "DC", "DVA_CLAIM" },
+ { 'R', "R ", "READY" },
+ { 'V', "VS", "VDEV_IO_START" },
+ { 'V', "VD", "VDEV_IO_DONE" },
+ { 'V', "VA", "VDEV_IO_ASSESS" },
+ { 'C', "CV", "CHECKSUM_VERIFY" },
+ { 'X', "X ", "DONE" },
+)
+/* END CSTYLED */
+
+/* ZIO priority: zio_priority_t, typically zio->io_priority */
+/* BEGIN CSTYLED */
+_VALSTR_ENUM_IMPL(zio_priority,
+ "SYNC_READ",
+ "SYNC_WRITE",
+ "ASYNC_READ",
+ "ASYNC_WRITE",
+ "SCRUB",
+ "REMOVAL",
+ "INITIALIZING",
+ "TRIM",
+ "REBUILD",
+ "[NUM_QUEUEABLE]",
+ "NOW",
+)
+/* END CSTYLED */
+
+#undef _VALSTR_BITFIELD_IMPL
+#undef _VALSTR_ENUM_IMPL