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 bool overflow:1;
90 enum printbuf_si si_units:1;
91 bool human_readable_units:1;
92 bool has_indent_or_tabstops:1;
93 bool suppress_indent_tabstop_handling:1;
94 u8 nr_tabstops;
95
96 /*
97 * Do not modify directly: use printbuf_tabstop_add(),
98 * printbuf_tabstop_get()
99 */
100 u8 cur_tabstop;
101 u8 _tabstops[PRINTBUF_INLINE_TABSTOPS];
102 };
103
104 int bch2_printbuf_make_room(struct printbuf *, unsigned);
105 __printf(2, 3) void bch2_prt_printf(struct printbuf *out, const char *fmt, ...);
106 __printf(2, 0) void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list);
107 const char *bch2_printbuf_str(const struct printbuf *);
108 void bch2_printbuf_exit(struct printbuf *);
109
110 void bch2_printbuf_tabstops_reset(struct printbuf *);
111 void bch2_printbuf_tabstop_pop(struct printbuf *);
112 int bch2_printbuf_tabstop_push(struct printbuf *, unsigned);
113
114 void bch2_printbuf_indent_add(struct printbuf *, unsigned);
115 void bch2_printbuf_indent_sub(struct printbuf *, unsigned);
116
117 void bch2_prt_newline(struct printbuf *);
118 void bch2_prt_tab(struct printbuf *);
119 void bch2_prt_tab_rjust(struct printbuf *);
120
121 void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned);
122 void bch2_prt_human_readable_u64(struct printbuf *, u64);
123 void bch2_prt_human_readable_s64(struct printbuf *, s64);
124 void bch2_prt_units_u64(struct printbuf *, u64);
125 void bch2_prt_units_s64(struct printbuf *, s64);
126 void bch2_prt_string_option(struct printbuf *, const char * const[], size_t);
127 void bch2_prt_bitflags(struct printbuf *, const char * const[], u64);
128 void bch2_prt_bitflags_vector(struct printbuf *, const char * const[],
129 unsigned long *, unsigned);
130
131 /* Initializer for a heap allocated printbuf: */
132 #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
133
134 /* Initializer a printbuf that points to an external buffer: */
135 #define PRINTBUF_EXTERN(_buf, _size) \
136 ((struct printbuf) { \
137 .buf = _buf, \
138 .size = _size, \
139 })
140
141 /*
142 * Returns size remaining of output buffer:
143 */
printbuf_remaining_size(struct printbuf * out)144 static inline unsigned printbuf_remaining_size(struct printbuf *out)
145 {
146 if (WARN_ON(out->size && out->pos >= out->size))
147 out->pos = out->size - 1;
148 return out->size - out->pos;
149 }
150
151 /*
152 * Returns number of characters we can print to the output buffer - i.e.
153 * excluding the terminating nul:
154 */
printbuf_remaining(struct printbuf * out)155 static inline unsigned printbuf_remaining(struct printbuf *out)
156 {
157 return out->size ? printbuf_remaining_size(out) - 1 : 0;
158 }
159
printbuf_written(struct printbuf * out)160 static inline unsigned printbuf_written(struct printbuf *out)
161 {
162 return out->size ? min(out->pos, out->size - 1) : 0;
163 }
164
printbuf_nul_terminate_reserved(struct printbuf * out)165 static inline void printbuf_nul_terminate_reserved(struct printbuf *out)
166 {
167 if (WARN_ON(out->size && out->pos >= out->size))
168 out->pos = out->size - 1;
169 if (out->size)
170 out->buf[out->pos] = 0;
171 }
172
printbuf_nul_terminate(struct printbuf * out)173 static inline void printbuf_nul_terminate(struct printbuf *out)
174 {
175 bch2_printbuf_make_room(out, 1);
176 printbuf_nul_terminate_reserved(out);
177 }
178
179 /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */
__prt_char_reserved(struct printbuf * out,char c)180 static inline void __prt_char_reserved(struct printbuf *out, char c)
181 {
182 if (printbuf_remaining(out))
183 out->buf[out->pos++] = c;
184 }
185
186 /* Doesn't nul terminate: */
__prt_char(struct printbuf * out,char c)187 static inline void __prt_char(struct printbuf *out, char c)
188 {
189 bch2_printbuf_make_room(out, 1);
190 __prt_char_reserved(out, c);
191 }
192
prt_char(struct printbuf * out,char c)193 static inline void prt_char(struct printbuf *out, char c)
194 {
195 bch2_printbuf_make_room(out, 2);
196 __prt_char_reserved(out, c);
197 printbuf_nul_terminate_reserved(out);
198 }
199
__prt_chars_reserved(struct printbuf * out,char c,unsigned n)200 static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
201 {
202 unsigned can_print = min(n, printbuf_remaining(out));
203
204 for (unsigned i = 0; i < can_print; i++)
205 out->buf[out->pos++] = c;
206 }
207
prt_chars(struct printbuf * out,char c,unsigned n)208 static inline void prt_chars(struct printbuf *out, char c, unsigned n)
209 {
210 bch2_printbuf_make_room(out, n);
211 __prt_chars_reserved(out, c, n);
212 printbuf_nul_terminate_reserved(out);
213 }
214
prt_bytes(struct printbuf * out,const void * b,unsigned n)215 static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
216 {
217 bch2_printbuf_make_room(out, n);
218
219 unsigned can_print = min(n, printbuf_remaining(out));
220
221 for (unsigned i = 0; i < can_print; i++)
222 out->buf[out->pos++] = ((char *) b)[i];
223
224 printbuf_nul_terminate(out);
225 }
226
prt_str(struct printbuf * out,const char * str)227 static inline void prt_str(struct printbuf *out, const char *str)
228 {
229 prt_bytes(out, str, strlen(str));
230 }
231
prt_str_indented(struct printbuf * out,const char * str)232 static inline void prt_str_indented(struct printbuf *out, const char *str)
233 {
234 bch2_prt_bytes_indented(out, str, strlen(str));
235 }
236
prt_hex_byte(struct printbuf * out,u8 byte)237 static inline void prt_hex_byte(struct printbuf *out, u8 byte)
238 {
239 bch2_printbuf_make_room(out, 3);
240 __prt_char_reserved(out, hex_asc_hi(byte));
241 __prt_char_reserved(out, hex_asc_lo(byte));
242 printbuf_nul_terminate_reserved(out);
243 }
244
prt_hex_byte_upper(struct printbuf * out,u8 byte)245 static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
246 {
247 bch2_printbuf_make_room(out, 3);
248 __prt_char_reserved(out, hex_asc_upper_hi(byte));
249 __prt_char_reserved(out, hex_asc_upper_lo(byte));
250 printbuf_nul_terminate_reserved(out);
251 }
252
253 /**
254 * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
255 */
printbuf_reset(struct printbuf * buf)256 static inline void printbuf_reset(struct printbuf *buf)
257 {
258 buf->pos = 0;
259 buf->allocation_failure = 0;
260 buf->indent = 0;
261 buf->nr_tabstops = 0;
262 buf->cur_tabstop = 0;
263 }
264
265 /**
266 * printbuf_atomic_inc - mark as entering an atomic section
267 */
printbuf_atomic_inc(struct printbuf * buf)268 static inline void printbuf_atomic_inc(struct printbuf *buf)
269 {
270 buf->atomic++;
271 }
272
273 /**
274 * printbuf_atomic_inc - mark as leaving an atomic section
275 */
printbuf_atomic_dec(struct printbuf * buf)276 static inline void printbuf_atomic_dec(struct printbuf *buf)
277 {
278 buf->atomic--;
279 }
280
281 #endif /* _BCACHEFS_PRINTBUF_H */
282