1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /* Copyright (C) 2022 Kent Overstreet */
4 #ifndef _BCACHEFS_PRINTBUF_H
5 #define _BCACHEFS_PRINTBUF_H
8 * Printbufs: Simple strings for printing to, with optional heap allocation
10 * This code has provisions for use in userspace, to aid in making other code
11 * portable between kernelspace and userspace.
14 * struct printbuf buf = PRINTBUF;
16 * prt_printf(&buf, "foo=");
17 * foo_to_text(&buf, foo);
18 * printk("%s", buf.buf);
19 * printbuf_exit(&buf);
22 * struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size)
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.
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.
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.
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
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.
44 * Indenting, tabstops:
46 * To aid is writing multi-line pretty printers spread across multiple
47 * functions, printbufs track the current indent level.
49 * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent
50 * level, respectively.
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.
58 * Make sure you use prt_newline() instead of \n in the format string for indent
59 * level and tabstops to work corretly.
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.
66 #include <linux/kernel.h>
67 #include <linux/string.h>
70 PRINTBUF_UNITS_2
, /* use binary powers of 2^10 */
71 PRINTBUF_UNITS_10
, /* use powers of 10^3 (standard SI) */
74 #define PRINTBUF_INLINE_TABSTOPS 6
80 unsigned last_newline
;
84 * If nonzero, allocations will be done with GFP_ATOMIC:
87 bool allocation_failure
:1;
88 bool heap_allocated
: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;
97 * Do not modify directly: use printbuf_tabstop_add(),
98 * printbuf_tabstop_get()
101 u8 _tabstops
[PRINTBUF_INLINE_TABSTOPS
];
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
*);
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);
114 void bch2_printbuf_indent_add(struct printbuf
*, unsigned);
115 void bch2_printbuf_indent_sub(struct printbuf
*, unsigned);
117 void bch2_prt_newline(struct printbuf
*);
118 void bch2_printbuf_strip_trailing_newline(struct printbuf
*);
119 void bch2_prt_tab(struct printbuf
*);
120 void bch2_prt_tab_rjust(struct printbuf
*);
122 void bch2_prt_bytes_indented(struct printbuf
*, const char *, unsigned);
123 void bch2_prt_human_readable_u64(struct printbuf
*, u64
);
124 void bch2_prt_human_readable_s64(struct printbuf
*, s64
);
125 void bch2_prt_units_u64(struct printbuf
*, u64
);
126 void bch2_prt_units_s64(struct printbuf
*, s64
);
127 void bch2_prt_string_option(struct printbuf
*, const char * const[], size_t);
128 void bch2_prt_bitflags(struct printbuf
*, const char * const[], u64
);
129 void bch2_prt_bitflags_vector(struct printbuf
*, const char * const[],
130 unsigned long *, unsigned);
132 /* Initializer for a heap allocated printbuf: */
133 #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
135 /* Initializer a printbuf that points to an external buffer: */
136 #define PRINTBUF_EXTERN(_buf, _size) \
137 ((struct printbuf) { \
143 * Returns size remaining of output buffer:
145 static inline unsigned printbuf_remaining_size(struct printbuf
*out
)
147 if (WARN_ON(out
->size
&& out
->pos
>= out
->size
))
148 out
->pos
= out
->size
- 1;
149 return out
->size
- out
->pos
;
153 * Returns number of characters we can print to the output buffer - i.e.
154 * excluding the terminating nul:
156 static inline unsigned printbuf_remaining(struct printbuf
*out
)
158 return out
->size
? printbuf_remaining_size(out
) - 1 : 0;
161 static inline unsigned printbuf_written(struct printbuf
*out
)
163 return out
->size
? min(out
->pos
, out
->size
- 1) : 0;
166 static inline void printbuf_nul_terminate_reserved(struct printbuf
*out
)
168 if (WARN_ON(out
->size
&& out
->pos
>= out
->size
))
169 out
->pos
= out
->size
- 1;
171 out
->buf
[out
->pos
] = 0;
174 static inline void printbuf_nul_terminate(struct printbuf
*out
)
176 bch2_printbuf_make_room(out
, 1);
177 printbuf_nul_terminate_reserved(out
);
180 /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */
181 static inline void __prt_char_reserved(struct printbuf
*out
, char c
)
183 if (printbuf_remaining(out
))
184 out
->buf
[out
->pos
++] = c
;
187 /* Doesn't nul terminate: */
188 static inline void __prt_char(struct printbuf
*out
, char c
)
190 bch2_printbuf_make_room(out
, 1);
191 __prt_char_reserved(out
, c
);
194 static inline void prt_char(struct printbuf
*out
, char c
)
196 bch2_printbuf_make_room(out
, 2);
197 __prt_char_reserved(out
, c
);
198 printbuf_nul_terminate_reserved(out
);
201 static inline void __prt_chars_reserved(struct printbuf
*out
, char c
, unsigned n
)
203 unsigned can_print
= min(n
, printbuf_remaining(out
));
205 for (unsigned i
= 0; i
< can_print
; i
++)
206 out
->buf
[out
->pos
++] = c
;
209 static inline void prt_chars(struct printbuf
*out
, char c
, unsigned n
)
211 bch2_printbuf_make_room(out
, n
);
212 __prt_chars_reserved(out
, c
, n
);
213 printbuf_nul_terminate_reserved(out
);
216 static inline void prt_bytes(struct printbuf
*out
, const void *b
, unsigned n
)
218 bch2_printbuf_make_room(out
, n
);
220 unsigned can_print
= min(n
, printbuf_remaining(out
));
222 for (unsigned i
= 0; i
< can_print
; i
++)
223 out
->buf
[out
->pos
++] = ((char *) b
)[i
];
225 printbuf_nul_terminate(out
);
228 static inline void prt_str(struct printbuf
*out
, const char *str
)
230 prt_bytes(out
, str
, strlen(str
));
233 static inline void prt_str_indented(struct printbuf
*out
, const char *str
)
235 bch2_prt_bytes_indented(out
, str
, strlen(str
));
238 static inline void prt_hex_byte(struct printbuf
*out
, u8 byte
)
240 bch2_printbuf_make_room(out
, 3);
241 __prt_char_reserved(out
, hex_asc_hi(byte
));
242 __prt_char_reserved(out
, hex_asc_lo(byte
));
243 printbuf_nul_terminate_reserved(out
);
246 static inline void prt_hex_byte_upper(struct printbuf
*out
, u8 byte
)
248 bch2_printbuf_make_room(out
, 3);
249 __prt_char_reserved(out
, hex_asc_upper_hi(byte
));
250 __prt_char_reserved(out
, hex_asc_upper_lo(byte
));
251 printbuf_nul_terminate_reserved(out
);
255 * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
257 static inline void printbuf_reset(struct printbuf
*buf
)
260 buf
->allocation_failure
= 0;
262 buf
->nr_tabstops
= 0;
263 buf
->cur_tabstop
= 0;
267 * printbuf_atomic_inc - mark as entering an atomic section
269 static inline void printbuf_atomic_inc(struct printbuf
*buf
)
275 * printbuf_atomic_inc - mark as leaving an atomic section
277 static inline void printbuf_atomic_dec(struct printbuf
*buf
)
282 #endif /* _BCACHEFS_PRINTBUF_H */