diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-11-09 01:24:07 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:11 -0400 |
commit | 319f9ac38eaba628d69b6ddbf402b35487315fc1 (patch) | |
tree | 01daddd4881b1f09bb4d50087e8b8803e59fea35 /fs/bcachefs | |
parent | 75369d4ec3d2dfc52af18a2d20cd0af14c935ac9 (diff) |
bcachefs: revamp to_text methods
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs')
40 files changed, 550 insertions, 635 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c index a4c4a08aed59..291d352ee370 100644 --- a/fs/bcachefs/alloc_background.c +++ b/fs/bcachefs/alloc_background.c @@ -94,17 +94,17 @@ const char *bch2_alloc_invalid(const struct bch_fs *c, struct bkey_s_c k) return NULL; } -int bch2_alloc_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_alloc_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - buf[0] = '\0'; - switch (k.k->type) { - case BCH_ALLOC: + case BCH_ALLOC: { + struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k); + + pr_buf(out, "gen %u", a.v->gen); break; } - - return 0; + } } static inline unsigned get_alloc_field(const u8 **p, unsigned bytes) diff --git a/fs/bcachefs/alloc_background.h b/fs/bcachefs/alloc_background.h index 33224070e827..99535fa60214 100644 --- a/fs/bcachefs/alloc_background.h +++ b/fs/bcachefs/alloc_background.h @@ -9,7 +9,7 @@ #define ALLOC_SCAN_BATCH(ca) max_t(size_t, 1, (ca)->mi.nbuckets >> 9) const char *bch2_alloc_invalid(const struct bch_fs *, struct bkey_s_c); -int bch2_alloc_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_alloc_ops (struct bkey_ops) { \ .key_invalid = bch2_alloc_invalid, \ diff --git a/fs/bcachefs/bkey.c b/fs/bcachefs/bkey.c index c0e86ada1c53..d7e022ba2027 100644 --- a/fs/bcachefs/bkey.c +++ b/fs/bcachefs/bkey.c @@ -60,8 +60,8 @@ static void bch2_bkey_pack_verify(const struct bkey_packed *packed, char buf1[160], buf2[160]; char buf3[160], buf4[160]; - bch2_bkey_to_text(buf1, sizeof(buf1), unpacked); - bch2_bkey_to_text(buf2, sizeof(buf2), &tmp); + bch2_bkey_to_text(&PBUF(buf1), unpacked); + bch2_bkey_to_text(&PBUF(buf2), &tmp); bch2_to_binary(buf3, (void *) unpacked, 80); bch2_to_binary(buf4, high_word(format, packed), 80); diff --git a/fs/bcachefs/bkey_methods.c b/fs/bcachefs/bkey_methods.c index b3f5f28b8761..7335fbbb3f61 100644 --- a/fs/bcachefs/bkey_methods.c +++ b/fs/bcachefs/bkey_methods.c @@ -111,7 +111,7 @@ void bch2_bkey_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k) if (invalid) { char buf[160]; - bch2_bkey_val_to_text(c, type, buf, sizeof(buf), k); + bch2_bkey_val_to_text(&PBUF(buf), c, type, k); bch2_fs_bug(c, "invalid bkey %s: %s", buf, invalid); return; } @@ -121,73 +121,57 @@ void bch2_bkey_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k) ops->key_debugcheck(c, b, k); } -#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) - -int bch2_bpos_to_text(char *buf, size_t size, struct bpos pos) +void bch2_bpos_to_text(struct printbuf *out, struct bpos pos) { - char *out = buf, *end = buf + size; - if (!bkey_cmp(pos, POS_MIN)) - p("POS_MIN"); + pr_buf(out, "POS_MIN"); else if (!bkey_cmp(pos, POS_MAX)) - p("POS_MAX"); + pr_buf(out, "POS_MAX"); else - p("%llu:%llu", pos.inode, pos.offset); - - return out - buf; + pr_buf(out, "%llu:%llu", pos.inode, pos.offset); } -int bch2_bkey_to_text(char *buf, size_t size, const struct bkey *k) +void bch2_bkey_to_text(struct printbuf *out, const struct bkey *k) { - char *out = buf, *end = buf + size; - - p("u64s %u type %u ", k->u64s, k->type); + pr_buf(out, "u64s %u type %u ", k->u64s, k->type); - out += bch2_bpos_to_text(out, end - out, k->p); + bch2_bpos_to_text(out, k->p); - p(" snap %u len %u ver %llu", k->p.snapshot, k->size, k->version.lo); - - return out - buf; + pr_buf(out, " snap %u len %u ver %llu", + k->p.snapshot, k->size, k->version.lo); } -int bch2_val_to_text(struct bch_fs *c, enum bkey_type type, - char *buf, size_t size, struct bkey_s_c k) +void bch2_val_to_text(struct printbuf *out, struct bch_fs *c, + enum bkey_type type, struct bkey_s_c k) { const struct bkey_ops *ops = &bch2_bkey_ops[type]; - char *out = buf, *end = buf + size; switch (k.k->type) { case KEY_TYPE_DELETED: - p(" deleted"); + pr_buf(out, " deleted"); break; case KEY_TYPE_DISCARD: - p(" discard"); + pr_buf(out, " discard"); break; case KEY_TYPE_ERROR: - p(" error"); + pr_buf(out, " error"); break; case KEY_TYPE_COOKIE: - p(" cookie"); + pr_buf(out, " cookie"); break; default: if (k.k->type >= KEY_TYPE_GENERIC_NR && ops->val_to_text) - out += ops->val_to_text(c, out, end - out, k); + ops->val_to_text(out, c, k); break; } - - return out - buf; } -int bch2_bkey_val_to_text(struct bch_fs *c, enum bkey_type type, - char *buf, size_t size, struct bkey_s_c k) +void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c, + enum bkey_type type, struct bkey_s_c k) { - char *out = buf, *end = buf + size; - - out += bch2_bkey_to_text(out, end - out, k.k); - out += scnprintf(out, end - out, ": "); - out += bch2_val_to_text(c, type, out, end - out, k); - - return out - buf; + bch2_bkey_to_text(out, k.k); + pr_buf(out, ": "); + bch2_val_to_text(out, c, type, k); } void bch2_bkey_swab(enum bkey_type type, diff --git a/fs/bcachefs/bkey_methods.h b/fs/bcachefs/bkey_methods.h index 6ee774ba3d7a..be6041e92c05 100644 --- a/fs/bcachefs/bkey_methods.h +++ b/fs/bcachefs/bkey_methods.h @@ -46,8 +46,8 @@ struct bkey_ops { struct bkey_s_c); void (*key_debugcheck)(struct bch_fs *, struct btree *, struct bkey_s_c); - int (*val_to_text)(struct bch_fs *, char *, - size_t, struct bkey_s_c); + void (*val_to_text)(struct printbuf *, struct bch_fs *, + struct bkey_s_c); void (*swab)(const struct bkey_format *, struct bkey_packed *); key_filter_fn key_normalize; key_merge_fn key_merge; @@ -62,12 +62,12 @@ const char *bch2_bkey_in_btree_node(struct btree *, struct bkey_s_c); void bch2_bkey_debugcheck(struct bch_fs *, struct btree *, struct bkey_s_c); -int bch2_bpos_to_text(char *, size_t, struct bpos); -int bch2_bkey_to_text(char *, size_t, const struct bkey *); -int bch2_val_to_text(struct bch_fs *, enum bkey_type, - char *, size_t, struct bkey_s_c); -int bch2_bkey_val_to_text(struct bch_fs *, enum bkey_type, - char *, size_t, struct bkey_s_c); +void bch2_bpos_to_text(struct printbuf *, struct bpos); +void bch2_bkey_to_text(struct printbuf *, const struct bkey *); +void bch2_val_to_text(struct printbuf *, struct bch_fs *, enum bkey_type, + struct bkey_s_c); +void bch2_bkey_val_to_text(struct printbuf *, struct bch_fs *, + enum bkey_type, struct bkey_s_c); void bch2_bkey_swab(enum bkey_type, const struct bkey_format *, struct bkey_packed *); diff --git a/fs/bcachefs/bset.c b/fs/bcachefs/bset.c index 7fc8fb85069f..ac84aac4a263 100644 --- a/fs/bcachefs/bset.c +++ b/fs/bcachefs/bset.c @@ -56,7 +56,7 @@ void bch2_dump_bset(struct btree *b, struct bset *i, unsigned set) _k = _n, k = n) { _n = bkey_next(_k); - bch2_bkey_to_text(buf, sizeof(buf), &k); + bch2_bkey_to_text(&PBUF(buf), &k); printk(KERN_ERR "block %u key %5u: %s\n", set, __btree_node_key_to_offset(b, _k), buf); @@ -106,7 +106,7 @@ void bch2_dump_btree_node_iter(struct btree *b, struct bkey uk = bkey_unpack_key(b, k); char buf[100]; - bch2_bkey_to_text(buf, sizeof(buf), &uk); + bch2_bkey_to_text(&PBUF(buf), &uk); printk(KERN_ERR "set %zu key %zi/%u: %s\n", t - b->set, k->_data - bset(b, t)->_data, bset(b, t)->u64s, buf); } @@ -150,8 +150,8 @@ static void bch2_btree_node_iter_next_check(struct btree_node_iter *_iter, char buf1[80], buf2[80]; bch2_dump_btree_node(b); - bch2_bkey_to_text(buf1, sizeof(buf1), &ku); - bch2_bkey_to_text(buf2, sizeof(buf2), &nu); + bch2_bkey_to_text(&PBUF(buf1), &ku); + bch2_bkey_to_text(&PBUF(buf2), &nu); printk(KERN_ERR "out of order/overlapping:\n%s\n%s\n", buf1, buf2); printk(KERN_ERR "iter was:"); @@ -212,8 +212,8 @@ void bch2_verify_insert_pos(struct btree *b, struct bkey_packed *where, char buf2[100]; bch2_dump_btree_node(b); - bch2_bkey_to_text(buf1, sizeof(buf1), &k1); - bch2_bkey_to_text(buf2, sizeof(buf2), &k2); + bch2_bkey_to_text(&PBUF(buf1), &k1); + bch2_bkey_to_text(&PBUF(buf2), &k2); panic("prev > insert:\n" "prev key %5u %s\n" @@ -234,8 +234,8 @@ void bch2_verify_insert_pos(struct btree *b, struct bkey_packed *where, char buf2[100]; bch2_dump_btree_node(b); - bch2_bkey_to_text(buf1, sizeof(buf1), &k1); - bch2_bkey_to_text(buf2, sizeof(buf2), &k2); + bch2_bkey_to_text(&PBUF(buf1), &k1); + bch2_bkey_to_text(&PBUF(buf2), &k2); panic("insert > next:\n" "insert key %5u %s\n" @@ -1767,8 +1767,8 @@ void bch2_btree_keys_stats(struct btree *b, struct bset_stats *stats) } } -int bch2_bkey_print_bfloat(struct btree *b, struct bkey_packed *k, - char *buf, size_t size) +void bch2_bfloat_to_text(struct printbuf *out, struct btree *b, + struct bkey_packed *k) { struct bset_tree *t = bch2_bkey_to_bset(b, k); struct bkey_packed *l, *r, *p; @@ -1776,28 +1776,29 @@ int bch2_bkey_print_bfloat(struct btree *b, struct bkey_packed *k, char buf1[200], buf2[200]; unsigned j, inorder; - if (!size) - return 0; + if (out->pos != out->end) + *out->pos = '\0'; if (!bset_has_ro_aux_tree(t)) - goto out; + return; inorder = bkey_to_cacheline(b, t, k); if (!inorder || inorder >= t->size) - goto out; + return; j = __inorder_to_eytzinger1(inorder, t->size, t->extra); if (k != tree_to_bkey(b, t, j)) - goto out; + return; switch (bkey_float(b, t, j)->exponent) { case BFLOAT_FAILED_UNPACKED: uk = bkey_unpack_key(b, k); - return scnprintf(buf, size, - " failed unpacked at depth %u\n" - "\t%llu:%llu\n", - ilog2(j), - uk.p.inode, uk.p.offset); + pr_buf(out, + " failed unpacked at depth %u\n" + "\t%llu:%llu\n", + ilog2(j), + uk.p.inode, uk.p.offset); + break; case BFLOAT_FAILED_PREV: p = tree_to_prev_bkey(b, t, j); l = is_power_of_2(j) @@ -1812,28 +1813,27 @@ int bch2_bkey_print_bfloat(struct btree *b, struct bkey_packed *k, bch2_to_binary(buf1, high_word(&b->format, p), b->nr_key_bits); bch2_to_binary(buf2, high_word(&b->format, k), b->nr_key_bits); - return scnprintf(buf, size, - " failed prev at depth %u\n" - "\tkey starts at bit %u but first differing bit at %u\n" - "\t%llu:%llu\n" - "\t%llu:%llu\n" - "\t%s\n" - "\t%s\n", - ilog2(j), - bch2_bkey_greatest_differing_bit(b, l, r), - bch2_bkey_greatest_differing_bit(b, p, k), - uk.p.inode, uk.p.offset, - up.p.inode, up.p.offset, - buf1, buf2); + pr_buf(out, + " failed prev at depth %u\n" + "\tkey starts at bit %u but first differing bit at %u\n" + "\t%llu:%llu\n" + "\t%llu:%llu\n" + "\t%s\n" + "\t%s\n", + ilog2(j), + bch2_bkey_greatest_differing_bit(b, l, r), + bch2_bkey_greatest_differing_bit(b, p, k), + uk.p.inode, uk.p.offset, + up.p.inode, up.p.offset, + buf1, buf2); + break; case BFLOAT_FAILED_OVERFLOW: uk = bkey_unpack_key(b, k); - return scnprintf(buf, size, - " failed overflow at depth %u\n" - "\t%llu:%llu\n", - ilog2(j), - uk.p.inode, uk.p.offset); + pr_buf(out, + " failed overflow at depth %u\n" + "\t%llu:%llu\n", + ilog2(j), + uk.p.inode, uk.p.offset); + break; } -out: - *buf = '\0'; - return 0; } diff --git a/fs/bcachefs/bset.h b/fs/bcachefs/bset.h index 1b0122dad2bc..5d03036620b9 100644 --- a/fs/bcachefs/bset.h +++ b/fs/bcachefs/bset.h @@ -607,8 +607,8 @@ struct bset_stats { }; void bch2_btree_keys_stats(struct btree *, struct bset_stats *); -int bch2_bkey_print_bfloat(struct btree *, struct bkey_packed *, - char *, size_t); +void bch2_bfloat_to_text(struct printbuf *, struct btree *, + struct bkey_packed *); /* Debug stuff */ diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c index 3cb3da363d11..846d5e816aa2 100644 --- a/fs/bcachefs/btree_cache.c +++ b/fs/bcachefs/btree_cache.c @@ -888,55 +888,54 @@ void bch2_btree_node_prefetch(struct bch_fs *c, struct btree_iter *iter, bch2_btree_node_fill(c, iter, k, level, SIX_LOCK_read, false); } -int bch2_print_btree_node(struct bch_fs *c, struct btree *b, - char *buf, size_t len) +void bch2_btree_node_to_text(struct printbuf *out, struct bch_fs *c, + struct btree *b) { const struct bkey_format *f = &b->format; struct bset_stats stats; - char ptrs[100]; memset(&stats, 0, sizeof(stats)); - bch2_val_to_text(c, BKEY_TYPE_BTREE, ptrs, sizeof(ptrs), - bkey_i_to_s_c(&b->key)); bch2_btree_keys_stats(b, &stats); - return scnprintf(buf, len, - "l %u %llu:%llu - %llu:%llu:\n" - " ptrs: %s\n" - " format: u64s %u fields %u %u %u %u %u\n" - " unpack fn len: %u\n" - " bytes used %zu/%zu (%zu%% full)\n" - " sib u64s: %u, %u (merge threshold %zu)\n" - " nr packed keys %u\n" - " nr unpacked keys %u\n" - " floats %zu\n" - " failed unpacked %zu\n" - " failed prev %zu\n" - " failed overflow %zu\n", - b->level, - b->data->min_key.inode, - b->data->min_key.offset, - b->data->max_key.inode, - b->data->max_key.offset, - ptrs, - f->key_u64s, - f->bits_per_field[0], - f->bits_per_field[1], - f->bits_per_field[2], - f->bits_per_field[3], - f->bits_per_field[4], - b->unpack_fn_len, - b->nr.live_u64s * sizeof(u64), - btree_bytes(c) - sizeof(struct btree_node), - b->nr.live_u64s * 100 / btree_max_u64s(c), - b->sib_u64s[0], - b->sib_u64s[1], - BTREE_FOREGROUND_MERGE_THRESHOLD(c), - b->nr.packed_keys, - b->nr.unpacked_keys, - stats.floats, - stats.failed_unpacked, - stats.failed_prev, - stats.failed_overflow); + pr_buf(out, + "l %u %llu:%llu - %llu:%llu:\n" + " ptrs: ", + b->level, + b->data->min_key.inode, + b->data->min_key.offset, + b->data->max_key.inode, + b->data->max_key.offset); + bch2_val_to_text(out, c, BKEY_TYPE_BTREE, + bkey_i_to_s_c(&b->key)); + pr_buf(out, "\n" + " format: u64s %u fields %u %u %u %u %u\n" + " unpack fn len: %u\n" + " bytes used %zu/%zu (%zu%% full)\n" + " sib u64s: %u, %u (merge threshold %zu)\n" + " nr packed keys %u\n" + " nr unpacked keys %u\n" + " floats %zu\n" + " failed unpacked %zu\n" + " failed prev %zu\n" + " failed overflow %zu\n", + f->key_u64s, + f->bits_per_field[0], + f->bits_per_field[1], + f->bits_per_field[2], + f->bits_per_field[3], + f->bits_per_field[4], + b->unpack_fn_len, + b->nr.live_u64s * sizeof(u64), + btree_bytes(c) - sizeof(struct btree_node), + b->nr.live_u64s * 100 / btree_max_u64s(c), + b->sib_u64s[0], + b->sib_u64s[1], + BTREE_FOREGROUND_MERGE_THRESHOLD(c), + b->nr.packed_keys, + b->nr.unpacked_keys, + stats.floats, + stats.failed_unpacked, + stats.failed_prev, + stats.failed_overflow); } diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h index f7b9bcfe09a3..cb7f66fc8bd4 100644 --- a/fs/bcachefs/btree_cache.h +++ b/fs/bcachefs/btree_cache.h @@ -85,7 +85,7 @@ static inline unsigned btree_blocks(struct bch_fs *c) #define btree_node_root(_c, _b) ((_c)->btree_roots[(_b)->btree_id].b) -int bch2_print_btree_node(struct bch_fs *, struct btree *, - char *, size_t); +void bch2_btree_node_to_text(struct printbuf *, struct bch_fs *, + struct btree *); #endif /* _BCACHEFS_BTREE_CACHE_H */ diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c index 1036b72f1ae6..f1c31e74348a 100644 --- a/fs/bcachefs/btree_io.c +++ b/fs/bcachefs/btree_io.c @@ -913,26 +913,20 @@ static void bset_encrypt(struct bch_fs *c, struct bset *i, unsigned offset) vstruct_end(i) - (void *) i->_data); } -static int btree_err_msg(struct bch_fs *c, struct btree *b, struct bset *i, - unsigned offset, int write, char *buf, size_t len) +static void btree_err_msg(struct printbuf *out, struct bch_fs *c, + struct btree *b, struct bset *i, + unsigned offset, int write) { - char *out = buf, *end = buf + len; - - out += scnprintf(out, end - out, - "error validating btree node %s" - "at btree %u level %u/%u\n" - "pos %llu:%llu node offset %u", - write ? "before write " : "", - b->btree_id, b->level, - c->btree_roots[b->btree_id].level, - b->key.k.p.inode, b->key.k.p.offset, - b->written); + pr_buf(out, "error validating btree node %s" + "at btree %u level %u/%u\n" + "pos %llu:%llu node offset %u", + write ? "before write " : "", + b->btree_id, b->level, + c->btree_roots[b->btree_id].level, + b->key.k.p.inode, b->key.k.p.offset, + b->written); if (i) - out += scnprintf(out, end - out, - " bset u64s %u", - le16_to_cpu(i->u64s)); - - return out - buf; + pr_buf(out, " bset u64s %u", le16_to_cpu(i->u64s)); } enum btree_err_type { @@ -949,10 +943,11 @@ enum btree_validate_ret { #define btree_err(type, c, b, i, msg, ...) \ ({ \ __label__ out; \ - char _buf[300], *out = _buf, *end = out + sizeof(_buf); \ + char _buf[300]; \ + struct printbuf out = PBUF(_buf); \ \ - out += btree_err_msg(c, b, i, b->written, write, out, end - out);\ - out += scnprintf(out, end - out, ": " msg, ##__VA_ARGS__); \ + btree_err_msg(&out, c, b, i, b->written, write); \ + pr_buf(&out, ": " msg, ##__VA_ARGS__); \ \ if (type == BTREE_ERR_FIXABLE && \ write == READ && \ @@ -1117,7 +1112,7 @@ static int validate_bset(struct bch_fs *c, struct btree *b, if (invalid) { char buf[160]; - bch2_bkey_val_to_text(c, type, buf, sizeof(buf), u); + bch2_bkey_val_to_text(&PBUF(buf), c, type, u); btree_err(BTREE_ERR_FIXABLE, c, b, i, "invalid bkey:\n%s\n%s", invalid, buf); @@ -1302,7 +1297,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b, bool have_retry !bversion_cmp(u.k->version, MAX_VERSION))) { char buf[160]; - bch2_bkey_val_to_text(c, type, buf, sizeof(buf), u); + bch2_bkey_val_to_text(&PBUF(buf), c, type, u); btree_err(BTREE_ERR_FIXABLE, c, b, i, "invalid bkey %s: %s", buf, invalid); @@ -2060,7 +2055,7 @@ void bch2_btree_verify_flushed(struct bch_fs *c) ssize_t bch2_dirty_btree_nodes_print(struct bch_fs *c, char *buf) { - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct bucket_table *tbl; struct rhash_head *pos; struct btree *b; @@ -2077,18 +2072,18 @@ ssize_t bch2_dirty_btree_nodes_print(struct bch_fs *c, char *buf) !(b->will_make_reachable & 1)) continue; - out += scnprintf(out, end - out, "%p d %u l %u w %u b %u r %u:%lu c %u p %u\n", - b, - (flags & (1 << BTREE_NODE_dirty)) != 0, - b->level, - b->written, - !list_empty_careful(&b->write_blocked), - b->will_make_reachable != 0, - b->will_make_reachable & 1, - b->writes[ idx].wait.list.first != NULL, - b->writes[!idx].wait.list.first != NULL); + pr_buf(&out, "%p d %u l %u w %u b %u r %u:%lu c %u p %u\n", + b, + (flags & (1 << BTREE_NODE_dirty)) != 0, + b->level, + b->written, + !list_empty_careful(&b->write_blocked), + b->will_make_reachable != 0, + b->will_make_reachable & 1, + b->writes[ idx].wait.list.first != NULL, + b->writes[!idx].wait.list.first != NULL); } rcu_read_unlock(); - return out - buf; + return out.pos - buf; } diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c index 1ba59c53c36f..ea37fa21ed6e 100644 --- a/fs/bcachefs/btree_iter.c +++ b/fs/bcachefs/btree_iter.c @@ -427,7 +427,7 @@ static void __bch2_btree_iter_verify(struct btree_iter *iter, char buf[100]; struct bkey uk = bkey_unpack_key(b, k); - bch2_bkey_to_text(buf, sizeof(buf), &uk); + bch2_bkey_to_text(&PBUF(buf), &uk); panic("prev key should be before iter pos:\n%s\n%llu:%llu\n", buf, iter->pos.inode, iter->pos.offset); } @@ -437,7 +437,7 @@ static void __bch2_btree_iter_verify(struct btree_iter *iter, char buf[100]; struct bkey uk = bkey_unpack_key(b, k); - bch2_bkey_to_text(buf, sizeof(buf), &uk); + bch2_bkey_to_text(&PBUF(buf), &uk); panic("iter should be after current key:\n" "iter pos %llu:%llu\n" "cur key %s\n", @@ -687,7 +687,7 @@ static void btree_iter_verify_new_node(struct btree_iter *iter, struct btree *b) char buf[100]; struct bkey uk = bkey_unpack_key(b, k); - bch2_bkey_to_text(buf, sizeof(buf), &uk); + bch2_bkey_to_text(&PBUF(buf), &uk); panic("parent iter doesn't point to new node:\n%s\n%llu:%llu\n", buf, b->key.k.p.inode, b->key.k.p.offset); } @@ -1451,18 +1451,7 @@ recheck: : KEY_OFFSET_MAX) - n.p.offset)); - //EBUG_ON(!n.size); - if (!n.size) { - char buf[100]; - bch2_dump_btree_node(iter->l[0].b); - - bch2_bkey_to_text(buf, sizeof(buf), k.k); - panic("iter at %llu:%llu\n" - "next key %s\n", - iter->pos.inode, - iter->pos.offset, - buf); - } + EBUG_ON(!n.size); iter->k = n; iter->uptodate = BTREE_ITER_UPTODATE; diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 4ec448718fd8..92bacd16fdc3 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -2150,20 +2150,20 @@ void bch2_btree_root_alloc(struct bch_fs *c, enum btree_id id) ssize_t bch2_btree_updates_print(struct bch_fs *c, char *buf) { - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct btree_update *as; mutex_lock(&c->btree_interior_update_lock); list_for_each_entry(as, &c->btree_interior_update_list, list) - out += scnprintf(out, end - out, "%p m %u w %u r %u j %llu\n", - as, - as->mode, - as->nodes_written, - atomic_read(&as->cl.remaining) & CLOSURE_REMAINING_MASK, - as->journal.seq); + pr_buf(&out, "%p m %u w %u r %u j %llu\n", + as, + as->mode, + as->nodes_written, + atomic_read(&as->cl.remaining) & CLOSURE_REMAINING_MASK, + as->journal.seq); mutex_unlock(&c->btree_interior_update_lock); - return out - buf; + return out.pos - buf; } size_t bch2_btree_interior_updates_nr_pending(struct bch_fs *c) diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c index 550bb10bbb7b..0a9efe57d5a9 100644 --- a/fs/bcachefs/debug.c +++ b/fs/bcachefs/debug.c @@ -223,8 +223,8 @@ static ssize_t bch2_read_btree(struct file *file, char __user *buf, k = bch2_btree_iter_peek(&iter); while (k.k && !(err = btree_iter_err(k))) { - bch2_bkey_val_to_text(i->c, bkey_type(0, i->id), - i->buf, sizeof(i->buf), k); + bch2_bkey_val_to_text(&PBUF(i->buf), i->c, + bkey_type(0, i->id), k); i->bytes = strlen(i->buf); BUG_ON(i->bytes >= PAGE_SIZE); i->buf[i->bytes] = '\n'; @@ -272,8 +272,8 @@ static ssize_t bch2_read_btree_formats(struct file *file, char __user *buf, return i->ret; for_each_btree_node(&iter, i->c, i->id, i->from, 0, b) { - i->bytes = bch2_print_btree_node(i->c, b, i->buf, - sizeof(i->buf)); + bch2_btree_node_to_text(&PBUF(i->buf), i->c, b); + i->bytes = strlen(i->buf); err = flush_buf(i); if (err) break; @@ -330,17 +330,16 @@ static ssize_t bch2_read_bfloat_failed(struct file *file, char __user *buf, bch2_btree_node_iter_peek(&l->iter, l->b); if (l->b != prev_node) { - i->bytes = bch2_print_btree_node(i->c, l->b, i->buf, - sizeof(i->buf)); + bch2_btree_node_to_text(&PBUF(i->buf), i->c, l->b); + i->bytes = strlen(i->buf); err = flush_buf(i); if (err) break; } prev_node = l->b; - i->bytes = bch2_bkey_print_bfloat(l->b, _k, i->buf, - sizeof(i->buf)); - + bch2_bfloat_to_text(&PBUF(i->buf), l->b, _k); + i->bytes = strlen(i->buf); err = flush_buf(i); if (err) break; diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c index 0651f5575131..c1a611b4d9ec 100644 --- a/fs/bcachefs/dirent.c +++ b/fs/bcachefs/dirent.c @@ -110,26 +110,23 @@ const char *bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k) } } -int bch2_dirent_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = buf + size; struct bkey_s_c_dirent d; switch (k.k->type) { case BCH_DIRENT: d = bkey_s_c_to_dirent(k); - out += bch_scnmemcpy(out, end - out, d.v->d_name, - bch2_dirent_name_bytes(d)); - out += scnprintf(out, end - out, " -> %llu", d.v->d_inum); + bch_scnmemcpy(out, d.v->d_name, + bch2_dirent_name_bytes(d)); + pr_buf(out, " -> %llu", d.v->d_inum); break; case BCH_DIRENT_WHITEOUT: - out += scnprintf(out, end - out, "whiteout"); + pr_buf(out, "whiteout"); break; } - - return out - buf; } static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans, diff --git a/fs/bcachefs/dirent.h b/fs/bcachefs/dirent.h index 30d2143d4ca7..2afb0baed11a 100644 --- a/fs/bcachefs/dirent.h +++ b/fs/bcachefs/dirent.h @@ -7,7 +7,7 @@ extern const struct bch_hash_desc bch2_dirent_hash_desc; const char *bch2_dirent_invalid(const struct bch_fs *, struct bkey_s_c); -int bch2_dirent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_dirent_ops (struct bkey_ops) { \ .key_invalid = bch2_dirent_invalid, \ diff --git a/fs/bcachefs/disk_groups.c b/fs/bcachefs/disk_groups.c index 48f472a384f1..ee10308131e9 100644 --- a/fs/bcachefs/disk_groups.c +++ b/fs/bcachefs/disk_groups.c @@ -83,11 +83,10 @@ err: return err; } -static size_t bch2_sb_disk_groups_to_text(char *buf, size_t size, +static void bch2_sb_disk_groups_to_text(struct printbuf *out, struct bch_sb *sb, struct bch_sb_field *f) { - char *out = buf, *end = buf + size; struct bch_sb_field_disk_groups *groups = field_to_type(f, disk_groups); struct bch_disk_group *g; @@ -97,18 +96,14 @@ static size_t bch2_sb_disk_groups_to_text(char *buf, size_t size, g < groups->entries + nr_groups; g++) { if (g != groups->entries) - out += scnprintf(out, end - out, " "); + pr_buf(out, " "); if (BCH_GROUP_DELETED(g)) - out += scnprintf(out, end - out, "[deleted]"); + pr_buf(out, "[deleted]"); else - out += scnprintf(out, end - out, - "[parent %llu name %s]", - BCH_GROUP_PARENT(g), - g->label); + pr_buf(out, "[parent %llu name %s]", + BCH_GROUP_PARENT(g), g->label); } - - return out - buf; } const struct bch_sb_field_ops bch_sb_field_ops_disk_groups = { @@ -343,10 +338,10 @@ int bch2_disk_path_find_or_create(struct bch_sb_handle *sb, const char *name) return v; } -int bch2_disk_path_print(struct bch_sb_handle *sb, - char *buf, size_t len, unsigned v) +void bch2_disk_path_to_text(struct printbuf *out, + struct bch_sb_handle *sb, + unsigned v) { - char *out = buf, *end = out + len; struct bch_sb_field_disk_groups *groups = bch2_sb_get_disk_groups(sb->sb); struct bch_disk_group *g; @@ -374,26 +369,18 @@ int bch2_disk_path_print(struct bch_sb_handle *sb, } while (nr) { - unsigned b = 0; - v = path[--nr]; g = groups->entries + v; - if (end != out) - b = min_t(size_t, end - out, - strnlen(g->label, sizeof(g->label))); - memcpy(out, g->label, b); - if (b < end - out) - out[b] = '\0'; - out += b; + bch_scnmemcpy(out, g->label, + strnlen(g->label, sizeof(g->label))); if (nr) - out += scnprintf(out, end - out, "."); + pr_buf(out, "."); } - - return out - buf; + return; inval: - return scnprintf(buf, len, "invalid group %u", v); + pr_buf(out, "invalid group %u", v); } int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name) @@ -452,14 +439,14 @@ int bch2_opt_target_parse(struct bch_fs *c, const char *buf, u64 *v) return -EINVAL; } -int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v) +void bch2_opt_target_to_text(struct printbuf *out, struct bch_fs *c, u64 v) { struct target t = target_decode(v); - int ret; switch (t.type) { case TARGET_NULL: - return scnprintf(buf, len, "none"); + pr_buf(out, "none"); + break; case TARGET_DEV: { struct bch_dev *ca; @@ -469,13 +456,12 @@ int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v) : NULL; if (ca && percpu_ref_tryget(&ca->io_ref)) { - ret = scnprintf(buf, len, "/dev/%pg", - ca->disk_sb.bdev); + pr_buf(out, "/dev/%pg", ca->disk_sb.bdev); percpu_ref_put(&ca->io_ref); } else if (ca) { - ret = scnprintf(buf, len, "offline device %u", t.dev); + pr_buf(out, "offline device %u", t.dev); } else { - ret = scnprintf(buf, len, "invalid device %u", t.dev); + pr_buf(out, "invalid device %u", t.dev); } rcu_read_unlock(); @@ -483,12 +469,10 @@ int bch2_opt_target_print(struct bch_fs *c, char *buf, size_t len, u64 v) } case TARGET_GROUP: mutex_lock(&c->sb_lock); - ret = bch2_disk_path_print(&c->disk_sb, buf, len, t.group); + bch2_disk_path_to_text(out, &c->disk_sb, t.group); mutex_unlock(&c->sb_lock); break; default: BUG(); } - - return ret; } diff --git a/fs/bcachefs/disk_groups.h b/fs/bcachefs/disk_groups.h index d202eb3a9de6..ceb75f86b615 100644 --- a/fs/bcachefs/disk_groups.h +++ b/fs/bcachefs/disk_groups.h @@ -59,10 +59,11 @@ bool bch2_dev_in_target(struct bch_fs *, unsigned, unsigned); int bch2_disk_path_find(struct bch_sb_handle *, const char *); int bch2_disk_path_find_or_create(struct bch_sb_handle *, const char *); -int bch2_disk_path_print(struct bch_sb_handle *, char *, size_t, unsigned); +void bch2_disk_path_to_text(struct printbuf *, struct bch_sb_handle *, + unsigned); int bch2_opt_target_parse(struct bch_fs *, const char *, u64 *); -int bch2_opt_target_print(struct bch_fs *, char *, size_t, u64); +void bch2_opt_target_to_text(struct printbuf *, struct bch_fs *, u64); int bch2_sb_disk_groups_to_cpu(struct bch_fs *); diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index 1606826e7802..a7223e7c8793 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -464,21 +464,18 @@ static const char *extent_ptr_invalid(const struct bch_fs *c, return NULL; } -static size_t extent_print_ptrs(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c_extent e) +static void extent_print_ptrs(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c_extent e) { - char *out = buf, *end = buf + size; const union bch_extent_entry *entry; struct bch_extent_crc_unpacked crc; const struct bch_extent_ptr *ptr; struct bch_dev *ca; bool first = true; -#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) - extent_for_each_entry(e, entry) { if (!first) - p(" "); + pr_buf(out, " "); switch (__extent_entry_type(entry)) { case BCH_EXTENT_ENTRY_crc32: @@ -486,12 +483,12 @@ static size_t extent_print_ptrs(struct bch_fs *c, char *buf, case BCH_EXTENT_ENTRY_crc128: crc = bch2_extent_crc_unpack(e.k, entry_to_crc(entry)); - p("crc: c_size %u size %u offset %u nonce %u csum %u compress %u", - crc.compressed_size, - crc.uncompressed_size, - crc.offset, crc.nonce, - crc.csum_type, - crc.compression_type); + pr_buf(out, "crc: c_size %u size %u offset %u nonce %u csum %u compress %u", + crc.compressed_size, + crc.uncompressed_size, + crc.offset, crc.nonce, + crc.csum_type, + crc.compression_type); break; case BCH_EXTENT_ENTRY_ptr: ptr = entry_to_ptr(entry); @@ -499,14 +496,14 @@ static size_t extent_print_ptrs(struct bch_fs *c, char *buf, ? bch_dev_bkey_exists(c, ptr->dev) : NULL; - p("ptr: %u:%llu gen %u%s%s", ptr->dev, - (u64) ptr->offset, ptr->gen, - ptr->cached ? " cached" : "", - ca && ptr_stale(ca, ptr) - ? " stale" : ""); + pr_buf(out, "ptr: %u:%llu gen %u%s%s", ptr->dev, + (u64) ptr->offset, ptr->gen, + ptr->cached ? " cached" : "", + ca && ptr_stale(ca, ptr) + ? " stale" : ""); break; default: - p("(invalid extent entry %.16llx)", *((u64 *) entry)); + pr_buf(out, "(invalid extent entry %.16llx)", *((u64 *) entry)); goto out; } @@ -514,9 +511,7 @@ static size_t extent_print_ptrs(struct bch_fs *c, char *buf, } out: if (bkey_extent_is_cached(e.k)) - p(" cached"); -#undef p - return out - buf; + pr_buf(out, " cached"); } static struct bch_dev_io_failures *dev_io_failures(struct bch_io_failures *f, @@ -681,8 +676,7 @@ void bch2_btree_ptr_debugcheck(struct bch_fs *c, struct btree *b, if (!test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) && !bch2_bkey_replicas_marked(c, btree_node_type(b), e.s_c)) { - bch2_bkey_val_to_text(c, btree_node_type(b), - buf, sizeof(buf), k); + bch2_bkey_val_to_text(&PBUF(buf), c, btree_node_type(b), k); bch2_fs_bug(c, "btree key bad (replicas not marked in superblock):\n%s", buf); @@ -691,29 +685,23 @@ void bch2_btree_ptr_debugcheck(struct bch_fs *c, struct btree *b, return; err: - bch2_bkey_val_to_text(c, btree_node_type(b), buf, sizeof(buf), k); - bch2_fs_bug(c, "%s btree pointer %s: bucket %zi " - "gen %i mark %08x", - err, buf, PTR_BUCKET_NR(ca, ptr), - mark.gen, (unsigned) mark.v.counter); + bch2_bkey_val_to_text(&PBUF(buf), c, btree_node_type(b), k); + bch2_fs_bug(c, "%s btree pointer %s: bucket %zi gen %i mark %08x", + err, buf, PTR_BUCKET_NR(ca, ptr), + mark.gen, (unsigned) mark.v.counter); } -int bch2_btree_ptr_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = buf + size; const char *invalid; -#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) - if (bkey_extent_is_data(k.k)) - out += extent_print_ptrs(c, buf, size, bkey_s_c_to_extent(k)); + extent_print_ptrs(out, c, bkey_s_c_to_extent(k)); invalid = bch2_btree_ptr_invalid(c, k); if (invalid) - p(" invalid: %s", invalid); -#undef p - return out - buf; + pr_buf(out, " invalid: %s", invalid); } int bch2_btree_pick_ptr(struct bch_fs *c, const struct btree *b, @@ -1112,8 +1100,8 @@ static void verify_extent_nonoverlapping(struct btree *b, char buf1[100]; char buf2[100]; - bch2_bkey_to_text(buf1, sizeof(buf1), &insert->k); - bch2_bkey_to_text(buf2, sizeof(buf2), &uk); + bch2_bkey_to_text(&PBUF(buf1), &insert->k); + bch2_bkey_to_text(&PBUF(buf2), &uk); bch2_dump_btree_node(b); panic("insert > next :\n" @@ -1705,8 +1693,8 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, } if (replicas > BCH_REPLICAS_MAX) { - bch2_bkey_val_to_text(c, btree_node_type(b), buf, - sizeof(buf), e.s_c); + bch2_bkey_val_to_text(&PBUF(buf), c, btree_node_type(b), + e.s_c); bch2_fs_bug(c, "extent key bad (too many replicas: %u): %s", replicas, buf); @@ -1715,8 +1703,8 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, if (!test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) && !bch2_bkey_replicas_marked(c, btree_node_type(b), e.s_c)) { - bch2_bkey_val_to_text(c, btree_node_type(b), - buf, sizeof(buf), e.s_c); + bch2_bkey_val_to_text(&PBUF(buf), c, btree_node_type(b), + e.s_c); bch2_fs_bug(c, "extent key bad (replicas not marked in superblock):\n%s", buf); @@ -1726,12 +1714,11 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, return; bad_ptr: - bch2_bkey_val_to_text(c, btree_node_type(b), buf, - sizeof(buf), e.s_c); + bch2_bkey_val_to_text(&PBUF(buf), c, btree_node_type(b), + e.s_c); bch2_fs_bug(c, "extent pointer bad gc mark: %s:\nbucket %zu " "gen %i type %u", buf, PTR_BUCKET_NR(ca, ptr), mark.gen, mark.data_type); - return; } void bch2_extent_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k) @@ -1748,22 +1735,17 @@ void bch2_extent_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k } } -int bch2_extent_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_extent_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = buf + size; const char *invalid; -#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) - if (bkey_extent_is_data(k.k)) - out += extent_print_ptrs(c, buf, size, bkey_s_c_to_extent(k)); + extent_print_ptrs(out, c, bkey_s_c_to_extent(k)); invalid = bch2_extent_invalid(c, k); if (invalid) - p(" invalid: %s", invalid); -#undef p - return out - buf; + pr_buf(out, " invalid: %s", invalid); } static void bch2_extent_crc_init(union bch_extent_crc *crc, diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h index 8754a940a476..d121ce5b3225 100644 --- a/fs/bcachefs/extents.h +++ b/fs/bcachefs/extents.h @@ -18,7 +18,8 @@ union bch_extent_crc; const char *bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c); void bch2_btree_ptr_debugcheck(struct bch_fs *, struct btree *, struct bkey_s_c); -int bch2_btree_ptr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *, + struct bkey_s_c); void bch2_ptr_swab(const struct bkey_format *, struct bkey_packed *); #define bch2_bkey_btree_ops (struct bkey_ops) { \ @@ -30,7 +31,7 @@ void bch2_ptr_swab(const struct bkey_format *, struct bkey_packed *); const char *bch2_extent_invalid(const struct bch_fs *, struct bkey_s_c); void bch2_extent_debugcheck(struct bch_fs *, struct btree *, struct bkey_s_c); -int bch2_extent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_extent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); bool bch2_ptr_normalize(struct bch_fs *, struct btree *, struct bkey_s); enum merge_result bch2_extent_merge(struct bch_fs *, struct btree *, struct bkey_i *, struct bkey_i *); diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 88bf88c047ae..b6fe2059fe5f 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -1619,7 +1619,7 @@ static int bch2_show_options(struct seq_file *seq, struct dentry *root) if (v == bch2_opt_get_by_id(&bch2_opts_default, i)) continue; - bch2_opt_to_text(c, buf, sizeof(buf), opt, v, + bch2_opt_to_text(&PBUF(buf), c, opt, v, OPT_SHOW_MOUNT_STYLE); seq_putc(seq, ','); seq_puts(seq, buf); diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 7e08592253a6..74b83201c213 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -234,8 +234,9 @@ static int hash_check_duplicates(const struct bch_hash_desc desc, if (fsck_err_on(k2.k->type == desc.key_type && !desc.cmp_bkey(k, k2), c, "duplicate hash table keys:\n%s", - (bch2_bkey_val_to_text(c, bkey_type(0, desc.btree_id), - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + bkey_type(0, desc.btree_id), + k), buf))) { ret = fsck_hash_delete_at(desc, &h->info, k_iter); if (ret) return ret; @@ -298,8 +299,9 @@ static int hash_check_key(const struct bch_hash_desc desc, "hashed to %llu chain starts at %llu\n%s", desc.btree_id, k.k->p.offset, hashed, h->chain->pos.offset, - (bch2_bkey_val_to_text(c, bkey_type(0, desc.btree_id), - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + bkey_type(0, desc.btree_id), + k), buf))) { ret = hash_redo_key(desc, h, c, k_iter, k, hashed); if (ret) { bch_err(c, "hash_redo_key err %i", ret); @@ -382,8 +384,9 @@ err_redo: "hashed to %llu chain starts at %llu\n%s", buf, strlen(buf), BTREE_ID_DIRENTS, k->k->p.offset, hash, h->chain->pos.offset, - (bch2_bkey_val_to_text(c, bkey_type(0, BTREE_ID_DIRENTS), - buf, sizeof(buf), *k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + bkey_type(0, BTREE_ID_DIRENTS), + *k), buf))) { ret = hash_redo_key(bch2_dirent_hash_desc, h, c, iter, *k, hash); if (ret) @@ -525,13 +528,15 @@ static int check_dirents(struct bch_fs *c) if (fsck_err_on(!w.have_inode, c, "dirent in nonexisting directory:\n%s", - (bch2_bkey_val_to_text(c, (enum bkey_type) BTREE_ID_DIRENTS, - buf, sizeof(buf), k), buf)) || + (bch2_bkey_val_to_text(&PBUF(buf), c, + (enum bkey_type) BTREE_ID_DIRENTS, + k), buf)) || fsck_err_on(!S_ISDIR(w.inode.bi_mode), c, "dirent in non directory inode type %u:\n%s", mode_to_type(w.inode.bi_mode), - (bch2_bkey_val_to_text(c, (enum bkey_type) BTREE_ID_DIRENTS, - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + (enum bkey_type) BTREE_ID_DIRENTS, + k), buf))) { ret = bch2_btree_delete_at(iter, 0); if (ret) goto err; @@ -580,8 +585,9 @@ static int check_dirents(struct bch_fs *c) if (fsck_err_on(d_inum == d.k->p.inode, c, "dirent points to own directory:\n%s", - (bch2_bkey_val_to_text(c, (enum bkey_type) BTREE_ID_DIRENTS, - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + (enum bkey_type) BTREE_ID_DIRENTS, + k), buf))) { ret = remove_dirent(c, iter, d); if (ret) goto err; @@ -597,8 +603,9 @@ static int check_dirents(struct bch_fs *c) if (fsck_err_on(!have_target, c, "dirent points to missing inode:\n%s", - (bch2_bkey_val_to_text(c, (enum bkey_type) BTREE_ID_DIRENTS, - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + (enum bkey_type) BTREE_ID_DIRENTS, + k), buf))) { ret = remove_dirent(c, iter, d); if (ret) goto err; @@ -610,8 +617,9 @@ static int check_dirents(struct bch_fs *c) mode_to_type(target.bi_mode), c, "incorrect d_type: should be %u:\n%s", mode_to_type(target.bi_mode), - (bch2_bkey_val_to_text(c, (enum bkey_type) BTREE_ID_DIRENTS, - buf, sizeof(buf), k), buf))) { + (bch2_bkey_val_to_text(&PBUF(buf), c, + (enum bkey_type) BTREE_ID_DIRENTS, + k), buf))) { struct bkey_i_dirent *n; n = kmalloc(bkey_bytes(d.k), GFP_KERNEL); diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c index debdbf58dd79..0a350c6d0932 100644 --- a/fs/bcachefs/inode.c +++ b/fs/bcachefs/inode.c @@ -228,10 +228,9 @@ const char *bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k) } } -int bch2_inode_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_inode_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = out + size; struct bkey_s_c_inode inode; struct bch_inode_unpacked unpacked; @@ -239,18 +238,16 @@ int bch2_inode_to_text(struct bch_fs *c, char *buf, case BCH_INODE_FS: inode = bkey_s_c_to_inode(k); if (bch2_inode_unpack(inode, &unpacked)) { - out += scnprintf(out, end - out, "(unpack error)"); + pr_buf(out, "(unpack error)"); break; } #define BCH_INODE_FIELD(_name, _bits) \ - out += scnprintf(out, end - out, #_name ": %llu ", (u64) unpacked._name); + pr_buf(out, #_name ": %llu ", (u64) unpacked._name); BCH_INODE_FIELDS() #undef BCH_INODE_FIELD break; } - - return out - buf; } void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u, diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h index 8713b51d3af7..897ff65d01cb 100644 --- a/fs/bcachefs/inode.h +++ b/fs/bcachefs/inode.h @@ -7,7 +7,7 @@ #include <linux/math64.h> const char *bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c); -int bch2_inode_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_inode_ops (struct bkey_ops) { \ .key_invalid = bch2_inode_invalid, \ diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 7499e15a2982..b4d037664628 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -1027,38 +1027,38 @@ out: ssize_t bch2_journal_print_debug(struct journal *j, char *buf) { + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct bch_fs *c = container_of(j, struct bch_fs, journal); union journal_res_state *s = &j->reservations; struct bch_dev *ca; unsigned iter; - ssize_t ret = 0; rcu_read_lock(); spin_lock(&j->lock); - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "active journal entries:\t%llu\n" - "seq:\t\t\t%llu\n" - "last_seq:\t\t%llu\n" - "last_seq_ondisk:\t%llu\n" - "reservation count:\t%u\n" - "reservation offset:\t%u\n" - "current entry u64s:\t%u\n" - "io in flight:\t\t%i\n" - "need write:\t\t%i\n" - "dirty:\t\t\t%i\n" - "replay done:\t\t%i\n", - fifo_used(&j->pin), - journal_cur_seq(j), - journal_last_seq(j), - j->last_seq_ondisk, - journal_state_count(*s, s->idx), - s->cur_entry_offset, - j->cur_entry_u64s, - s->prev_buf_unwritten, - test_bit(JOURNAL_NEED_WRITE, &j->flags), - journal_entry_is_open(j), - test_bit(JOURNAL_REPLAY_DONE, &j->flags)); + pr_buf(&out, + "active journal entries:\t%llu\n" + "seq:\t\t\t%llu\n" + "last_seq:\t\t%llu\n" + "last_seq_ondisk:\t%llu\n" + "reservation count:\t%u\n" + "reservation offset:\t%u\n" + "current entry u64s:\t%u\n" + "io in flight:\t\t%i\n" + "need write:\t\t%i\n" + "dirty:\t\t\t%i\n" + "replay done:\t\t%i\n", + fifo_used(&j->pin), + journal_cur_seq(j), + journal_last_seq(j), + j->last_seq_ondisk, + journal_state_count(*s, s->idx), + s->cur_entry_offset, + j->cur_entry_u64s, + s->prev_buf_unwritten, + test_bit(JOURNAL_NEED_WRITE, &j->flags), + journal_entry_is_open(j), + test_bit(JOURNAL_REPLAY_DONE, &j->flags)); for_each_member_device_rcu(ca, c, iter, &c->rw_devs[BCH_DATA_JOURNAL]) { @@ -1067,50 +1067,46 @@ ssize_t bch2_journal_print_debug(struct journal *j, char *buf) if (!ja->nr) continue; - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "dev %u:\n" - "\tnr\t\t%u\n" - "\tcur_idx\t\t%u (seq %llu)\n" - "\tlast_idx\t%u (seq %llu)\n", - iter, ja->nr, - ja->cur_idx, ja->bucket_seq[ja->cur_idx], - ja->last_idx, ja->bucket_seq[ja->last_idx]); + pr_buf(&out, + "dev %u:\n" + "\tnr\t\t%u\n" + "\tcur_idx\t\t%u (seq %llu)\n" + "\tlast_idx\t%u (seq %llu)\n", + iter, ja->nr, + ja->cur_idx, ja->bucket_seq[ja->cur_idx], + ja->last_idx, ja->bucket_seq[ja->last_idx]); } spin_unlock(&j->lock); rcu_read_unlock(); - return ret; + return out.pos - buf; } ssize_t bch2_journal_print_pins(struct journal *j, char *buf) { + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct journal_entry_pin_list *pin_list; struct journal_entry_pin *pin; - ssize_t ret = 0; u64 i; spin_lock(&j->lock); fifo_for_each_entry_ptr(pin_list, &j->pin, i) { - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "%llu: count %u\n", - i, atomic_read(&pin_list->count)); + pr_buf(&out, "%llu: count %u\n", + i, atomic_read(&pin_list->count)); list_for_each_entry(pin, &pin_list->list, list) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "\t%p %pf\n", - pin, pin->flush); + pr_buf(&out, "\t%p %pf\n", + pin, pin->flush); if (!list_empty(&pin_list->flushed)) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "flushed:\n"); + pr_buf(&out, "flushed:\n"); list_for_each_entry(pin, &pin_list->flushed, list) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "\t%p %pf\n", - pin, pin->flush); + pr_buf(&out, "\t%p %pf\n", + pin, pin->flush); } spin_unlock(&j->lock); - return ret; + return out.pos - buf; } diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index eb2fbe235483..4555d55b23dd 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -146,7 +146,6 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, { void *next = vstruct_next(entry); const char *invalid; - char buf[160]; int ret = 0; if (journal_entry_err_on(!k->k.u64s, c, @@ -179,8 +178,10 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, invalid = bch2_bkey_invalid(c, key_type, bkey_i_to_s_c(k)); if (invalid) { - bch2_bkey_val_to_text(c, key_type, buf, sizeof(buf), - bkey_i_to_s_c(k)); + char buf[160]; + + bch2_bkey_val_to_text(&PBUF(buf), c, key_type, + bkey_i_to_s_c(k)); mustfix_fsck_err(c, "invalid %s in journal: %s\n%s", type, invalid, buf); diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c index 9351caeb6630..c12af1a86f0b 100644 --- a/fs/bcachefs/opts.c +++ b/fs/bcachefs/opts.c @@ -145,7 +145,7 @@ const struct bch_option bch2_opt_table[] = { #define OPT_STR(_choices) .type = BCH_OPT_STR, .choices = _choices #define OPT_FN(_fn) .type = BCH_OPT_FN, \ .parse = _fn##_parse, \ - .print = _fn##_print + .to_text = _fn##_to_text #define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \ [Opt_##_name] = { \ @@ -235,38 +235,38 @@ int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt, return 0; } -int bch2_opt_to_text(struct bch_fs *c, char *buf, size_t len, - const struct bch_option *opt, u64 v, - unsigned flags) +void bch2_opt_to_text(struct printbuf *out, struct bch_fs *c, + const struct bch_option *opt, u64 v, + unsigned flags) { - char *out = buf, *end = buf + len; - if (flags & OPT_SHOW_MOUNT_STYLE) { - if (opt->type == BCH_OPT_BOOL) - return scnprintf(out, end - out, "%s%s", - v ? "" : "no", - opt->attr.name); + if (opt->type == BCH_OPT_BOOL) { + pr_buf(out, "%s%s", + v ? "" : "no", + opt->attr.name); + return; + } - out += scnprintf(out, end - out, "%s=", opt->attr.name); + pr_buf(out, "%s=", opt->attr.name); } switch (opt->type) { case BCH_OPT_BOOL: case BCH_OPT_UINT: - out += scnprintf(out, end - out, "%lli", v); + pr_buf(out, "%lli", v); break; case BCH_OPT_STR: - out += (flags & OPT_SHOW_FULL_LIST) - ? bch2_scnprint_string_list(out, end - out, opt->choices, v) - : scnprintf(out, end - out, opt->choices[v]); + if (flags & OPT_SHOW_FULL_LIST) + bch2_string_opt_to_text(out, opt->choices, v); + else + pr_buf(out, opt->choices[v]); break; case BCH_OPT_FN: - return opt->print(c, out, end - out, v); + opt->to_text(out, c, v); + break; default: BUG(); } - - return out - buf; } int bch2_parse_mount_opts(struct bch_opts *opts, char *options) diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index 52fb9781d933..47617cd011ff 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.h @@ -229,6 +229,7 @@ enum bch_opt_id { }; struct bch_fs; +struct printbuf; struct bch_option { struct attribute attr; @@ -245,7 +246,7 @@ struct bch_option { }; struct { int (*parse)(struct bch_fs *, const char *, u64 *); - int (*print)(struct bch_fs *, char *, size_t, u64); + void (*to_text)(struct printbuf *, struct bch_fs *, u64); }; }; @@ -265,8 +266,8 @@ int bch2_opt_parse(struct bch_fs *, const struct bch_option *, const char *, u64 #define OPT_SHOW_FULL_LIST (1 << 0) #define OPT_SHOW_MOUNT_STYLE (1 << 1) -int bch2_opt_to_text(struct bch_fs *, char *, size_t, - const struct bch_option *, u64, unsigned); +void bch2_opt_to_text(struct printbuf *, struct bch_fs *, + const struct bch_option *, u64, unsigned); int bch2_parse_mount_opts(struct bch_opts *, char *); diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c index 79a7f82868d6..8127f4454dac 100644 --- a/fs/bcachefs/quota.c +++ b/fs/bcachefs/quota.c @@ -46,10 +46,9 @@ static const char * const bch2_quota_counters[] = { "inodes", }; -int bch2_quota_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_quota_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = buf + size; struct bkey_s_c_quota dq; unsigned i; @@ -58,14 +57,12 @@ int bch2_quota_to_text(struct bch_fs *c, char *buf, dq = bkey_s_c_to_quota(k); for (i = 0; i < Q_COUNTERS; i++) - out += scnprintf(out, end - out, "%s hardlimit %llu softlimit %llu", - bch2_quota_counters[i], - le64_to_cpu(dq.v->c[i].hardlimit), - le64_to_cpu(dq.v->c[i].softlimit)); + pr_buf(out, "%s hardlimit %llu softlimit %llu", + bch2_quota_counters[i], + le64_to_cpu(dq.v->c[i].hardlimit), + le64_to_cpu(dq.v->c[i].softlimit)); break; } - - return out - buf; } #ifdef CONFIG_BCACHEFS_QUOTA diff --git a/fs/bcachefs/quota.h b/fs/bcachefs/quota.h index 9650e518cd64..9c06eb07bccb 100644 --- a/fs/bcachefs/quota.h +++ b/fs/bcachefs/quota.h @@ -8,7 +8,7 @@ extern const struct bch_sb_field_ops bch_sb_field_ops_quota; const char *bch2_quota_invalid(const struct bch_fs *, struct bkey_s_c); -int bch2_quota_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_quota_ops (struct bkey_ops) { \ .key_invalid = bch2_quota_invalid, \ diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c index 570dbae5a240..5d246c5b8186 100644 --- a/fs/bcachefs/rebalance.c +++ b/fs/bcachefs/rebalance.c @@ -252,49 +252,43 @@ static int bch2_rebalance_thread(void *arg) ssize_t bch2_rebalance_work_show(struct bch_fs *c, char *buf) { - char *out = buf, *end = out + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct bch_fs_rebalance *r = &c->rebalance; struct rebalance_work w = rebalance_work(c); char h1[21], h2[21]; bch2_hprint(h1, w.dev_most_full_work << 9); bch2_hprint(h2, w.dev_most_full_capacity << 9); - out += scnprintf(out, end - out, - "fullest_dev (%i):\t%s/%s\n", - w.dev_most_full_idx, h1, h2); + pr_buf(&out, "fullest_dev (%i):\t%s/%s\n", + w.dev_most_full_idx, h1, h2); bch2_hprint(h1, w.total_work << 9); bch2_hprint(h2, c->capacity << 9); - out += scnprintf(out, end - out, - "total work:\t\t%s/%s\n", - h1, h2); + pr_buf(&out, "total work:\t\t%s/%s\n", h1, h2); - out += scnprintf(out, end - out, - "rate:\t\t\t%u\n", - r->pd.rate.rate); + pr_buf(&out, "rate:\t\t\t%u\n", r->pd.rate.rate); switch (r->state) { case REBALANCE_WAITING: - out += scnprintf(out, end - out, "waiting\n"); + pr_buf(&out, "waiting\n"); break; case REBALANCE_THROTTLED: bch2_hprint(h1, (r->throttled_until_iotime - atomic_long_read(&c->io_clock[WRITE].now)) << 9); - out += scnprintf(out, end - out, - "throttled for %lu sec or %s io\n", - (r->throttled_until_cputime - jiffies) / HZ, - h1); + pr_buf(&out, "throttled for %lu sec or %s io\n", + (r->throttled_until_cputime - jiffies) / HZ, + h1); break; case REBALANCE_RUNNING: - out += scnprintf(out, end - out, "running\n"); - out += scnprintf(out, end - out, "pos %llu:%llu\n", - r->move_stats.iter.pos.inode, - r->move_stats.iter.pos.offset); + pr_buf(&out, "running\n"); + pr_buf(&out, "pos %llu:%llu\n", + r->move_stats.iter.pos.inode, + r->move_stats.iter.pos.offset); break; } - return out - buf; + return out.pos - buf; } void bch2_rebalance_stop(struct bch_fs *c) diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c index a7c3aca1bf01..fb11b97cdeee 100644 --- a/fs/bcachefs/replicas.c +++ b/fs/bcachefs/replicas.c @@ -40,38 +40,31 @@ static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r) eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL); } -static int replicas_entry_to_text(struct bch_replicas_entry *e, - char *buf, size_t size) +static void replicas_entry_to_text(struct printbuf *out, + struct bch_replicas_entry *e) { - char *out = buf, *end = out + size; unsigned i; - out += scnprintf(out, end - out, "%u: [", e->data_type); + pr_buf(out, "%u: [", e->data_type); for (i = 0; i < e->nr_devs; i++) - out += scnprintf(out, end - out, - i ? " %u" : "%u", e->devs[i]); - out += scnprintf(out, end - out, "]"); - - return out - buf; + pr_buf(out, i ? " %u" : "%u", e->devs[i]); + pr_buf(out, "]"); } -int bch2_cpu_replicas_to_text(struct bch_replicas_cpu *r, - char *buf, size_t size) +void bch2_cpu_replicas_to_text(struct printbuf *out, + struct bch_replicas_cpu *r) { - char *out = buf, *end = out + size; struct bch_replicas_entry *e; bool first = true; for_each_cpu_replicas_entry(r, e) { if (!first) - out += scnprintf(out, end - out, " "); + pr_buf(out, " "); first = false; - out += replicas_entry_to_text(e, out, end - out); + replicas_entry_to_text(out, e); } - - return out - buf; } static void extent_to_replicas(struct bkey_s_c k, @@ -510,32 +503,28 @@ err: return err; } -const struct bch_sb_field_ops bch_sb_field_ops_replicas = { - .validate = bch2_sb_validate_replicas, -}; - -int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *r, char *buf, size_t size) +static void bch2_sb_replicas_to_text(struct printbuf *out, + struct bch_sb *sb, + struct bch_sb_field *f) { - char *out = buf, *end = out + size; + struct bch_sb_field_replicas *r = field_to_type(f, replicas); struct bch_replicas_entry *e; bool first = true; - if (!r) { - out += scnprintf(out, end - out, "(no replicas section found)"); - return out - buf; - } - for_each_replicas_entry(r, e) { if (!first) - out += scnprintf(out, end - out, " "); + pr_buf(out, " "); first = false; - out += replicas_entry_to_text(e, out, end - out); + replicas_entry_to_text(out, e); } - - return out - buf; } +const struct bch_sb_field_ops bch_sb_field_ops_replicas = { + .validate = bch2_sb_validate_replicas, + .to_text = bch2_sb_replicas_to_text, +}; + /* Query replicas: */ bool bch2_replicas_marked(struct bch_fs *c, diff --git a/fs/bcachefs/replicas.h b/fs/bcachefs/replicas.h index ebbb1334cc2c..d3d81a1a39cd 100644 --- a/fs/bcachefs/replicas.h +++ b/fs/bcachefs/replicas.h @@ -13,8 +13,7 @@ int bch2_mark_replicas(struct bch_fs *, enum bch_data_type, int bch2_mark_bkey_replicas(struct bch_fs *, enum bkey_type, struct bkey_s_c); -int bch2_cpu_replicas_to_text(struct bch_replicas_cpu *, char *, size_t); -int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *, char *, size_t); +void bch2_cpu_replicas_to_text(struct printbuf *, struct bch_replicas_cpu *); struct replicas_status { struct { diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index 58c35d9665eb..0c2b20c9e8c4 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -951,21 +951,20 @@ static const char *bch2_sb_field_validate(struct bch_sb *sb, : NULL; } -size_t bch2_sb_field_to_text(char *buf, size_t size, - struct bch_sb *sb, struct bch_sb_field *f) +void bch2_sb_field_to_text(struct printbuf *out, struct bch_sb *sb, + struct bch_sb_field *f) { unsigned type = le32_to_cpu(f->type); - size_t (*to_text)(char *, size_t, struct bch_sb *, - struct bch_sb_field *) = - type < BCH_SB_FIELD_NR - ? bch2_sb_field_ops[type]->to_text - : NULL; + const struct bch_sb_field_ops *ops = type < BCH_SB_FIELD_NR + ? bch2_sb_field_ops[type] : NULL; - if (!to_text) { - if (size) - buf[0] = '\0'; - return 0; - } + if (ops) + pr_buf(out, "%s", bch2_sb_fields[type]); + else + pr_buf(out, "(unknown field %u)", type); + + pr_buf(out, " (size %llu):", vstruct_bytes(f)); - return to_text(buf, size, sb, f); + if (ops && ops->to_text) + bch2_sb_field_ops[type]->to_text(out, sb, f); } diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h index 1ea91f71f3b0..ceef650d55dd 100644 --- a/fs/bcachefs/super-io.h +++ b/fs/bcachefs/super-io.h @@ -38,7 +38,7 @@ extern const char * const bch2_sb_fields[]; struct bch_sb_field_ops { const char * (*validate)(struct bch_sb *, struct bch_sb_field *); - size_t (*to_text)(char *, size_t, struct bch_sb *, + void (*to_text)(struct printbuf *, struct bch_sb *, struct bch_sb_field *); }; @@ -136,7 +136,7 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) void bch2_fs_mark_clean(struct bch_fs *, bool); -size_t bch2_sb_field_to_text(char *, size_t, struct bch_sb *, - struct bch_sb_field *); +void bch2_sb_field_to_text(struct printbuf *, struct bch_sb *, + struct bch_sb_field *); #endif /* _BCACHEFS_SUPER_IO_H */ diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index 54d23cf46f95..a22beff7cc96 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -1236,10 +1236,9 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) data = bch2_dev_has_data(c, ca); if (data) { char data_has_str[100]; - bch2_scnprint_flag_list(data_has_str, - sizeof(data_has_str), - bch2_data_types, - data); + + bch2_string_opt_to_text(&PBUF(data_has_str), + bch2_data_types, data); bch_err(ca, "Remove failed, still has data (%s)", data_has_str); ret = -EBUSY; goto err; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index ee91bcc6433c..4ca84de6ab0e 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -230,42 +230,34 @@ static size_t bch2_btree_cache_size(struct bch_fs *c) static ssize_t show_fs_alloc_debug(struct bch_fs *c, char *buf) { - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct bch_fs_usage stats = bch2_fs_usage_read(c); unsigned replicas, type; - out += scnprintf(out, end - out, - "capacity:\t\t%llu\n", - c->capacity); + pr_buf(&out, "capacity:\t\t%llu\n", c->capacity); for (replicas = 0; replicas < ARRAY_SIZE(stats.replicas); replicas++) { - out += scnprintf(out, end - out, - "%u replicas:\n", - replicas + 1); + pr_buf(&out, "%u replicas:\n", replicas + 1); for (type = BCH_DATA_SB; type < BCH_DATA_NR; type++) - out += scnprintf(out, end - out, - "\t%s:\t\t%llu\n", - bch2_data_types[type], - stats.replicas[replicas].data[type]); - out += scnprintf(out, end - out, - "\treserved:\t%llu\n", - stats.replicas[replicas].persistent_reserved); + pr_buf(&out, "\t%s:\t\t%llu\n", + bch2_data_types[type], + stats.replicas[replicas].data[type]); + pr_buf(&out, "\treserved:\t%llu\n", + stats.replicas[replicas].persistent_reserved); } - out += scnprintf(out, end - out, "bucket usage\n"); + pr_buf(&out, "bucket usage\n"); for (type = BCH_DATA_SB; type < BCH_DATA_NR; type++) - out += scnprintf(out, end - out, - "\t%s:\t\t%llu\n", - bch2_data_types[type], - stats.buckets[type]); + pr_buf(&out, "\t%s:\t\t%llu\n", + bch2_data_types[type], + stats.buckets[type]); - out += scnprintf(out, end - out, - "online reserved:\t%llu\n", - stats.online_reserved); + pr_buf(&out, "online reserved:\t%llu\n", + stats.online_reserved); - return out - buf; + return out.pos - buf; } static ssize_t bch2_compression_stats(struct bch_fs *c, char *buf) @@ -559,16 +551,16 @@ struct attribute *bch2_fs_internal_files[] = { SHOW(bch2_fs_opts_dir) { - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir); const struct bch_option *opt = container_of(attr, struct bch_option, attr); int id = opt - bch2_opt_table; u64 v = bch2_opt_get_by_id(&c->opts, id); - out += bch2_opt_to_text(c, out, end - out, opt, v, OPT_SHOW_FULL_LIST); - out += scnprintf(out, end - out, "\n"); + bch2_opt_to_text(&out, c, opt, v, OPT_SHOW_FULL_LIST); + pr_buf(&out, "\n"); - return out - buf; + return out.pos - buf; } STORE(bch2_fs_opts_dir) @@ -742,25 +734,23 @@ static ssize_t show_quantiles(struct bch_fs *c, struct bch_dev *ca, static ssize_t show_reserve_stats(struct bch_dev *ca, char *buf) { + struct printbuf out = _PBUF(buf, PAGE_SIZE); enum alloc_reserve i; - ssize_t ret; spin_lock(&ca->freelist_lock); - ret = scnprintf(buf, PAGE_SIZE, - "free_inc:\t%zu\t%zu\n", - fifo_used(&ca->free_inc), - ca->free_inc.size); + pr_buf(&out, "free_inc:\t%zu\t%zu\n", + fifo_used(&ca->free_inc), + ca->free_inc.size); for (i = 0; i < RESERVE_NR; i++) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, - "free[%u]:\t%zu\t%zu\n", i, - fifo_used(&ca->free[i]), - ca->free[i].size); + pr_buf(&out, "free[%u]:\t%zu\t%zu\n", i, + fifo_used(&ca->free[i]), + ca->free[i].size); spin_unlock(&ca->freelist_lock); - return ret; + return out.pos - buf; } static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf) @@ -825,11 +815,11 @@ static const char * const bch2_rw[] = { static ssize_t show_dev_iodone(struct bch_dev *ca, char *buf) { - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); int rw, i, cpu; for (rw = 0; rw < 2; rw++) { - out += scnprintf(out, end - out, "%s:\n", bch2_rw[rw]); + pr_buf(&out, "%s:\n", bch2_rw[rw]); for (i = 1; i < BCH_DATA_NR; i++) { u64 n = 0; @@ -837,19 +827,19 @@ static ssize_t show_dev_iodone(struct bch_dev *ca, char *buf) for_each_possible_cpu(cpu) n += per_cpu_ptr(ca->io_done, cpu)->sectors[rw][i]; - out += scnprintf(out, end - out, "%-12s:%12llu\n", - bch2_data_types[i], n << 9); + pr_buf(&out, "%-12s:%12llu\n", + bch2_data_types[i], n << 9); } } - return out - buf; + return out.pos - buf; } SHOW(bch2_dev) { struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj); struct bch_fs *c = ca->fs; - char *out = buf, *end = buf + PAGE_SIZE; + struct printbuf out = _PBUF(buf, PAGE_SIZE); sysfs_printf(uuid, "%pU\n", ca->uuid.b); @@ -863,41 +853,39 @@ SHOW(bch2_dev) if (attr == &sysfs_label) { if (ca->mi.group) { mutex_lock(&c->sb_lock); - out += bch2_disk_path_print(&c->disk_sb, out, end - out, - ca->mi.group - 1); + bch2_disk_path_to_text(&out, &c->disk_sb, + ca->mi.group - 1); mutex_unlock(&c->sb_lock); } else { - out += scnprintf(out, end - out, "none"); + pr_buf(&out, "none"); } - out += scnprintf(out, end - out, "\n"); - return out - buf; + pr_buf(&out, "\n"); + return out.pos - buf; } if (attr == &sysfs_has_data) { - out += bch2_scnprint_flag_list(out, end - out, - bch2_data_types, - bch2_dev_has_data(c, ca)); - out += scnprintf(out, end - out, "\n"); - return out - buf; + bch2_flags_to_text(&out, bch2_data_types, + bch2_dev_has_data(c, ca)); + pr_buf(&out, "\n"); + return out.pos - buf; } sysfs_pd_controller_show(copy_gc, &ca->copygc_pd); if (attr == &sysfs_cache_replacement_policy) { - out += bch2_scnprint_string_list(out, end - out, - bch2_cache_replacement_policies, - ca->mi.replacement); - out += scnprintf(out, end - out, "\n"); - return out - buf; + bch2_string_opt_to_text(&out, + bch2_cache_replacement_policies, + ca->mi.replacement); + pr_buf(&out, "\n"); + return out.pos - buf; } if (attr == &sysfs_state_rw) { - out += bch2_scnprint_string_list(out, end - out, - bch2_dev_state, - ca->mi.state); - out += scnprintf(out, end - out, "\n"); - return out - buf; + bch2_string_opt_to_text(&out, bch2_dev_state, + ca->mi.state); + pr_buf(&out, "\n"); + return out.pos - buf; } if (attr == &sysfs_iodone) diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c index ed90bd3a5d18..bb6b4383d33f 100644 --- a/fs/bcachefs/util.c +++ b/fs/bcachefs/util.c @@ -124,47 +124,31 @@ ssize_t bch2_hprint(char *buf, s64 v) return sprintf(buf, "%lli%s%c", v, dec, si_units[u]); } -ssize_t bch2_scnprint_string_list(char *buf, size_t size, - const char * const list[], - size_t selected) +void bch2_string_opt_to_text(struct printbuf *out, + const char * const list[], + size_t selected) { - char *out = buf; size_t i; - if (size) - *out = '\0'; - for (i = 0; list[i]; i++) - out += scnprintf(out, buf + size - out, - i == selected ? "[%s] " : "%s ", list[i]); - - if (out != buf) - *--out = '\0'; - - return out - buf; + pr_buf(out, i == selected ? "[%s] " : "%s ", list[i]); } -ssize_t bch2_scnprint_flag_list(char *buf, size_t size, - const char * const list[], u64 flags) +void bch2_flags_to_text(struct printbuf *out, + const char * const list[], u64 flags) { - char *out = buf, *end = buf + size; unsigned bit, nr = 0; + if (out->pos != out->end) + *out->pos = '\0'; + while (list[nr]) nr++; - if (size) - *out = '\0'; - while (flags && (bit = __ffs(flags)) < nr) { - out += scnprintf(out, end - out, "%s,", list[bit]); + pr_buf(out, "%s,", list[bit]); flags ^= 1 << bit; } - - if (out != buf) - *--out = '\0'; - - return out - buf; } u64 bch2_read_flag_list(char *opt, const char * const list[]) @@ -329,50 +313,50 @@ static const struct time_unit *pick_time_units(u64 ns) return u; } -static size_t pr_time_units(char *buf, size_t len, u64 ns) +static void pr_time_units(struct printbuf *out, u64 ns) { const struct time_unit *u = pick_time_units(ns); - return scnprintf(buf, len, "%llu %s", div_u64(ns, u->nsecs), u->name); + pr_buf(out, "%llu %s", div_u64(ns, u->nsecs), u->name); } size_t bch2_time_stats_print(struct bch2_time_stats *stats, char *buf, size_t len) { - char *out = buf, *end = buf + len; + struct printbuf out = _PBUF(buf, len); const struct time_unit *u; u64 freq = READ_ONCE(stats->average_frequency); u64 q, last_q = 0; int i; - out += scnprintf(out, end - out, "count:\t\t%llu\n", + pr_buf(&out, "count:\t\t%llu\n", stats->count); - out += scnprintf(out, end - out, "rate:\t\t%llu/sec\n", - freq ? div64_u64(NSEC_PER_SEC, freq) : 0); + pr_buf(&out, "rate:\t\t%llu/sec\n", + freq ? div64_u64(NSEC_PER_SEC, freq) : 0); - out += scnprintf(out, end - out, "frequency:\t"); - out += pr_time_units(out, end - out, freq); + pr_buf(&out, "frequency:\t"); + pr_time_units(&out, freq); - out += scnprintf(out, end - out, "\navg duration:\t"); - out += pr_time_units(out, end - out, stats->average_duration); + pr_buf(&out, "\navg duration:\t"); + pr_time_units(&out, stats->average_duration); - out += scnprintf(out, end - out, "\nmax duration:\t"); - out += pr_time_units(out, end - out, stats->max_duration); + pr_buf(&out, "\nmax duration:\t"); + pr_time_units(&out, stats->max_duration); i = eytzinger0_first(NR_QUANTILES); u = pick_time_units(stats->quantiles.entries[i].m); - out += scnprintf(out, end - out, "\nquantiles (%s):\t", u->name); + pr_buf(&out, "\nquantiles (%s):\t", u->name); eytzinger0_for_each(i, NR_QUANTILES) { bool is_last = eytzinger0_next(i, NR_QUANTILES) == -1; q = max(stats->quantiles.entries[i].m, last_q); - out += scnprintf(out, end - out, "%llu%s", - div_u64(q, u->nsecs), - is_last ? "\n" : " "); + pr_buf(&out, "%llu%s", + div_u64(q, u->nsecs), + is_last ? "\n" : " "); last_q = q; } - return out - buf; + return out.pos - buf; } void bch2_time_stats_exit(struct bch2_time_stats *stats) @@ -615,18 +599,17 @@ void memcpy_from_bio(void *dst, struct bio *src, struct bvec_iter src_iter) } } -size_t bch_scnmemcpy(char *buf, size_t size, const char *src, size_t len) +void bch_scnmemcpy(struct printbuf *out, + const char *src, size_t len) { - size_t n; - - if (!size) - return 0; + size_t n = printbuf_remaining(out); - n = min(size - 1, len); - memcpy(buf, src, n); - buf[n] = '\0'; - - return n; + if (n) { + n = min(n - 1, len); + memcpy(out->pos, src, n); + out->pos += n; + *out->pos = '\0'; + } } #include "eytzinger.h" diff --git a/fs/bcachefs/util.h b/fs/bcachefs/util.h index cb6bed68abf8..47afd3955c7a 100644 --- a/fs/bcachefs/util.h +++ b/fs/bcachefs/util.h @@ -235,6 +235,32 @@ do { \ #define ANYSINT_MAX(t) \ ((((t) 1 << (sizeof(t) * 8 - 2)) - (t) 1) * (t) 2 + (t) 1) +struct printbuf { + char *pos; + char *end; +}; + +static inline size_t printbuf_remaining(struct printbuf *buf) +{ + return buf->end - buf->pos; +} + +#define _PBUF(_buf, _len) \ + ((struct printbuf) { \ + .pos = _buf, \ + .end = _buf + _len, \ + }) + +#define PBUF(_buf) _PBUF(_buf, sizeof(_buf)) + +#define pr_buf(_out, ...) \ +do { \ + (_out)->pos += scnprintf((_out)->pos, printbuf_remaining(_out), \ + __VA_ARGS__); \ +} while (0) + +void bch_scnmemcpy(struct printbuf *, const char *, size_t); + int bch2_strtoint_h(const char *, int *); int bch2_strtouint_h(const char *, unsigned int *); int bch2_strtoll_h(const char *, long long *); @@ -311,9 +337,10 @@ ssize_t bch2_hprint(char *buf, s64 v); bool bch2_is_zero(const void *, size_t); -ssize_t bch2_scnprint_string_list(char *, size_t, const char * const[], size_t); +void bch2_string_opt_to_text(struct printbuf *, + const char * const [], size_t); -ssize_t bch2_scnprint_flag_list(char *, size_t, const char * const[], u64); +void bch2_flags_to_text(struct printbuf *, const char * const[], u64); u64 bch2_read_flag_list(char *, const char * const[]); #define NR_QUANTILES 15 @@ -629,8 +656,6 @@ static inline struct bio_vec next_contig_bvec(struct bio *bio, #define bio_for_each_contig_segment(bv, bio, iter) \ __bio_for_each_contig_segment(bv, bio, iter, (bio)->bi_iter) -size_t bch_scnmemcpy(char *, size_t, const char *, size_t); - void sort_cmp_size(void *base, size_t num, size_t size, int (*cmp_func)(const void *, const void *, size_t), void (*swap_func)(void *, void *, size_t)); diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c index 44bf4a2f3c84..7f6258e09a0d 100644 --- a/fs/bcachefs/xattr.c +++ b/fs/bcachefs/xattr.c @@ -111,10 +111,9 @@ const char *bch2_xattr_invalid(const struct bch_fs *c, struct bkey_s_c k) } } -int bch2_xattr_to_text(struct bch_fs *c, char *buf, - size_t size, struct bkey_s_c k) +void bch2_xattr_to_text(struct printbuf *out, struct bch_fs *c, + struct bkey_s_c k) { - char *out = buf, *end = buf + size; const struct xattr_handler *handler; struct bkey_s_c_xattr xattr; @@ -124,26 +123,22 @@ int bch2_xattr_to_text(struct bch_fs *c, char *buf, handler = bch2_xattr_type_to_handler(xattr.v->x_type); if (handler && handler->prefix) - out += scnprintf(out, end - out, "%s", handler->prefix); + pr_buf(out, "%s", handler->prefix); else if (handler) - out += scnprintf(out, end - out, "(type %u)", - xattr.v->x_type); + pr_buf(out, "(type %u)", xattr.v->x_type); else - out += scnprintf(out, end - out, "(unknown type %u)", - xattr.v->x_type); - - out += bch_scnmemcpy(out, end - out, xattr.v->x_name, - xattr.v->x_name_len); - out += scnprintf(out, end - out, ":"); - out += bch_scnmemcpy(out, end - out, xattr_val(xattr.v), - le16_to_cpu(xattr.v->x_val_len)); + pr_buf(out, "(unknown type %u)", xattr.v->x_type); + + bch_scnmemcpy(out, xattr.v->x_name, + xattr.v->x_name_len); + pr_buf(out, ":"); + bch_scnmemcpy(out, xattr_val(xattr.v), + le16_to_cpu(xattr.v->x_val_len)); break; case BCH_XATTR_WHITEOUT: - out += scnprintf(out, end - out, "whiteout"); + pr_buf(out, "whiteout"); break; } - - return out - buf; } int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode, @@ -355,7 +350,7 @@ static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, struct bch_opts opts = bch2_inode_opts_to_opts(bch2_inode_opts_get(&inode->ei_inode)); const struct bch_option *opt; - int ret, id; + int id; u64 v; id = bch2_opt_lookup(name); @@ -369,9 +364,22 @@ static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, v = bch2_opt_get_by_id(&opts, id); - ret = bch2_opt_to_text(c, buffer, size, opt, v, 0); + if (!buffer) { + char buf[512]; + struct printbuf out = PBUF(buf); - return ret < size || !buffer ? ret : -ERANGE; + bch2_opt_to_text(&out, c, opt, v, 0); + + return out.pos - buf; + } else { + struct printbuf out = _PBUF(buffer, size); + + bch2_opt_to_text(&out, c, opt, v, 0); + + return printbuf_remaining(&out) + ? (void *) out.pos - buffer + : -ERANGE; + } } struct inode_opt_set { diff --git a/fs/bcachefs/xattr.h b/fs/bcachefs/xattr.h index b2fe1dc42b83..63be44b02a2b 100644 --- a/fs/bcachefs/xattr.h +++ b/fs/bcachefs/xattr.h @@ -7,7 +7,7 @@ extern const struct bch_hash_desc bch2_xattr_hash_desc; const char *bch2_xattr_invalid(const struct bch_fs *, struct bkey_s_c); -int bch2_xattr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c); +void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_xattr_ops (struct bkey_ops) { \ .key_invalid = bch2_xattr_invalid, \ |