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