xref: /linux/fs/bcachefs/printbuf.h (revision ff0905bbf991f4337b5ebc19c0d43525ebb0d96b)
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_add_nextline(struct printbuf *, unsigned);
116 void bch2_printbuf_indent_sub(struct printbuf *, unsigned);
117 
118 void bch2_prt_newline(struct printbuf *);
119 void bch2_printbuf_strip_trailing_newline(struct printbuf *);
120 void bch2_prt_tab(struct printbuf *);
121 void bch2_prt_tab_rjust(struct printbuf *);
122 
123 void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned);
124 void bch2_prt_human_readable_u64(struct printbuf *, u64);
125 void bch2_prt_human_readable_s64(struct printbuf *, s64);
126 void bch2_prt_units_u64(struct printbuf *, u64);
127 void bch2_prt_units_s64(struct printbuf *, s64);
128 void bch2_prt_string_option(struct printbuf *, const char * const[], size_t);
129 void bch2_prt_bitflags(struct printbuf *, const char * const[], u64);
130 void bch2_prt_bitflags_vector(struct printbuf *, const char * const[],
131 			      unsigned long *, unsigned);
132 
133 /* Initializer for a heap allocated printbuf: */
134 #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
135 
136 /* Initializer a printbuf that points to an external buffer: */
137 #define PRINTBUF_EXTERN(_buf, _size)			\
138 ((struct printbuf) {					\
139 	.buf	= _buf,					\
140 	.size	= _size,				\
141 })
142 
bch2_printbuf_init(void)143 static inline struct printbuf bch2_printbuf_init(void)
144 {
145 	return PRINTBUF;
146 }
147 
DEFINE_CLASS(printbuf,struct printbuf,bch2_printbuf_exit (& _T),bch2_printbuf_init (),void)148 DEFINE_CLASS(printbuf, struct printbuf,
149 	     bch2_printbuf_exit(&_T), bch2_printbuf_init(), void)
150 
151 /*
152  * Returns size remaining of output buffer:
153  */
154 static inline unsigned printbuf_remaining_size(struct printbuf *out)
155 {
156 	if (WARN_ON(out->size && out->pos >= out->size))
157 		out->pos = out->size - 1;
158 	return out->size - out->pos;
159 }
160 
161 /*
162  * Returns number of characters we can print to the output buffer - i.e.
163  * excluding the terminating nul:
164  */
printbuf_remaining(struct printbuf * out)165 static inline unsigned printbuf_remaining(struct printbuf *out)
166 {
167 	return out->size ? printbuf_remaining_size(out) - 1 : 0;
168 }
169 
printbuf_written(struct printbuf * out)170 static inline unsigned printbuf_written(struct printbuf *out)
171 {
172 	return out->size ? min(out->pos, out->size - 1) : 0;
173 }
174 
printbuf_nul_terminate_reserved(struct printbuf * out)175 static inline void printbuf_nul_terminate_reserved(struct printbuf *out)
176 {
177 	if (WARN_ON(out->size && out->pos >= out->size))
178 		out->pos = out->size - 1;
179 	if (out->size)
180 		out->buf[out->pos] = 0;
181 }
182 
printbuf_nul_terminate(struct printbuf * out)183 static inline void printbuf_nul_terminate(struct printbuf *out)
184 {
185 	bch2_printbuf_make_room(out, 1);
186 	printbuf_nul_terminate_reserved(out);
187 }
188 
189 /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */
__prt_char_reserved(struct printbuf * out,char c)190 static inline void __prt_char_reserved(struct printbuf *out, char c)
191 {
192 	if (printbuf_remaining(out))
193 		out->buf[out->pos++] = c;
194 }
195 
196 /* Doesn't nul terminate: */
__prt_char(struct printbuf * out,char c)197 static inline void __prt_char(struct printbuf *out, char c)
198 {
199 	bch2_printbuf_make_room(out, 1);
200 	__prt_char_reserved(out, c);
201 }
202 
prt_char(struct printbuf * out,char c)203 static inline void prt_char(struct printbuf *out, char c)
204 {
205 	bch2_printbuf_make_room(out, 2);
206 	__prt_char_reserved(out, c);
207 	printbuf_nul_terminate_reserved(out);
208 }
209 
__prt_chars_reserved(struct printbuf * out,char c,unsigned n)210 static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
211 {
212 	unsigned can_print = min(n, printbuf_remaining(out));
213 
214 	for (unsigned i = 0; i < can_print; i++)
215 		out->buf[out->pos++] = c;
216 }
217 
prt_chars(struct printbuf * out,char c,unsigned n)218 static inline void prt_chars(struct printbuf *out, char c, unsigned n)
219 {
220 	bch2_printbuf_make_room(out, n);
221 	__prt_chars_reserved(out, c, n);
222 	printbuf_nul_terminate_reserved(out);
223 }
224 
prt_bytes(struct printbuf * out,const void * b,unsigned n)225 static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
226 {
227 	bch2_printbuf_make_room(out, n);
228 
229 	unsigned can_print = min(n, printbuf_remaining(out));
230 
231 	for (unsigned i = 0; i < can_print; i++)
232 		out->buf[out->pos++] = ((char *) b)[i];
233 
234 	printbuf_nul_terminate(out);
235 }
236 
prt_str(struct printbuf * out,const char * str)237 static inline void prt_str(struct printbuf *out, const char *str)
238 {
239 	prt_bytes(out, str, strlen(str));
240 }
241 
prt_str_indented(struct printbuf * out,const char * str)242 static inline void prt_str_indented(struct printbuf *out, const char *str)
243 {
244 	bch2_prt_bytes_indented(out, str, strlen(str));
245 }
246 
prt_hex_byte(struct printbuf * out,u8 byte)247 static inline void prt_hex_byte(struct printbuf *out, u8 byte)
248 {
249 	bch2_printbuf_make_room(out, 3);
250 	__prt_char_reserved(out, hex_asc_hi(byte));
251 	__prt_char_reserved(out, hex_asc_lo(byte));
252 	printbuf_nul_terminate_reserved(out);
253 }
254 
prt_hex_byte_upper(struct printbuf * out,u8 byte)255 static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
256 {
257 	bch2_printbuf_make_room(out, 3);
258 	__prt_char_reserved(out, hex_asc_upper_hi(byte));
259 	__prt_char_reserved(out, hex_asc_upper_lo(byte));
260 	printbuf_nul_terminate_reserved(out);
261 }
262 
printbuf_reset_keep_tabstops(struct printbuf * buf)263 static inline void printbuf_reset_keep_tabstops(struct printbuf *buf)
264 {
265 	buf->pos		= 0;
266 	buf->allocation_failure	= 0;
267 	buf->last_newline	= 0;
268 	buf->last_field		= 0;
269 	buf->indent		= 0;
270 	buf->cur_tabstop	= 0;
271 }
272 
273 /**
274  * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
275  */
printbuf_reset(struct printbuf * buf)276 static inline void printbuf_reset(struct printbuf *buf)
277 {
278 	printbuf_reset_keep_tabstops(buf);
279 	buf->nr_tabstops	= 0;
280 }
281 
282 /**
283  * printbuf_atomic_inc - mark as entering an atomic section
284  */
printbuf_atomic_inc(struct printbuf * buf)285 static inline void printbuf_atomic_inc(struct printbuf *buf)
286 {
287 	buf->atomic++;
288 }
289 
290 /**
291  * printbuf_atomic_inc - mark as leaving an atomic section
292  */
printbuf_atomic_dec(struct printbuf * buf)293 static inline void printbuf_atomic_dec(struct printbuf *buf)
294 {
295 	buf->atomic--;
296 }
297 
298 #endif /* _BCACHEFS_PRINTBUF_H */
299