bcachefs: revamp to_text methods

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2018-11-09 01:24:07 -05:00 committed by Kent Overstreet
parent 75369d4ec3
commit 319f9ac38e
40 changed files with 549 additions and 634 deletions

View file

@ -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)

View file

@ -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, \

View file

@ -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);

View file

@ -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;
pr_buf(out, "u64s %u type %u ", k->u64s, k->type);
p("u64s %u type %u ", k->u64s, k->type);
bch2_bpos_to_text(out, k->p);
out += bch2_bpos_to_text(out, end - 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,

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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 @@ __bch2_btree_iter_peek_slot_extents(struct btree_iter *iter)
: 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;

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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, \

View file

@ -83,11 +83,10 @@ static const char *bch2_sb_disk_groups_validate(struct bch_sb *sb,
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;
}

View file

@ -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 *);

View file

@ -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,

View file

@ -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 *);

View file

@ -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);

View file

@ -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 @@ static int check_dirent_hash(struct hash_check *h, struct bch_fs *c,
"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);

View file

@ -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,

View file

@ -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, \

View file

@ -1027,38 +1027,38 @@ int bch2_fs_journal_init(struct journal *j)
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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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 *);

View file

@ -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

View file

@ -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, \

View file

@ -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)

View file

@ -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 @@ static const char *bch2_sb_validate_replicas(struct bch_sb *sb, struct bch_sb_fi
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,

View file

@ -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 {

View file

@ -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);
return to_text(buf, size, sb, f);
pr_buf(out, " (size %llu):", vstruct_bytes(f));
if (ops && ops->to_text)
bch2_sb_field_ops[type]->to_text(out, sb, f);
}

View file

@ -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 */

View file

@ -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;

View file

@ -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)

View file

@ -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;
size_t n = printbuf_remaining(out);
if (!size)
return 0;
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"

View file

@ -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));

View file

@ -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);
pr_buf(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));
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 {

View file

@ -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, \