Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
 69enum 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
 76struct 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
103int 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);
106const char *bch2_printbuf_str(const struct printbuf *);
107void bch2_printbuf_exit(struct printbuf *);
108
109void bch2_printbuf_tabstops_reset(struct printbuf *);
110void bch2_printbuf_tabstop_pop(struct printbuf *);
111int bch2_printbuf_tabstop_push(struct printbuf *, unsigned);
112
113void bch2_printbuf_indent_add(struct printbuf *, unsigned);
114void bch2_printbuf_indent_sub(struct printbuf *, unsigned);
115
116void bch2_prt_newline(struct printbuf *);
117void bch2_prt_tab(struct printbuf *);
118void bch2_prt_tab_rjust(struct printbuf *);
119
120void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned);
121void bch2_prt_human_readable_u64(struct printbuf *, u64);
122void bch2_prt_human_readable_s64(struct printbuf *, s64);
123void bch2_prt_units_u64(struct printbuf *, u64);
124void bch2_prt_units_s64(struct printbuf *, s64);
125void bch2_prt_string_option(struct printbuf *, const char * const[], size_t);
126void bch2_prt_bitflags(struct printbuf *, const char * const[], u64);
127void 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 */
143static 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 */
152static inline unsigned printbuf_remaining(struct printbuf *out)
153{
154	return out->pos < out->size ? out->size - out->pos - 1 : 0;
155}
156
157static 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 */
165static inline bool printbuf_overflowed(struct printbuf *out)
166{
167	return out->pos >= out->size;
168}
169
170static 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: */
181static 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: */
189static 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
195static inline void prt_char(struct printbuf *out, char c)
196{
197	__prt_char(out, c);
198	printbuf_nul_terminate(out);
199}
200
201static 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
210static 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
217static 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
232static inline void prt_str(struct printbuf *out, const char *str)
233{
234	prt_bytes(out, str, strlen(str));
235}
236
237static inline void prt_str_indented(struct printbuf *out, const char *str)
238{
239	bch2_prt_bytes_indented(out, str, strlen(str));
240}
241
242static 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
250static 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 */
261static 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 */
273static 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 */
281static inline void printbuf_atomic_dec(struct printbuf *buf)
282{
283	buf->atomic--;
284}
285
286#endif /* _BCACHEFS_PRINTBUF_H */