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