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