]> git.sesse.net Git - bcachefs-tools-debian/blob - linux/printbuf.c
Update bcachefs sources to 24f7e08cd8 bcachefs: shrinker.to_text() methods
[bcachefs-tools-debian] / linux / printbuf.c
1 // SPDX-License-Identifier: LGPL-2.1+
2 /* Copyright (C) 2022 Kent Overstreet */
3
4 #include <linux/err.h>
5 #include <linux/math64.h>
6 #include <linux/printbuf.h>
7 #include <linux/slab.h>
8
9 #ifdef __KERNEL__
10 #include <linux/export.h>
11 #include <linux/kernel.h>
12 #else
13 #ifndef EXPORT_SYMBOL
14 #define EXPORT_SYMBOL(x)
15 #endif
16 #endif
17
18 static inline size_t printbuf_linelen(struct printbuf *buf)
19 {
20         return buf->pos - buf->last_newline;
21 }
22
23 int printbuf_make_room(struct printbuf *out, unsigned extra)
24 {
25         unsigned new_size;
26         char *buf;
27
28         if (!out->heap_allocated)
29                 return 0;
30
31         /* Reserved space for terminating nul: */
32         extra += 1;
33
34         if (out->pos + extra < out->size)
35                 return 0;
36
37         new_size = roundup_pow_of_two(out->size + extra);
38         buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
39
40         if (!buf) {
41                 out->allocation_failure = true;
42                 return -ENOMEM;
43         }
44
45         out->buf        = buf;
46         out->size       = new_size;
47         return 0;
48 }
49 EXPORT_SYMBOL(printbuf_make_room);
50
51 /**
52  * printbuf_str - returns printbuf's buf as a C string, guaranteed to be null
53  * terminated
54  */
55 const char *printbuf_str(const struct printbuf *buf)
56 {
57         /*
58          * If we've written to a printbuf then it's guaranteed to be a null
59          * terminated string - but if we haven't, then we might not have
60          * allocated a buffer at all:
61          */
62         return buf->pos
63                 ? buf->buf
64                 : "";
65 }
66 EXPORT_SYMBOL(printbuf_str);
67
68 /**
69  * printbuf_exit - exit a printbuf, freeing memory it owns and poisoning it
70  * against accidental use.
71  */
72 void printbuf_exit(struct printbuf *buf)
73 {
74         if (buf->heap_allocated) {
75                 kfree(buf->buf);
76                 buf->buf = ERR_PTR(-EINTR); /* poison value */
77         }
78 }
79 EXPORT_SYMBOL(printbuf_exit);
80
81 void prt_newline(struct printbuf *buf)
82 {
83         unsigned i;
84
85         printbuf_make_room(buf, 1 + buf->indent);
86
87         __prt_char(buf, '\n');
88
89         buf->last_newline       = buf->pos;
90
91         for (i = 0; i < buf->indent; i++)
92                 __prt_char(buf, ' ');
93
94         printbuf_nul_terminate(buf);
95
96         buf->last_field         = buf->pos;
97         buf->tabstop = 0;
98 }
99 EXPORT_SYMBOL(prt_newline);
100
101 /**
102  * printbuf_indent_add - add to the current indent level
103  *
104  * @buf: printbuf to control
105  * @spaces: number of spaces to add to the current indent level
106  *
107  * Subsequent lines, and the current line if the output position is at the start
108  * of the current line, will be indented by @spaces more spaces.
109  */
110 void printbuf_indent_add(struct printbuf *buf, unsigned spaces)
111 {
112         if (WARN_ON_ONCE(buf->indent + spaces < buf->indent))
113                 spaces = 0;
114
115         buf->indent += spaces;
116         while (spaces--)
117                 prt_char(buf, ' ');
118 }
119 EXPORT_SYMBOL(printbuf_indent_add);
120
121 /**
122  * printbuf_indent_sub - subtract from the current indent level
123  *
124  * @buf: printbuf to control
125  * @spaces: number of spaces to subtract from the current indent level
126  *
127  * Subsequent lines, and the current line if the output position is at the start
128  * of the current line, will be indented by @spaces less spaces.
129  */
130 void printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
131 {
132         if (WARN_ON_ONCE(spaces > buf->indent))
133                 spaces = buf->indent;
134
135         if (buf->last_newline + buf->indent == buf->pos) {
136                 buf->pos -= spaces;
137                 printbuf_nul_terminate(buf);
138         }
139         buf->indent -= spaces;
140 }
141 EXPORT_SYMBOL(printbuf_indent_sub);
142
143 /**
144  * prt_tab - Advance printbuf to the next tabstop
145  *
146  * @buf: printbuf to control
147  *
148  * Advance output to the next tabstop by printing spaces.
149  */
150 void prt_tab(struct printbuf *out)
151 {
152         int spaces = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out));
153
154         BUG_ON(out->tabstop > ARRAY_SIZE(out->tabstops));
155
156         prt_chars(out, ' ', spaces);
157
158         out->last_field = out->pos;
159         out->tabstop++;
160 }
161 EXPORT_SYMBOL(prt_tab);
162
163 /**
164  * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying
165  * previous output
166  *
167  * @buf: printbuf to control
168  *
169  * Advance output to the next tabstop by inserting spaces immediately after the
170  * previous tabstop, right justifying previously outputted text.
171  */
172 void prt_tab_rjust(struct printbuf *buf)
173 {
174         BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops));
175
176         if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) {
177                 unsigned move = buf->pos - buf->last_field;
178                 unsigned shift = buf->tabstops[buf->tabstop] -
179                         printbuf_linelen(buf);
180
181                 printbuf_make_room(buf, shift);
182
183                 if (buf->last_field + shift < buf->size)
184                         memmove(buf->buf + buf->last_field + shift,
185                                 buf->buf + buf->last_field,
186                                 min(move, buf->size - 1 - buf->last_field - shift));
187
188                 if (buf->last_field < buf->size)
189                         memset(buf->buf + buf->last_field, ' ',
190                                min(shift, buf->size - buf->last_field));
191
192                 buf->pos += shift;
193                 printbuf_nul_terminate(buf);
194         }
195
196         buf->last_field = buf->pos;
197         buf->tabstop++;
198 }
199 EXPORT_SYMBOL(prt_tab_rjust);
200
201 enum string_size_units {
202         STRING_UNITS_10,        /* use powers of 10^3 (standard SI) */
203         STRING_UNITS_2,         /* use binary powers of 2^10 */
204 };
205 static int string_get_size(u64 size, u64 blk_size,
206                            const enum string_size_units units,
207                            char *buf, int len)
208 {
209         static const char *const units_10[] = {
210                 "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
211         };
212         static const char *const units_2[] = {
213                 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
214         };
215         static const char *const *const units_str[] = {
216                 [STRING_UNITS_10] = units_10,
217                 [STRING_UNITS_2] = units_2,
218         };
219         static const unsigned int divisor[] = {
220                 [STRING_UNITS_10] = 1000,
221                 [STRING_UNITS_2] = 1024,
222         };
223         static const unsigned int rounding[] = { 500, 50, 5 };
224         int i = 0, j;
225         u32 remainder = 0, sf_cap;
226         char tmp[13];
227         const char *unit;
228
229         tmp[0] = '\0';
230
231         if (blk_size == 0)
232                 size = 0;
233         if (size == 0)
234                 goto out;
235
236         /* This is Napier's algorithm.  Reduce the original block size to
237          *
238          * coefficient * divisor[units]^i
239          *
240          * we do the reduction so both coefficients are just under 32 bits so
241          * that multiplying them together won't overflow 64 bits and we keep
242          * as much precision as possible in the numbers.
243          *
244          * Note: it's safe to throw away the remainders here because all the
245          * precision is in the coefficients.
246          */
247         while (blk_size >> 32) {
248                 do_div(blk_size, divisor[units]);
249                 i++;
250         }
251
252         while (size >> 32) {
253                 do_div(size, divisor[units]);
254                 i++;
255         }
256
257         /* now perform the actual multiplication keeping i as the sum of the
258          * two logarithms */
259         size *= blk_size;
260
261         /* and logarithmically reduce it until it's just under the divisor */
262         while (size >= divisor[units]) {
263                 remainder = do_div(size, divisor[units]);
264                 i++;
265         }
266
267         /* work out in j how many digits of precision we need from the
268          * remainder */
269         sf_cap = size;
270         for (j = 0; sf_cap*10 < 1000; j++)
271                 sf_cap *= 10;
272
273         if (units == STRING_UNITS_2) {
274                 /* express the remainder as a decimal.  It's currently the
275                  * numerator of a fraction whose denominator is
276                  * divisor[units], which is 1 << 10 for STRING_UNITS_2 */
277                 remainder *= 1000;
278                 remainder >>= 10;
279         }
280
281         /* add a 5 to the digit below what will be printed to ensure
282          * an arithmetical round up and carry it through to size */
283         remainder += rounding[j];
284         if (remainder >= 1000) {
285                 remainder -= 1000;
286                 size += 1;
287         }
288
289         if (j) {
290                 snprintf(tmp, sizeof(tmp), ".%03u", remainder);
291                 tmp[j+1] = '\0';
292         }
293
294  out:
295         if (i >= ARRAY_SIZE(units_2))
296                 unit = "UNK";
297         else
298                 unit = units_str[units][i];
299
300         return snprintf(buf, len, "%u%s %s", (u32)size, tmp, unit);
301 }
302
303 /**
304  * prt_human_readable_u64 - Print out a u64 in human readable units
305  *
306  * Units of 2^10 (default) or 10^3 are controlled via @buf->si_units
307  */
308 void prt_human_readable_u64(struct printbuf *buf, u64 v)
309 {
310         printbuf_make_room(buf, 10);
311         buf->pos += string_get_size(v, 1, !buf->si_units,
312                                     buf->buf + buf->pos,
313                                     printbuf_remaining_size(buf));
314 }
315 EXPORT_SYMBOL(prt_human_readable_u64);
316
317 /**
318  * prt_human_readable_s64 - Print out a s64 in human readable units
319  *
320  * Units of 2^10 (default) or 10^3 are controlled via @buf->si_units
321  */
322 void prt_human_readable_s64(struct printbuf *buf, s64 v)
323 {
324         if (v < 0)
325                 prt_char(buf, '-');
326         prt_human_readable_u64(buf, abs(v));
327 }
328 EXPORT_SYMBOL(prt_human_readable_s64);
329
330 /**
331  * prt_units_u64 - Print out a u64 according to printbuf unit options
332  *
333  * Units are either raw (default), or human reabable units (controlled via
334  * @buf->human_readable_units)
335  */
336 void prt_units_u64(struct printbuf *out, u64 v)
337 {
338         if (out->human_readable_units)
339                 prt_human_readable_u64(out, v);
340         else
341                 prt_printf(out, "%llu", v);
342 }
343 EXPORT_SYMBOL(prt_units_u64);
344
345 /**
346  * prt_units_s64 - Print out a s64 according to printbuf unit options
347  *
348  * Units are either raw (default), or human reabable units (controlled via
349  * @buf->human_readable_units)
350  */
351 void prt_units_s64(struct printbuf *out, s64 v)
352 {
353         if (v < 0)
354                 prt_char(out, '-');
355         prt_units_u64(out, abs(v));
356 }
357 EXPORT_SYMBOL(prt_units_s64);