Commit acce32a5 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 62606398
Loading
Loading
Loading
Loading
+31 −34
Original line number Diff line number Diff line
@@ -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,
	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]);
}

+24 −29
Original line number Diff line number Diff line
@@ -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);
}

/**