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