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 143 static inline struct printbuf bch2_printbuf_init(void) 144 { 145 return PRINTBUF; 146 } 147 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 */ 165 static inline unsigned printbuf_remaining(struct printbuf *out) 166 { 167 return out->size ? printbuf_remaining_size(out) - 1 : 0; 168 } 169 170 static inline unsigned printbuf_written(struct printbuf *out) 171 { 172 return out->size ? min(out->pos, out->size - 1) : 0; 173 } 174 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 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: */ 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: */ 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 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 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 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 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 237 static inline void prt_str(struct printbuf *out, const char *str) 238 { 239 prt_bytes(out, str, strlen(str)); 240 } 241 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 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 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 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 */ 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 */ 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 */ 293 static inline void printbuf_atomic_dec(struct printbuf *buf) 294 { 295 buf->atomic--; 296 } 297 298 #endif /* _BCACHEFS_PRINTBUF_H */ 299