xref: /freebsd/sys/contrib/openzfs/module/zcommon/zfs_valstr.c (revision df58e8b1506f241670be86a560fb6e8432043aee)
161145dc2SMartin 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;
42071ab5a1SMartin Matuska 
43071ab5a1SMartin Matuska 	/* 2 byte name + 1 byte NULL terminator to make GCC happy */
44071ab5a1SMartin Matuska 	const char	vb_pair[3];
45e2df9bb4SMartin Matuska 	const char	*vb_name;
46e2df9bb4SMartin Matuska } valstr_bit_t;
47e2df9bb4SMartin Matuska 
48e2df9bb4SMartin Matuska /*
49e2df9bb4SMartin Matuska  * Emits a character for each bit in `bits`, up to the number of elements
50e2df9bb4SMartin Matuska  * in the table. Set bits get the character in vb_bit, clear bits get a
51e2df9bb4SMartin Matuska  * space. This results in all strings having the same width, for easier
52e2df9bb4SMartin Matuska  * visual comparison.
53e2df9bb4SMartin Matuska  */
54e2df9bb4SMartin Matuska static size_t
valstr_bitfield_bits(const valstr_bit_t * table,const size_t nelems,uint64_t bits,char * out,size_t outlen)55e2df9bb4SMartin Matuska valstr_bitfield_bits(const valstr_bit_t *table, const size_t nelems,
56e2df9bb4SMartin Matuska     uint64_t bits, char *out, size_t outlen)
57e2df9bb4SMartin Matuska {
58e2df9bb4SMartin Matuska 	ASSERT(out);
59e2df9bb4SMartin Matuska 	size_t n = 0;
60e2df9bb4SMartin Matuska 	for (int b = 0; b < nelems; b++) {
61e2df9bb4SMartin Matuska 		if (n == outlen)
62e2df9bb4SMartin Matuska 			break;
63e2df9bb4SMartin Matuska 		uint64_t mask = (1ULL << b);
64e2df9bb4SMartin Matuska 		out[n++] = (bits & mask) ? table[b].vb_bit : ' ';
65e2df9bb4SMartin Matuska 	}
66e2df9bb4SMartin Matuska 	if (n < outlen)
67e2df9bb4SMartin Matuska 		out[n++] = '\0';
68e2df9bb4SMartin Matuska 	return (n);
69e2df9bb4SMartin Matuska }
70e2df9bb4SMartin Matuska 
71e2df9bb4SMartin Matuska /*
72e2df9bb4SMartin Matuska  * Emits a two-char pair for each bit set in `bits`, taken from vb_pair, and
73e2df9bb4SMartin Matuska  * separated by a `|` character. This gives a concise representation of the
74e2df9bb4SMartin Matuska  * whole value.
75e2df9bb4SMartin Matuska  */
76e2df9bb4SMartin Matuska static size_t
valstr_bitfield_pairs(const valstr_bit_t * table,const size_t nelems,uint64_t bits,char * out,size_t outlen)77e2df9bb4SMartin Matuska valstr_bitfield_pairs(const valstr_bit_t *table, const size_t nelems,
78e2df9bb4SMartin Matuska     uint64_t bits, char *out, size_t outlen)
79e2df9bb4SMartin Matuska {
80e2df9bb4SMartin Matuska 	ASSERT(out);
81e2df9bb4SMartin Matuska 	size_t n = 0;
82e2df9bb4SMartin Matuska 	for (int b = 0; b < nelems; b++) {
83e2df9bb4SMartin Matuska 		ASSERT3U(n, <=, outlen);
84e2df9bb4SMartin Matuska 		if (n == outlen)
85e2df9bb4SMartin Matuska 			break;
86e2df9bb4SMartin Matuska 		uint64_t mask = (1ULL << b);
87e2df9bb4SMartin Matuska 		if (bits & mask) {
88e2df9bb4SMartin Matuska 			size_t len = (n > 0) ? 3 : 2;
89e2df9bb4SMartin Matuska 			if (n > outlen-len)
90e2df9bb4SMartin Matuska 				break;
91e2df9bb4SMartin Matuska 			if (n > 0)
92e2df9bb4SMartin Matuska 				out[n++] = '|';
93e2df9bb4SMartin Matuska 			out[n++] = table[b].vb_pair[0];
94e2df9bb4SMartin Matuska 			out[n++] = table[b].vb_pair[1];
95e2df9bb4SMartin Matuska 		}
96e2df9bb4SMartin Matuska 	}
97e2df9bb4SMartin Matuska 	if (n < outlen)
98e2df9bb4SMartin Matuska 		out[n++] = '\0';
99e2df9bb4SMartin Matuska 	return (n);
100e2df9bb4SMartin Matuska }
101e2df9bb4SMartin Matuska 
102e2df9bb4SMartin Matuska /*
103e2df9bb4SMartin Matuska  * Emits the full name for each bit set in `bits`, taken from vb_name, and
104e2df9bb4SMartin Matuska  * separated by a space. This unambiguously shows the entire set of bits, but
105e2df9bb4SMartin Matuska  * can get very long.
106e2df9bb4SMartin Matuska  */
107e2df9bb4SMartin Matuska static size_t
valstr_bitfield_str(const valstr_bit_t * table,const size_t nelems,uint64_t bits,char * out,size_t outlen)108e2df9bb4SMartin Matuska valstr_bitfield_str(const valstr_bit_t *table, const size_t nelems,
109e2df9bb4SMartin Matuska     uint64_t bits, char *out, size_t outlen)
110e2df9bb4SMartin Matuska {
111e2df9bb4SMartin Matuska 	ASSERT(out);
112e2df9bb4SMartin Matuska 	size_t n = 0;
113e2df9bb4SMartin Matuska 	for (int b = 0; b < nelems; b++) {
114e2df9bb4SMartin Matuska 		ASSERT3U(n, <=, outlen);
115e2df9bb4SMartin Matuska 		if (n == outlen)
116e2df9bb4SMartin Matuska 			break;
117e2df9bb4SMartin Matuska 		uint64_t mask = (1ULL << b);
118e2df9bb4SMartin Matuska 		if (bits & mask) {
119e2df9bb4SMartin Matuska 			size_t len = strlen(table[b].vb_name);
120e2df9bb4SMartin Matuska 			if (n > 0)
121e2df9bb4SMartin Matuska 				len++;
122e2df9bb4SMartin Matuska 			if (n > outlen-len)
123e2df9bb4SMartin Matuska 				break;
124e2df9bb4SMartin Matuska 			if (n > 0) {
125e2df9bb4SMartin Matuska 				out[n++] = ' ';
126e2df9bb4SMartin Matuska 				len--;
127e2df9bb4SMartin Matuska 			}
128e2df9bb4SMartin Matuska 			memcpy(&out[n], table[b].vb_name, len);
129e2df9bb4SMartin Matuska 			n += len;
130e2df9bb4SMartin Matuska 		}
131e2df9bb4SMartin Matuska 	}
132e2df9bb4SMartin Matuska 	if (n < outlen)
133e2df9bb4SMartin Matuska 		out[n++] = '\0';
134e2df9bb4SMartin Matuska 	return (n);
135e2df9bb4SMartin Matuska }
136e2df9bb4SMartin Matuska 
137e2df9bb4SMartin Matuska /*
138e2df9bb4SMartin Matuska  * Emits the name of the given enum value in the table.
139e2df9bb4SMartin Matuska  */
140e2df9bb4SMartin Matuska static size_t
valstr_enum_str(const char ** table,const size_t nelems,int v,char * out,size_t outlen)141e2df9bb4SMartin Matuska valstr_enum_str(const char **table, const size_t nelems,
142e2df9bb4SMartin Matuska     int v, char *out, size_t outlen)
143e2df9bb4SMartin Matuska {
144e2df9bb4SMartin Matuska 	ASSERT(out);
145e2df9bb4SMartin Matuska 	ASSERT3U(v, <, nelems);
146e2df9bb4SMartin Matuska 	if (v >= nelems)
147e2df9bb4SMartin Matuska 		return (0);
148e2df9bb4SMartin Matuska 	return (MIN(strlcpy(out, table[v], outlen), outlen));
149e2df9bb4SMartin Matuska }
150e2df9bb4SMartin Matuska 
151e2df9bb4SMartin Matuska /*
152e2df9bb4SMartin Matuska  * These macros create the string tables for the given name, and implement
153e2df9bb4SMartin Matuska  * the public functions described in zfs_valstr.h.
154e2df9bb4SMartin Matuska  */
155e2df9bb4SMartin Matuska #define	_VALSTR_BITFIELD_IMPL(name, ...)				\
156e2df9bb4SMartin Matuska static const valstr_bit_t valstr_ ## name ## _table[] = { __VA_ARGS__ };\
157e2df9bb4SMartin Matuska size_t									\
158e2df9bb4SMartin Matuska zfs_valstr_ ## name ## _bits(uint64_t bits, char *out, size_t outlen)	\
159e2df9bb4SMartin Matuska {									\
160e2df9bb4SMartin Matuska 	return (valstr_bitfield_bits(valstr_ ## name ## _table,		\
161e2df9bb4SMartin Matuska 	    ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen));	\
162e2df9bb4SMartin Matuska }									\
163e2df9bb4SMartin Matuska 									\
164e2df9bb4SMartin Matuska size_t									\
165e2df9bb4SMartin Matuska zfs_valstr_ ## name ## _pairs(uint64_t bits, char *out, size_t outlen)	\
166e2df9bb4SMartin Matuska {									\
167e2df9bb4SMartin Matuska 	return (valstr_bitfield_pairs(valstr_ ## name ## _table,	\
168e2df9bb4SMartin Matuska 	    ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen));	\
169e2df9bb4SMartin Matuska }									\
170e2df9bb4SMartin Matuska 									\
171e2df9bb4SMartin Matuska size_t									\
172e2df9bb4SMartin Matuska zfs_valstr_ ## name(uint64_t bits, char *out, size_t outlen)		\
173e2df9bb4SMartin Matuska {									\
174e2df9bb4SMartin Matuska 	return (valstr_bitfield_str(valstr_ ## name ## _table,		\
175e2df9bb4SMartin Matuska 	    ARRAY_SIZE(valstr_ ## name ## _table), bits, out, outlen));	\
176e2df9bb4SMartin Matuska }									\
177e2df9bb4SMartin Matuska 
178e2df9bb4SMartin Matuska #define	_VALSTR_ENUM_IMPL(name, ...)					\
179e2df9bb4SMartin Matuska static const char *valstr_ ## name ## _table[] = { __VA_ARGS__ };	\
180e2df9bb4SMartin Matuska size_t									\
181e2df9bb4SMartin Matuska zfs_valstr_ ## name(int v, char *out, size_t outlen)			\
182e2df9bb4SMartin Matuska {									\
183e2df9bb4SMartin Matuska 	return (valstr_enum_str(valstr_ ## name ## _table,		\
184e2df9bb4SMartin Matuska 	    ARRAY_SIZE(valstr_ ## name ## _table), v, out, outlen));	\
185e2df9bb4SMartin Matuska }									\
186e2df9bb4SMartin Matuska 
187e2df9bb4SMartin Matuska 
188e2df9bb4SMartin Matuska /* String tables */
189e2df9bb4SMartin Matuska 
190e2df9bb4SMartin Matuska /* ZIO flags: zio_flag_t, typically zio->io_flags */
191e2df9bb4SMartin Matuska _VALSTR_BITFIELD_IMPL(zio_flag,
192e2df9bb4SMartin Matuska 	{ '.', "DA", "DONT_AGGREGATE" },
193e2df9bb4SMartin Matuska 	{ '.', "RP", "IO_REPAIR" },
194e2df9bb4SMartin Matuska 	{ '.', "SH", "SELF_HEAL" },
195e2df9bb4SMartin Matuska 	{ '.', "RS", "RESILVER" },
196e2df9bb4SMartin Matuska 	{ '.', "SC", "SCRUB" },
197e2df9bb4SMartin Matuska 	{ '.', "ST", "SCAN_THREAD" },
198e2df9bb4SMartin Matuska 	{ '.', "PH", "PHYSICAL" },
199e2df9bb4SMartin Matuska 	{ '.', "CF", "CANFAIL" },
200e2df9bb4SMartin Matuska 	{ '.', "SP", "SPECULATIVE" },
201e2df9bb4SMartin Matuska 	{ '.', "CW", "CONFIG_WRITER" },
202e2df9bb4SMartin Matuska 	{ '.', "DR", "DONT_RETRY" },
203e2df9bb4SMartin Matuska 	{ '?', "??", "[UNUSED 11]" },
204e2df9bb4SMartin Matuska 	{ '.', "ND", "NODATA" },
205e2df9bb4SMartin Matuska 	{ '.', "ID", "INDUCE_DAMAGE" },
206*df58e8b1SMartin Matuska 	{ '.', "AT", "ALLOC_THROTTLED" },
207e2df9bb4SMartin Matuska 	{ '.', "RE", "IO_RETRY" },
208e2df9bb4SMartin Matuska 	{ '.', "PR", "PROBE" },
209e2df9bb4SMartin Matuska 	{ '.', "TH", "TRYHARD" },
210e2df9bb4SMartin Matuska 	{ '.', "OP", "OPTIONAL" },
21187bf66d4SMartin Matuska 	{ '.', "RD", "DIO_READ" },
212e2df9bb4SMartin Matuska 	{ '.', "DQ", "DONT_QUEUE" },
213e2df9bb4SMartin Matuska 	{ '.', "DP", "DONT_PROPAGATE" },
214e2df9bb4SMartin Matuska 	{ '.', "BY", "IO_BYPASS" },
215e2df9bb4SMartin Matuska 	{ '.', "RW", "IO_REWRITE" },
216e2df9bb4SMartin Matuska 	{ '.', "CM", "RAW_COMPRESS" },
217e2df9bb4SMartin Matuska 	{ '.', "EN", "RAW_ENCRYPT" },
218e2df9bb4SMartin Matuska 	{ '.', "GG", "GANG_CHILD" },
219e2df9bb4SMartin Matuska 	{ '.', "DD", "DDT_CHILD" },
220e2df9bb4SMartin Matuska 	{ '.', "GF", "GODFATHER" },
221e2df9bb4SMartin Matuska 	{ '.', "NP", "NOPWRITE" },
222e2df9bb4SMartin Matuska 	{ '.', "EX", "REEXECUTED" },
223e2df9bb4SMartin Matuska 	{ '.', "DG", "DELEGATED" },
224b1c1ee44SMartin Matuska 	{ '.', "PA", "PREALLOCATED" },
225e2df9bb4SMartin Matuska )
226e2df9bb4SMartin Matuska 
227e2df9bb4SMartin Matuska /*
228e2df9bb4SMartin Matuska  * ZIO pipeline stage(s): enum zio_stage, typically zio->io_stage or
229e2df9bb4SMartin Matuska  *                        zio->io_pipeline.
230e2df9bb4SMartin Matuska  */
231e2df9bb4SMartin Matuska _VALSTR_BITFIELD_IMPL(zio_stage,
232e2df9bb4SMartin Matuska 	{ 'O', "O ", "OPEN" },
233e2df9bb4SMartin Matuska 	{ 'I', "RI", "READ_BP_INIT" },
234e2df9bb4SMartin Matuska 	{ 'I', "WI", "WRITE_BP_INIT" },
235e2df9bb4SMartin Matuska 	{ 'I', "FI", "FREE_BP_INIT" },
236e2df9bb4SMartin Matuska 	{ 'A', "IA", "ISSUE_ASYNC" },
237e2df9bb4SMartin Matuska 	{ 'W', "WC", "WRITE_COMPRESS" },
238e2df9bb4SMartin Matuska 	{ 'E', "EN", "ENCRYPT" },
239e2df9bb4SMartin Matuska 	{ 'C', "CG", "CHECKSUM_GENERATE" },
240e2df9bb4SMartin Matuska 	{ 'N', "NW", "NOP_WRITE" },
241e2df9bb4SMartin Matuska 	{ 'B', "BF", "BRT_FREE" },
242e2df9bb4SMartin Matuska 	{ 'd', "dS", "DDT_READ_START" },
243e2df9bb4SMartin Matuska 	{ 'd', "dD", "DDT_READ_DONE" },
244e2df9bb4SMartin Matuska 	{ 'd', "dW", "DDT_WRITE" },
245e2df9bb4SMartin Matuska 	{ 'd', "dF", "DDT_FREE" },
246e2df9bb4SMartin Matuska 	{ 'G', "GA", "GANG_ASSEMBLE" },
247e2df9bb4SMartin Matuska 	{ 'G', "GI", "GANG_ISSUE" },
248e2df9bb4SMartin Matuska 	{ 'D', "DT", "DVA_THROTTLE" },
249e2df9bb4SMartin Matuska 	{ 'D', "DA", "DVA_ALLOCATE" },
250e2df9bb4SMartin Matuska 	{ 'D', "DF", "DVA_FREE" },
251e2df9bb4SMartin Matuska 	{ 'D', "DC", "DVA_CLAIM" },
252e2df9bb4SMartin Matuska 	{ 'R', "R ", "READY" },
253e2df9bb4SMartin Matuska 	{ 'V', "VS", "VDEV_IO_START" },
254e2df9bb4SMartin Matuska 	{ 'V', "VD", "VDEV_IO_DONE" },
255e2df9bb4SMartin Matuska 	{ 'V', "VA", "VDEV_IO_ASSESS" },
256e2df9bb4SMartin Matuska 	{ 'C', "CV", "CHECKSUM_VERIFY" },
2577a7741afSMartin Matuska 	{ 'C', "DC", "DIO_CHECKSUM_VERIFY" },
258e2df9bb4SMartin Matuska 	{ 'X', "X ", "DONE" },
259e2df9bb4SMartin Matuska )
260e2df9bb4SMartin Matuska 
2613747329bSMartin Matuska /* ZIO type: zio_type_t, typically zio->io_type */
2623747329bSMartin Matuska _VALSTR_ENUM_IMPL(zio_type,
2633747329bSMartin Matuska 	"NULL",
2643747329bSMartin Matuska 	"READ",
2653747329bSMartin Matuska 	"WRITE",
2663747329bSMartin Matuska 	"FREE",
2673747329bSMartin Matuska 	"CLAIM",
2683747329bSMartin Matuska 	"FLUSH",
2693747329bSMartin Matuska 	"TRIM",
2703747329bSMartin Matuska )
2713747329bSMartin Matuska 
272e2df9bb4SMartin Matuska /* ZIO priority: zio_priority_t, typically zio->io_priority */
273e2df9bb4SMartin Matuska _VALSTR_ENUM_IMPL(zio_priority,
274e2df9bb4SMartin Matuska 	"SYNC_READ",
275e2df9bb4SMartin Matuska 	"SYNC_WRITE",
276e2df9bb4SMartin Matuska 	"ASYNC_READ",
277e2df9bb4SMartin Matuska 	"ASYNC_WRITE",
278e2df9bb4SMartin Matuska 	"SCRUB",
279e2df9bb4SMartin Matuska 	"REMOVAL",
280e2df9bb4SMartin Matuska 	"INITIALIZING",
281e2df9bb4SMartin Matuska 	"TRIM",
282e2df9bb4SMartin Matuska 	"REBUILD",
283e2df9bb4SMartin Matuska 	"[NUM_QUEUEABLE]",
284e2df9bb4SMartin Matuska 	"NOW",
285e2df9bb4SMartin Matuska )
286e2df9bb4SMartin Matuska 
287e2df9bb4SMartin Matuska #undef _VALSTR_BITFIELD_IMPL
288e2df9bb4SMartin Matuska #undef _VALSTR_ENUM_IMPL
289