bcachefs: printbuf improvements

- 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>
This commit is contained in:
Kent Overstreet 2024-04-10 14:32:45 -04:00
parent 62606398d5
commit acce32a51e
2 changed files with 55 additions and 63 deletions

View 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]);
}

View 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);
}
/**