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