bcachefs: printbuf improvements
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 10 Apr 2024 18:32:45 +0000 (14:32 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 8 May 2024 21:29:17 +0000 (17:29 -0400)
- fix assorted (harmless) off-by-one errors
- we were inconsistent on whether out->pos stays <= out->size on
  overflow; now it does, and printbuf.overflow exists to indicate if a
  printbuf has overflowed
- factor out printbuf_advance_pos()
- printbuf_nul_terminate_reserved(); use this to reduce the number of
  printbuf_make_room() calls

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/printbuf.c
fs/bcachefs/printbuf.h

index b27d22925929a6554079fb8731f82dfb3dd0421c..46ce63312a3fb4a6a2f66890c5c90853f1c41c0b 100644 (file)
@@ -17,28 +17,28 @@ static inline unsigned printbuf_linelen(struct printbuf *buf)
 
 int bch2_printbuf_make_room(struct printbuf *out, unsigned extra)
 {
-       unsigned new_size;
-       char *buf;
-
-       if (!out->heap_allocated)
-               return 0;
-
        /* Reserved space for terminating nul: */
        extra += 1;
 
-       if (out->pos + extra < out->size)
+       if (out->pos + extra <= out->size)
                return 0;
 
-       new_size = roundup_pow_of_two(out->size + extra);
+       if (!out->heap_allocated) {
+               out->overflow = true;
+               return 0;
+       }
+
+       unsigned new_size = roundup_pow_of_two(out->size + extra);
 
        /*
         * Note: output buffer must be freeable with kfree(), it's not required
         * that the user use printbuf_exit().
         */
-       buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
+       char *buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT);
 
        if (!buf) {
                out->allocation_failure = true;
+               out->overflow = true;
                return -ENOMEM;
        }
 
@@ -47,6 +47,11 @@ int bch2_printbuf_make_room(struct printbuf *out, unsigned extra)
        return 0;
 }
 
+static void printbuf_advance_pos(struct printbuf *out, unsigned len)
+{
+       out->pos += min(len, printbuf_remaining(out));
+}
+
 void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
 {
        int len;
@@ -55,14 +60,12 @@ void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
                va_list args2;
 
                va_copy(args2, args);
-               len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args2);
+               len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args2);
                va_end(args2);
-       } while (len + 1 >= printbuf_remaining(out) &&
-                !bch2_printbuf_make_room(out, len + 1));
+       } while (len > printbuf_remaining(out) &&
+                !bch2_printbuf_make_room(out, len));
 
-       len = min_t(size_t, len,
-                 printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
-       out->pos += len;
+       printbuf_advance_pos(out, len);
 }
 
 void bch2_prt_printf(struct printbuf *out, const char *fmt, ...)
@@ -72,14 +75,12 @@ void bch2_prt_printf(struct printbuf *out, const char *fmt, ...)
 
        do {
                va_start(args, fmt);
-               len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args);
+               len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args);
                va_end(args);
-       } while (len + 1 >= printbuf_remaining(out) &&
-                !bch2_printbuf_make_room(out, len + 1));
+       } while (len > printbuf_remaining(out) &&
+                !bch2_printbuf_make_room(out, len));
 
-       len = min_t(size_t, len,
-                 printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
-       out->pos += len;
+       printbuf_advance_pos(out, len);
 }
 
 /**
@@ -194,18 +195,15 @@ void bch2_printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
 
 void bch2_prt_newline(struct printbuf *buf)
 {
-       unsigned i;
-
        bch2_printbuf_make_room(buf, 1 + buf->indent);
 
-       __prt_char(buf, '\n');
+       __prt_char_reserved(buf, '\n');
 
        buf->last_newline       = buf->pos;
 
-       for (i = 0; i < buf->indent; i++)
-               __prt_char(buf, ' ');
+       __prt_chars_reserved(buf, ' ', buf->indent);
 
-       printbuf_nul_terminate(buf);
+       printbuf_nul_terminate_reserved(buf);
 
        buf->last_field         = buf->pos;
        buf->cur_tabstop        = 0;
@@ -262,7 +260,7 @@ static void __prt_tab_rjust(struct printbuf *buf)
                        memset(buf->buf + buf->last_field, ' ',
                               min((unsigned) pad, buf->size - buf->last_field));
 
-               buf->pos += pad;
+               printbuf_advance_pos(buf, pad);
                printbuf_nul_terminate(buf);
        }
 
@@ -348,9 +346,10 @@ void bch2_prt_bytes_indented(struct printbuf *out, const char *str, unsigned cou
 void bch2_prt_human_readable_u64(struct printbuf *out, u64 v)
 {
        bch2_printbuf_make_room(out, 10);
-       out->pos += string_get_size(v, 1, !out->si_units,
-                                   out->buf + out->pos,
-                                   printbuf_remaining_size(out));
+       unsigned len = string_get_size(v, 1, !out->si_units,
+                                      out->buf + out->pos,
+                                      printbuf_remaining_size(out));
+       printbuf_advance_pos(out, len);
 }
 
 /**
@@ -402,9 +401,7 @@ void bch2_prt_string_option(struct printbuf *out,
                            const char * const list[],
                            size_t selected)
 {
-       size_t i;
-
-       for (i = 0; list[i]; i++)
+       for (size_t i = 0; list[i]; i++)
                bch2_prt_printf(out, i == selected ? "[%s] " : "%s ", list[i]);
 }
 
index 9a4a56c409371570e26b1279850322ce1f2f3820..9ecc56bc96359ab9b752189bc787cf0f61e5dbc8 100644 (file)
@@ -86,6 +86,7 @@ struct printbuf {
        u8                      atomic;
        bool                    allocation_failure:1;
        bool                    heap_allocated:1;
+       bool                    overflow:1;
        enum printbuf_si        si_units:1;
        bool                    human_readable_units:1;
        bool                    has_indent_or_tabstops:1;
@@ -142,7 +143,9 @@ void bch2_prt_bitflags_vector(struct printbuf *, const char * const[],
  */
 static inline unsigned printbuf_remaining_size(struct printbuf *out)
 {
-       return out->pos < out->size ? out->size - out->pos : 0;
+       if (WARN_ON(out->size && out->pos >= out->size))
+               out->pos = out->size - 1;
+       return out->size - out->pos;
 }
 
 /*
@@ -151,7 +154,7 @@ static inline unsigned printbuf_remaining_size(struct printbuf *out)
  */
 static inline unsigned printbuf_remaining(struct printbuf *out)
 {
-       return out->pos < out->size ? out->size - out->pos - 1 : 0;
+       return out->size ? printbuf_remaining_size(out) - 1 : 0;
 }
 
 static inline unsigned printbuf_written(struct printbuf *out)
@@ -159,30 +162,25 @@ static inline unsigned printbuf_written(struct printbuf *out)
        return out->size ? min(out->pos, out->size - 1) : 0;
 }
 
-/*
- * Returns true if output was truncated:
- */
-static inline bool printbuf_overflowed(struct printbuf *out)
+static inline void printbuf_nul_terminate_reserved(struct printbuf *out)
 {
-       return out->pos >= out->size;
+       if (WARN_ON(out->size && out->pos >= out->size))
+               out->pos = out->size - 1;
+       if (out->size)
+               out->buf[out->pos] = 0;
 }
 
 static inline void printbuf_nul_terminate(struct printbuf *out)
 {
        bch2_printbuf_make_room(out, 1);
-
-       if (out->pos < out->size)
-               out->buf[out->pos] = 0;
-       else if (out->size)
-               out->buf[out->size - 1] = 0;
+       printbuf_nul_terminate_reserved(out);
 }
 
 /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */
 static inline void __prt_char_reserved(struct printbuf *out, char c)
 {
        if (printbuf_remaining(out))
-               out->buf[out->pos] = c;
-       out->pos++;
+               out->buf[out->pos++] = c;
 }
 
 /* Doesn't nul terminate: */
@@ -194,37 +192,34 @@ static inline void __prt_char(struct printbuf *out, char c)
 
 static inline void prt_char(struct printbuf *out, char c)
 {
-       __prt_char(out, c);
-       printbuf_nul_terminate(out);
+       bch2_printbuf_make_room(out, 2);
+       __prt_char_reserved(out, c);
+       printbuf_nul_terminate_reserved(out);
 }
 
 static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
 {
-       unsigned i, can_print = min(n, printbuf_remaining(out));
+       unsigned can_print = min(n, printbuf_remaining(out));
 
-       for (i = 0; i < can_print; i++)
+       for (unsigned i = 0; i < can_print; i++)
                out->buf[out->pos++] = c;
-       out->pos += n - can_print;
 }
 
 static inline void prt_chars(struct printbuf *out, char c, unsigned n)
 {
        bch2_printbuf_make_room(out, n);
        __prt_chars_reserved(out, c, n);
-       printbuf_nul_terminate(out);
+       printbuf_nul_terminate_reserved(out);
 }
 
 static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
 {
-       unsigned i, can_print;
-
        bch2_printbuf_make_room(out, n);
 
-       can_print = min(n, printbuf_remaining(out));
+       unsigned can_print = min(n, printbuf_remaining(out));
 
-       for (i = 0; i < can_print; i++)
+       for (unsigned i = 0; i < can_print; i++)
                out->buf[out->pos++] = ((char *) b)[i];
-       out->pos += n - can_print;
 
        printbuf_nul_terminate(out);
 }
@@ -241,18 +236,18 @@ static inline void prt_str_indented(struct printbuf *out, const char *str)
 
 static inline void prt_hex_byte(struct printbuf *out, u8 byte)
 {
-       bch2_printbuf_make_room(out, 2);
+       bch2_printbuf_make_room(out, 3);
        __prt_char_reserved(out, hex_asc_hi(byte));
        __prt_char_reserved(out, hex_asc_lo(byte));
-       printbuf_nul_terminate(out);
+       printbuf_nul_terminate_reserved(out);
 }
 
 static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
 {
-       bch2_printbuf_make_room(out, 2);
+       bch2_printbuf_make_room(out, 3);
        __prt_char_reserved(out, hex_asc_upper_hi(byte));
        __prt_char_reserved(out, hex_asc_upper_lo(byte));
-       printbuf_nul_terminate(out);
+       printbuf_nul_terminate_reserved(out);
 }
 
 /**