summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-08-12 14:00:46 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2022-10-05 16:49:14 -0400
commitf07be1e3598ae59da9a6e38f7310c51fd13b74e4 (patch)
treedfa0c0be7c94b7f716d59e49d2a2244f5a5ea737
parentff521443e648985642d2b01ee061fcf3290b894b (diff)
lib/printbuf: Tabstop improvements
- Add a flag, has_indent_or_tabstops, that is set if indent level or tabstops are set. - Tabstops can no longer be set by modifying the tabstop array directly: instead, the new functions are provided: printbuf_tabstop_push() - add a new tabstop, n spaces after previous tabstop printbuf_tabtstop_pop() - remove previous tabstop printbuf_tabstops_reset() - remove all tabstops Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/debug.c3
-rw-r--r--fs/bcachefs/journal.c3
-rw-r--r--fs/bcachefs/rebalance.c3
-rw-r--r--fs/bcachefs/super-io.c8
-rw-r--r--fs/bcachefs/sysfs.c3
-rw-r--r--fs/bcachefs/util.c3
-rw-r--r--include/linux/printbuf.h25
-rw-r--r--lib/printbuf.c122
8 files changed, 121 insertions, 49 deletions
diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c
index 938740544469..448a3ee27038 100644
--- a/fs/bcachefs/debug.c
+++ b/fs/bcachefs/debug.c
@@ -409,7 +409,8 @@ static const struct file_operations bfloat_failed_debug_ops = {
static void bch2_cached_btree_node_to_text(struct printbuf *out, struct bch_fs *c,
struct btree *b)
{
- out->tabstops[0] = 32;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 32);
prt_printf(out, "%px btree=%s l=%u ",
b,
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c
index d77092aa069e..3f1cf1ac921a 100644
--- a/fs/bcachefs/journal.c
+++ b/fs/bcachefs/journal.c
@@ -1255,8 +1255,9 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j)
u64 seq;
unsigned i;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 24);
out->atomic++;
- out->tabstops[0] = 24;
rcu_read_lock();
s = READ_ONCE(j->reservations);
diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c
index ecc64dd92b05..17b289b051f2 100644
--- a/fs/bcachefs/rebalance.c
+++ b/fs/bcachefs/rebalance.c
@@ -268,7 +268,8 @@ void bch2_rebalance_work_to_text(struct printbuf *out, struct bch_fs *c)
struct bch_fs_rebalance *r = &c->rebalance;
struct rebalance_work w = rebalance_work(c);
- out->tabstops[0] = 20;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 20);
prt_printf(out, "fullest_dev (%i):", w.dev_most_full_idx);
prt_tab(out);
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 3dacb8ffbe56..414c40cf3614 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -1425,8 +1425,8 @@ void bch2_sb_field_to_text(struct printbuf *out, struct bch_sb *sb,
const struct bch_sb_field_ops *ops = type < BCH_SB_FIELD_NR
? bch2_sb_field_ops[type] : NULL;
- if (!out->tabstops[0])
- out->tabstops[0] = 32;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 32);
if (ops)
prt_printf(out, "%s", bch2_sb_fields[type]);
@@ -1474,8 +1474,8 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
u64 fields_have = 0;
unsigned nr_devices = 0;
- if (!out->tabstops[0])
- out->tabstops[0] = 32;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 32);
mi = bch2_sb_get_members(sb);
if (mi) {
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index 2c650055f530..2dfed1ffadd7 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -560,7 +560,8 @@ SHOW(bch2_fs_counters)
u64 counter = 0;
u64 counter_since_mount = 0;
- out->tabstops[0] = 32;
+ printbuf_tabstop_push(out, 32);
+
#define x(t, ...) \
if (attr == &sysfs_##t) { \
counter = percpu_u64_get(&c->counters[BCH_COUNTER_##t]);\
diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c
index ee2c7d9e7050..2f7d73170f35 100644
--- a/fs/bcachefs/util.c
+++ b/fs/bcachefs/util.c
@@ -526,7 +526,8 @@ void bch2_pd_controller_init(struct bch_pd_controller *pd)
void bch2_pd_controller_debug_to_text(struct printbuf *out, struct bch_pd_controller *pd)
{
- out->tabstops[0] = 20;
+ if (!out->nr_tabstops)
+ printbuf_tabstop_push(out, 20);
prt_printf(out, "rate:");
prt_tab(out);
diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h
index eb2edb86b22c..24e62e56d18c 100644
--- a/include/linux/printbuf.h
+++ b/include/linux/printbuf.h
@@ -71,6 +71,8 @@ enum printbuf_si {
PRINTBUF_UNITS_10, /* use powers of 10^3 (standard SI) */
};
+#define PRINTBUF_INLINE_TABSTOPS 4
+
struct printbuf {
char *buf;
unsigned size;
@@ -86,19 +88,33 @@ struct printbuf {
bool heap_allocated:1;
enum printbuf_si si_units:1;
bool human_readable_units:1;
- u8 tabstop;
- u8 tabstops[4];
+ bool has_indent_or_tabstops:1;
+ bool suppress_indent_tabstop_handling:1;
+ u8 nr_tabstops;
+
+ /*
+ * Do not modify directly: use printbuf_tabstop_add(),
+ * printbuf_tabstop_get()
+ */
+ u8 cur_tabstop;
+ u8 _tabstops[PRINTBUF_INLINE_TABSTOPS];
};
int printbuf_make_room(struct printbuf *, unsigned);
const char *printbuf_str(const struct printbuf *);
void printbuf_exit(struct printbuf *);
-void prt_newline(struct printbuf *);
+void printbuf_tabstops_reset(struct printbuf *);
+void printbuf_tabstop_pop(struct printbuf *);
+int printbuf_tabstop_push(struct printbuf *, unsigned);
+
void printbuf_indent_add(struct printbuf *, unsigned);
void printbuf_indent_sub(struct printbuf *, unsigned);
+
+void prt_newline(struct printbuf *);
void prt_tab(struct printbuf *);
void prt_tab_rjust(struct printbuf *);
+
void prt_bytes_indented(struct printbuf *, const char *, unsigned);
void prt_human_readable_u64(struct printbuf *, u64);
void prt_human_readable_s64(struct printbuf *, s64);
@@ -241,7 +257,8 @@ static inline void printbuf_reset(struct printbuf *buf)
buf->pos = 0;
buf->allocation_failure = 0;
buf->indent = 0;
- buf->tabstop = 0;
+ buf->nr_tabstops = 0;
+ buf->cur_tabstop = 0;
}
/**
diff --git a/lib/printbuf.c b/lib/printbuf.c
index 3fbb74754b48..2aa4a1b7294e 100644
--- a/lib/printbuf.c
+++ b/lib/printbuf.c
@@ -13,7 +13,7 @@
#include <linux/string_helpers.h>
#include <linux/printbuf.h>
-static inline size_t printbuf_linelen(struct printbuf *buf)
+static inline unsigned printbuf_linelen(struct printbuf *buf)
{
return buf->pos - buf->last_newline;
}
@@ -81,25 +81,43 @@ void printbuf_exit(struct printbuf *buf)
}
EXPORT_SYMBOL(printbuf_exit);
-void prt_newline(struct printbuf *buf)
+void printbuf_tabstops_reset(struct printbuf *buf)
{
- unsigned i;
-
- printbuf_make_room(buf, 1 + buf->indent);
-
- __prt_char(buf, '\n');
+ buf->nr_tabstops = 0;
+}
+EXPORT_SYMBOL(printbuf_tabstops_reset);
- buf->last_newline = buf->pos;
+void printbuf_tabstop_pop(struct printbuf *buf)
+{
+ if (buf->nr_tabstops)
+ --buf->nr_tabstops;
+}
+EXPORT_SYMBOL(printbuf_tabstop_pop);
- for (i = 0; i < buf->indent; i++)
- __prt_char(buf, ' ');
+/*
+ * printbuf_tabstop_set - add a tabstop, n spaces from the previous tabstop
+ *
+ * @buf: printbuf to control
+ * @spaces: number of spaces from previous tabpstop
+ *
+ * In the future this function may allocate memory if setting more than
+ * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start
+ * of line.
+ */
+int printbuf_tabstop_push(struct printbuf *buf, unsigned spaces)
+{
+ unsigned prev_tabstop = buf->nr_tabstops
+ ? buf->_tabstops[buf->nr_tabstops - 1]
+ : 0;
- printbuf_nul_terminate(buf);
+ if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops)))
+ return -EINVAL;
- buf->last_field = buf->pos;
- buf->tabstop = 0;
+ buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces;
+ buf->has_indent_or_tabstops = true;
+ return 0;
}
-EXPORT_SYMBOL(prt_newline);
+EXPORT_SYMBOL(printbuf_tabstop_push);
/**
* printbuf_indent_add - add to the current indent level
@@ -116,8 +134,9 @@ void printbuf_indent_add(struct printbuf *buf, unsigned spaces)
spaces = 0;
buf->indent += spaces;
- while (spaces--)
- prt_char(buf, ' ');
+ prt_chars(buf, ' ', spaces);
+
+ buf->has_indent_or_tabstops = true;
}
EXPORT_SYMBOL(printbuf_indent_add);
@@ -140,23 +159,50 @@ void printbuf_indent_sub(struct printbuf *buf, unsigned spaces)
printbuf_nul_terminate(buf);
}
buf->indent -= spaces;
+
+ if (!buf->indent && !buf->nr_tabstops)
+ buf->has_indent_or_tabstops = false;
}
EXPORT_SYMBOL(printbuf_indent_sub);
-static inline bool tabstop_is_set(struct printbuf *buf)
+void prt_newline(struct printbuf *buf)
{
- return buf->tabstop < ARRAY_SIZE(buf->tabstops) &&
- buf->tabstops[buf->tabstop];
+ unsigned i;
+
+ printbuf_make_room(buf, 1 + buf->indent);
+
+ __prt_char(buf, '\n');
+
+ buf->last_newline = buf->pos;
+
+ for (i = 0; i < buf->indent; i++)
+ __prt_char(buf, ' ');
+
+ printbuf_nul_terminate(buf);
+
+ buf->last_field = buf->pos;
+ buf->cur_tabstop = 0;
+}
+EXPORT_SYMBOL(prt_newline);
+
+/*
+ * Returns spaces from start of line, if set, or 0 if unset:
+ */
+static inline unsigned cur_tabstop(struct printbuf *buf)
+{
+ return buf->cur_tabstop < buf->nr_tabstops
+ ? buf->_tabstops[buf->cur_tabstop]
+ : 0;
}
static void __prt_tab(struct printbuf *out)
{
- int spaces = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out));
+ int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out));
prt_chars(out, ' ', spaces);
out->last_field = out->pos;
- out->tabstop++;
+ out->cur_tabstop++;
}
/**
@@ -168,7 +214,7 @@ static void __prt_tab(struct printbuf *out)
*/
void prt_tab(struct printbuf *out)
{
- if (WARN_ON(!tabstop_is_set(out)))
+ if (WARN_ON(!cur_tabstop(out)))
return;
__prt_tab(out);
@@ -177,28 +223,27 @@ EXPORT_SYMBOL(prt_tab);
static void __prt_tab_rjust(struct printbuf *buf)
{
- if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) {
- unsigned move = buf->pos - buf->last_field;
- unsigned shift = buf->tabstops[buf->tabstop] -
- printbuf_linelen(buf);
+ unsigned move = buf->pos - buf->last_field;
+ int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf);
- printbuf_make_room(buf, shift);
+ if (pad > 0) {
+ printbuf_make_room(buf, pad);
- if (buf->last_field + shift < buf->size)
- memmove(buf->buf + buf->last_field + shift,
+ if (buf->last_field + pad < buf->size)
+ memmove(buf->buf + buf->last_field + pad,
buf->buf + buf->last_field,
- min(move, buf->size - 1 - buf->last_field - shift));
+ min(move, buf->size - 1 - buf->last_field - pad));
if (buf->last_field < buf->size)
memset(buf->buf + buf->last_field, ' ',
- min(shift, buf->size - buf->last_field));
+ min((unsigned) pad, buf->size - buf->last_field));
- buf->pos += shift;
+ buf->pos += pad;
printbuf_nul_terminate(buf);
}
buf->last_field = buf->pos;
- buf->tabstop++;
+ buf->cur_tabstop++;
}
/**
@@ -212,7 +257,7 @@ static void __prt_tab_rjust(struct printbuf *buf)
*/
void prt_tab_rjust(struct printbuf *buf)
{
- if (WARN_ON(!tabstop_is_set(buf)))
+ if (WARN_ON(!cur_tabstop(buf)))
return;
__prt_tab_rjust(buf);
@@ -236,6 +281,11 @@ void prt_bytes_indented(struct printbuf *out, const char *str, unsigned count)
const char *unprinted_start = str;
const char *end = str + count;
+ if (!out->has_indent_or_tabstops || out->suppress_indent_tabstop_handling) {
+ prt_bytes(out, str, count);
+ return;
+ }
+
while (str != end) {
switch (*str) {
case '\n':
@@ -244,14 +294,14 @@ void prt_bytes_indented(struct printbuf *out, const char *str, unsigned count)
prt_newline(out);
break;
case '\t':
- if (likely(tabstop_is_set(out))) {
+ if (likely(cur_tabstop(out))) {
prt_bytes(out, unprinted_start, str - unprinted_start);
unprinted_start = str + 1;
__prt_tab(out);
}
break;
case '\r':
- if (likely(tabstop_is_set(out))) {
+ if (likely(cur_tabstop(out))) {
prt_bytes(out, unprinted_start, str - unprinted_start);
unprinted_start = str + 1;
__prt_tab_rjust(out);