1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | /* Copyright (C) 2022 Kent Overstreet */ |
3 | |
4 | #ifndef _BCACHEFS_PRINTBUF_H |
5 | #define _BCACHEFS_PRINTBUF_H |
6 | |
7 | /* |
8 | * Printbufs: Simple strings for printing to, with optional heap allocation |
9 | * |
10 | * This code has provisions for use in userspace, to aid in making other code |
11 | * portable between kernelspace and userspace. |
12 | * |
13 | * Basic example: |
14 | * struct printbuf buf = PRINTBUF; |
15 | * |
16 | * prt_printf(&buf, "foo="); |
17 | * foo_to_text(&buf, foo); |
18 | * printk("%s", buf.buf); |
19 | * printbuf_exit(&buf); |
20 | * |
21 | * Or |
22 | * struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size) |
23 | * |
24 | * We can now write pretty printers instead of writing code that dumps |
25 | * everything to the kernel log buffer, and then those pretty-printers can be |
26 | * used by other code that outputs to kernel log, sysfs, debugfs, etc. |
27 | * |
28 | * Memory allocation: Outputing to a printbuf may allocate memory. This |
29 | * allocation is done with GFP_KERNEL, by default: use the newer |
30 | * memalloc_*_(save|restore) functions as needed. |
31 | * |
32 | * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory allocations |
33 | * will be done with GFP_NOWAIT if printbuf->atomic is nonzero. |
34 | * |
35 | * It's allowed to grab the output buffer and free it later with kfree() instead |
36 | * of using printbuf_exit(), if the user just needs a heap allocated string at |
37 | * the end. |
38 | * |
39 | * Memory allocation failures: We don't return errors directly, because on |
40 | * memory allocation failure we usually don't want to bail out and unwind - we |
41 | * want to print what we've got, on a best-effort basis. But code that does want |
42 | * to return -ENOMEM may check printbuf.allocation_failure. |
43 | * |
44 | * Indenting, tabstops: |
45 | * |
46 | * To aid is writing multi-line pretty printers spread across multiple |
47 | * functions, printbufs track the current indent level. |
48 | * |
49 | * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent |
50 | * level, respectively. |
51 | * |
52 | * To use tabstops, set printbuf->tabstops[]; they are in units of spaces, from |
53 | * start of line. Once set, prt_tab() will output spaces up to the next tabstop. |
54 | * prt_tab_rjust() will also advance the current line of text up to the next |
55 | * tabstop, but it does so by shifting text since the previous tabstop up to the |
56 | * next tabstop - right justifying it. |
57 | * |
58 | * Make sure you use prt_newline() instead of \n in the format string for indent |
59 | * level and tabstops to work corretly. |
60 | * |
61 | * Output units: printbuf->units exists to tell pretty-printers how to output |
62 | * numbers: a raw value (e.g. directly from a superblock field), as bytes, or as |
63 | * human readable bytes. prt_units() obeys it. |
64 | */ |
65 | |
66 | #include <linux/kernel.h> |
67 | #include <linux/string.h> |
68 | |
69 | enum printbuf_si { |
70 | PRINTBUF_UNITS_2, /* use binary powers of 2^10 */ |
71 | PRINTBUF_UNITS_10, /* use powers of 10^3 (standard SI) */ |
72 | }; |
73 | |
74 | #define PRINTBUF_INLINE_TABSTOPS 6 |
75 | |
76 | struct printbuf { |
77 | char *buf; |
78 | unsigned size; |
79 | unsigned pos; |
80 | unsigned last_newline; |
81 | unsigned last_field; |
82 | unsigned indent; |
83 | /* |
84 | * If nonzero, allocations will be done with GFP_ATOMIC: |
85 | */ |
86 | u8 atomic; |
87 | bool allocation_failure:1; |
88 | bool heap_allocated:1; |
89 | enum printbuf_si si_units:1; |
90 | bool human_readable_units:1; |
91 | bool has_indent_or_tabstops:1; |
92 | bool suppress_indent_tabstop_handling:1; |
93 | u8 nr_tabstops; |
94 | |
95 | /* |
96 | * Do not modify directly: use printbuf_tabstop_add(), |
97 | * printbuf_tabstop_get() |
98 | */ |
99 | u8 cur_tabstop; |
100 | u8 _tabstops[PRINTBUF_INLINE_TABSTOPS]; |
101 | }; |
102 | |
103 | int bch2_printbuf_make_room(struct printbuf *, unsigned); |
104 | __printf(2, 3) void bch2_prt_printf(struct printbuf *out, const char *fmt, ...); |
105 | __printf(2, 0) void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list); |
106 | const char *bch2_printbuf_str(const struct printbuf *); |
107 | void bch2_printbuf_exit(struct printbuf *); |
108 | |
109 | void bch2_printbuf_tabstops_reset(struct printbuf *); |
110 | void bch2_printbuf_tabstop_pop(struct printbuf *); |
111 | int bch2_printbuf_tabstop_push(struct printbuf *, unsigned); |
112 | |
113 | void bch2_printbuf_indent_add(struct printbuf *, unsigned); |
114 | void bch2_printbuf_indent_sub(struct printbuf *, unsigned); |
115 | |
116 | void bch2_prt_newline(struct printbuf *); |
117 | void bch2_prt_tab(struct printbuf *); |
118 | void bch2_prt_tab_rjust(struct printbuf *); |
119 | |
120 | void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned); |
121 | void bch2_prt_human_readable_u64(struct printbuf *, u64); |
122 | void bch2_prt_human_readable_s64(struct printbuf *, s64); |
123 | void bch2_prt_units_u64(struct printbuf *, u64); |
124 | void bch2_prt_units_s64(struct printbuf *, s64); |
125 | void bch2_prt_string_option(struct printbuf *, const char * const[], size_t); |
126 | void bch2_prt_bitflags(struct printbuf *, const char * const[], u64); |
127 | void bch2_prt_bitflags_vector(struct printbuf *, const char * const[], |
128 | unsigned long *, unsigned); |
129 | |
130 | /* Initializer for a heap allocated printbuf: */ |
131 | #define PRINTBUF ((struct printbuf) { .heap_allocated = true }) |
132 | |
133 | /* Initializer a printbuf that points to an external buffer: */ |
134 | #define PRINTBUF_EXTERN(_buf, _size) \ |
135 | ((struct printbuf) { \ |
136 | .buf = _buf, \ |
137 | .size = _size, \ |
138 | }) |
139 | |
140 | /* |
141 | * Returns size remaining of output buffer: |
142 | */ |
143 | static inline unsigned printbuf_remaining_size(struct printbuf *out) |
144 | { |
145 | return out->pos < out->size ? out->size - out->pos : 0; |
146 | } |
147 | |
148 | /* |
149 | * Returns number of characters we can print to the output buffer - i.e. |
150 | * excluding the terminating nul: |
151 | */ |
152 | static inline unsigned printbuf_remaining(struct printbuf *out) |
153 | { |
154 | return out->pos < out->size ? out->size - out->pos - 1 : 0; |
155 | } |
156 | |
157 | static inline unsigned printbuf_written(struct printbuf *out) |
158 | { |
159 | return out->size ? min(out->pos, out->size - 1) : 0; |
160 | } |
161 | |
162 | /* |
163 | * Returns true if output was truncated: |
164 | */ |
165 | static inline bool printbuf_overflowed(struct printbuf *out) |
166 | { |
167 | return out->pos >= out->size; |
168 | } |
169 | |
170 | static inline void printbuf_nul_terminate(struct printbuf *out) |
171 | { |
172 | bch2_printbuf_make_room(out, 1); |
173 | |
174 | if (out->pos < out->size) |
175 | out->buf[out->pos] = 0; |
176 | else if (out->size) |
177 | out->buf[out->size - 1] = 0; |
178 | } |
179 | |
180 | /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */ |
181 | static inline void __prt_char_reserved(struct printbuf *out, char c) |
182 | { |
183 | if (printbuf_remaining(out)) |
184 | out->buf[out->pos] = c; |
185 | out->pos++; |
186 | } |
187 | |
188 | /* Doesn't nul terminate: */ |
189 | static inline void __prt_char(struct printbuf *out, char c) |
190 | { |
191 | bch2_printbuf_make_room(out, 1); |
192 | __prt_char_reserved(out, c); |
193 | } |
194 | |
195 | static inline void prt_char(struct printbuf *out, char c) |
196 | { |
197 | __prt_char(out, c); |
198 | printbuf_nul_terminate(out); |
199 | } |
200 | |
201 | static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n) |
202 | { |
203 | unsigned i, can_print = min(n, printbuf_remaining(out)); |
204 | |
205 | for (i = 0; i < can_print; i++) |
206 | out->buf[out->pos++] = c; |
207 | out->pos += n - can_print; |
208 | } |
209 | |
210 | static inline void prt_chars(struct printbuf *out, char c, unsigned n) |
211 | { |
212 | bch2_printbuf_make_room(out, n); |
213 | __prt_chars_reserved(out, c, n); |
214 | printbuf_nul_terminate(out); |
215 | } |
216 | |
217 | static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n) |
218 | { |
219 | unsigned i, can_print; |
220 | |
221 | bch2_printbuf_make_room(out, n); |
222 | |
223 | can_print = min(n, printbuf_remaining(out)); |
224 | |
225 | for (i = 0; i < can_print; i++) |
226 | out->buf[out->pos++] = ((char *) b)[i]; |
227 | out->pos += n - can_print; |
228 | |
229 | printbuf_nul_terminate(out); |
230 | } |
231 | |
232 | static inline void prt_str(struct printbuf *out, const char *str) |
233 | { |
234 | prt_bytes(out, b: str, strlen(str)); |
235 | } |
236 | |
237 | static inline void prt_str_indented(struct printbuf *out, const char *str) |
238 | { |
239 | bch2_prt_bytes_indented(out, str, strlen(str)); |
240 | } |
241 | |
242 | static inline void prt_hex_byte(struct printbuf *out, u8 byte) |
243 | { |
244 | bch2_printbuf_make_room(out, 2); |
245 | __prt_char_reserved(out, hex_asc_hi(byte)); |
246 | __prt_char_reserved(out, hex_asc_lo(byte)); |
247 | printbuf_nul_terminate(out); |
248 | } |
249 | |
250 | static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte) |
251 | { |
252 | bch2_printbuf_make_room(out, 2); |
253 | __prt_char_reserved(out, hex_asc_upper_hi(byte)); |
254 | __prt_char_reserved(out, hex_asc_upper_lo(byte)); |
255 | printbuf_nul_terminate(out); |
256 | } |
257 | |
258 | /** |
259 | * printbuf_reset - re-use a printbuf without freeing and re-initializing it: |
260 | */ |
261 | static inline void printbuf_reset(struct printbuf *buf) |
262 | { |
263 | buf->pos = 0; |
264 | buf->allocation_failure = 0; |
265 | buf->indent = 0; |
266 | buf->nr_tabstops = 0; |
267 | buf->cur_tabstop = 0; |
268 | } |
269 | |
270 | /** |
271 | * printbuf_atomic_inc - mark as entering an atomic section |
272 | */ |
273 | static inline void printbuf_atomic_inc(struct printbuf *buf) |
274 | { |
275 | buf->atomic++; |
276 | } |
277 | |
278 | /** |
279 | * printbuf_atomic_inc - mark as leaving an atomic section |
280 | */ |
281 | static inline void printbuf_atomic_dec(struct printbuf *buf) |
282 | { |
283 | buf->atomic--; |
284 | } |
285 | |
286 | #endif /* _BCACHEFS_PRINTBUF_H */ |
287 | |