/* SPDX-License-Identifier: LGPL-2.1+ */ /* Copyright (C) 2022 Kent Overstreet */ #ifndef _BCACHEFS_PRINTBUF_H #define _BCACHEFS_PRINTBUF_H /* * Printbufs: Simple strings for printing to, with optional heap allocation * * This code has provisions for use in userspace, to aid in making other code * portable between kernelspace and userspace. * * Basic example: * struct printbuf buf = PRINTBUF; * * prt_printf(&buf, "foo="); * foo_to_text(&buf, foo); * printk("%s", buf.buf); * printbuf_exit(&buf); * * Or * struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size) * * We can now write pretty printers instead of writing code that dumps * everything to the kernel log buffer, and then those pretty-printers can be * used by other code that outputs to kernel log, sysfs, debugfs, etc. * * Memory allocation: Outputing to a printbuf may allocate memory. This * allocation is done with GFP_KERNEL, by default: use the newer * memalloc_*_(save|restore) functions as needed. * * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory allocations * will be done with GFP_NOWAIT if printbuf->atomic is nonzero. * * It's allowed to grab the output buffer and free it later with kfree() instead * of using printbuf_exit(), if the user just needs a heap allocated string at * the end. * * Memory allocation failures: We don't return errors directly, because on * memory allocation failure we usually don't want to bail out and unwind - we * want to print what we've got, on a best-effort basis. But code that does want * to return -ENOMEM may check printbuf.allocation_failure. * * Indenting, tabstops: * * To aid is writing multi-line pretty printers spread across multiple * functions, printbufs track the current indent level. * * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent * level, respectively. * * To use tabstops, set printbuf->tabstops[]; they are in units of spaces, from * start of line. Once set, prt_tab() will output spaces up to the next tabstop. * prt_tab_rjust() will also advance the current line of text up to the next * tabstop, but it does so by shifting text since the previous tabstop up to the * next tabstop - right justifying it. * * Make sure you use prt_newline() instead of \n in the format string for indent * level and tabstops to work corretly. * * Output units: printbuf->units exists to tell pretty-printers how to output * numbers: a raw value (e.g. directly from a superblock field), as bytes, or as * human readable bytes. prt_units() obeys it. */ #include <linux/kernel.h> #include <linux/string.h> enum printbuf_si { … }; #define PRINTBUF_INLINE_TABSTOPS … struct printbuf { … }; int bch2_printbuf_make_room(struct printbuf *, unsigned); __printf(2, 3) void bch2_prt_printf(struct printbuf *out, const char *fmt, ...); __printf(2, 0) void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list); const char *bch2_printbuf_str(const struct printbuf *); void bch2_printbuf_exit(struct printbuf *); void bch2_printbuf_tabstops_reset(struct printbuf *); void bch2_printbuf_tabstop_pop(struct printbuf *); int bch2_printbuf_tabstop_push(struct printbuf *, unsigned); void bch2_printbuf_indent_add(struct printbuf *, unsigned); void bch2_printbuf_indent_sub(struct printbuf *, unsigned); void bch2_prt_newline(struct printbuf *); void bch2_printbuf_strip_trailing_newline(struct printbuf *); void bch2_prt_tab(struct printbuf *); void bch2_prt_tab_rjust(struct printbuf *); void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned); void bch2_prt_human_readable_u64(struct printbuf *, u64); void bch2_prt_human_readable_s64(struct printbuf *, s64); void bch2_prt_units_u64(struct printbuf *, u64); void bch2_prt_units_s64(struct printbuf *, s64); void bch2_prt_string_option(struct printbuf *, const char * const[], size_t); void bch2_prt_bitflags(struct printbuf *, const char * const[], u64); void bch2_prt_bitflags_vector(struct printbuf *, const char * const[], unsigned long *, unsigned); /* Initializer for a heap allocated printbuf: */ #define PRINTBUF … /* Initializer a printbuf that points to an external buffer: */ #define PRINTBUF_EXTERN(_buf, _size) … /* * Returns size remaining of output buffer: */ static inline unsigned printbuf_remaining_size(struct printbuf *out) { … } /* * Returns number of characters we can print to the output buffer - i.e. * excluding the terminating nul: */ static inline unsigned printbuf_remaining(struct printbuf *out) { … } static inline unsigned printbuf_written(struct printbuf *out) { … } static inline void printbuf_nul_terminate_reserved(struct printbuf *out) { … } static inline void printbuf_nul_terminate(struct printbuf *out) { … } /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */ static inline void __prt_char_reserved(struct printbuf *out, char c) { … } /* Doesn't nul terminate: */ static inline void __prt_char(struct printbuf *out, char c) { … } static inline void prt_char(struct printbuf *out, char c) { … } static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n) { … } static inline void prt_chars(struct printbuf *out, char c, unsigned n) { … } static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n) { … } static inline void prt_str(struct printbuf *out, const char *str) { … } static inline void prt_str_indented(struct printbuf *out, const char *str) { … } static inline void prt_hex_byte(struct printbuf *out, u8 byte) { … } static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte) { … } /** * printbuf_reset - re-use a printbuf without freeing and re-initializing it: */ static inline void printbuf_reset(struct printbuf *buf) { … } /** * printbuf_atomic_inc - mark as entering an atomic section */ static inline void printbuf_atomic_inc(struct printbuf *buf) { … } /** * printbuf_atomic_inc - mark as leaving an atomic section */ static inline void printbuf_atomic_dec(struct printbuf *buf) { … } #endif /* _BCACHEFS_PRINTBUF_H */