tmp = __bch2_bkey_unpack_key(format, packed);
if (memcmp(&tmp, unpacked, sizeof(struct bkey))) {
- char buf1[160], buf2[160];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
char buf3[160], buf4[160];
- bch2_bkey_to_text(&PBUF(buf1), unpacked);
- bch2_bkey_to_text(&PBUF(buf2), &tmp);
+ bch2_bkey_to_text(&buf1, unpacked);
+ bch2_bkey_to_text(&buf2, &tmp);
bch2_to_binary(buf3, (void *) unpacked, 80);
bch2_to_binary(buf4, high_word(format, packed), 80);
format->bits_per_field[2],
format->bits_per_field[3],
format->bits_per_field[4],
- buf1, buf2, buf3, buf4);
+ buf1.buf, buf2.buf, buf3, buf4);
}
}
struct bkey_packed *_k, *_n;
struct bkey uk, n;
struct bkey_s_c k;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
if (!i->u64s)
return;
_n = bkey_next(_k);
k = bkey_disassemble(b, _k, &uk);
+
+ printbuf_reset(&buf);
if (c)
- bch2_bkey_val_to_text(&PBUF(buf), c, k);
+ bch2_bkey_val_to_text(&buf, c, k);
else
- bch2_bkey_to_text(&PBUF(buf), k.k);
+ bch2_bkey_to_text(&buf, k.k);
printk(KERN_ERR "block %u key %5zu: %s\n", set,
- _k->_data - i->_data, buf);
+ _k->_data - i->_data, buf.buf);
if (_n == vstruct_last(i))
continue;
!bpos_cmp(n.p, k.k->p))
printk(KERN_ERR "Duplicate keys\n");
}
+
+ printbuf_exit(&buf);
}
void bch2_dump_btree_node(struct bch_fs *c, struct btree *b)
struct btree_node_iter *iter)
{
struct btree_node_iter_set *set;
+ struct printbuf buf = PRINTBUF;
printk(KERN_ERR "btree node iter with %u/%u sets:\n",
__btree_node_iter_used(iter), b->nsets);
struct bkey_packed *k = __btree_node_offset_to_key(b, set->k);
struct bset_tree *t = bch2_bkey_to_bset(b, k);
struct bkey uk = bkey_unpack_key(b, k);
- char buf[100];
- bch2_bkey_to_text(&PBUF(buf), &uk);
+ printbuf_reset(&buf);
+ bch2_bkey_to_text(&buf, &uk);
printk(KERN_ERR "set %zu key %u: %s\n",
- t - b->set, set->k, buf);
+ t - b->set, set->k, buf.buf);
}
+
+ printbuf_exit(&buf);
}
#ifdef CONFIG_BCACHEFS_DEBUG
struct btree_node_iter_set *set;
struct bkey ku = bkey_unpack_key(b, k);
struct bkey nu = bkey_unpack_key(b, n);
- char buf1[80], buf2[80];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
bch2_dump_btree_node(NULL, b);
- bch2_bkey_to_text(&PBUF(buf1), &ku);
- bch2_bkey_to_text(&PBUF(buf2), &nu);
+ bch2_bkey_to_text(&buf1, &ku);
+ bch2_bkey_to_text(&buf2, &nu);
printk(KERN_ERR "out of order/overlapping:\n%s\n%s\n",
- buf1, buf2);
+ buf1.buf, buf2.buf);
printk(KERN_ERR "iter was:");
btree_node_iter_for_each(_iter, set) {
struct bset_tree *t = bch2_bkey_to_bset(b, where);
struct bkey_packed *prev = bch2_bkey_prev_all(b, t, where);
struct bkey_packed *next = (void *) (where->_data + clobber_u64s);
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
#if 0
BUG_ON(prev &&
bkey_iter_cmp(b, prev, insert) > 0);
bkey_iter_cmp(b, prev, insert) > 0) {
struct bkey k1 = bkey_unpack_key(b, prev);
struct bkey k2 = bkey_unpack_key(b, insert);
- char buf1[100];
- char buf2[100];
bch2_dump_btree_node(NULL, b);
- bch2_bkey_to_text(&PBUF(buf1), &k1);
- bch2_bkey_to_text(&PBUF(buf2), &k2);
+ bch2_bkey_to_text(&buf1, &k1);
+ bch2_bkey_to_text(&buf2, &k2);
panic("prev > insert:\n"
"prev key %s\n"
"insert key %s\n",
- buf1, buf2);
+ buf1.buf, buf2.buf);
}
#endif
#if 0
bkey_iter_cmp(b, insert, next) > 0) {
struct bkey k1 = bkey_unpack_key(b, insert);
struct bkey k2 = bkey_unpack_key(b, next);
- char buf1[100];
- char buf2[100];
bch2_dump_btree_node(NULL, b);
- bch2_bkey_to_text(&PBUF(buf1), &k1);
- bch2_bkey_to_text(&PBUF(buf2), &k2);
+ bch2_bkey_to_text(&buf1, &k1);
+ bch2_bkey_to_text(&buf2, &k2);
panic("insert > next:\n"
"insert key %s\n"
"next key %s\n",
- buf1, buf2);
+ buf1.buf, buf2.buf);
}
#endif
}
struct bkey uk;
unsigned j, inorder;
- if (out->pos != out->end)
- *out->pos = '\0';
-
if (!bset_has_ro_aux_tree(t))
return;
static noinline void btree_bad_header(struct bch_fs *c, struct btree *b)
{
- char buf1[200], buf2[100], buf3[100];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
+ struct printbuf buf3 = PRINTBUF;
if (!test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags))
return;
- bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(&b->key));
- bch2_bpos_to_text(&PBUF(buf2), b->data->min_key);
- bch2_bpos_to_text(&PBUF(buf3), b->data->max_key);
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(&b->key));
+ bch2_bpos_to_text(&buf2, b->data->min_key);
+ bch2_bpos_to_text(&buf3, b->data->max_key);
bch2_fs_inconsistent(c, "btree node header doesn't match ptr\n"
"btree %s level %u\n"
"header: btree %s level %llu\n"
"min %s max %s\n",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1,
+ buf1.buf,
bch2_btree_ids[BTREE_NODE_ID(b->data)],
BTREE_NODE_LEVEL(b->data),
- buf2, buf3);
+ buf2.buf, buf3.buf);
+
+ printbuf_exit(&buf3);
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
}
static inline void btree_check_header(struct bch_fs *c, struct btree *b)
struct bpos expected_start = bkey_deleted(&prev->k->k)
? node_start
: bpos_successor(prev->k->k.p);
- char buf1[200], buf2[200];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
int ret = 0;
if (cur.k->k.type == KEY_TYPE_btree_ptr_v2) {
struct bkey_i_btree_ptr_v2 *bp = bkey_i_to_btree_ptr_v2(cur.k);
- if (bkey_deleted(&prev->k->k)) {
- struct printbuf out = PBUF(buf1);
- pr_buf(&out, "start of node: ");
- bch2_bpos_to_text(&out, node_start);
- } else {
- bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(prev->k));
- }
-
if (bpos_cmp(expected_start, bp->v.min_key)) {
bch2_topology_error(c);
+ if (bkey_deleted(&prev->k->k)) {
+ pr_buf(&buf1, "start of node: ");
+ bch2_bpos_to_text(&buf1, node_start);
+ } else {
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(prev->k));
+ }
+ bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(cur.k));
+
if (__fsck_err(c,
FSCK_CAN_FIX|
FSCK_CAN_IGNORE|
" prev %s\n"
" cur %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1,
- (bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(cur.k)), buf2)) &&
+ buf1.buf, buf2.buf) &&
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
bch_info(c, "Halting mark and sweep to start topology repair pass");
- return FSCK_ERR_START_TOPOLOGY_REPAIR;
+ ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
+ goto err;
} else {
set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
}
if (is_last && bpos_cmp(cur.k->k.p, node_end)) {
bch2_topology_error(c);
+ printbuf_reset(&buf1);
+ printbuf_reset(&buf2);
+
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(cur.k));
+ bch2_bpos_to_text(&buf2, node_end);
+
if (__fsck_err(c,
FSCK_CAN_FIX|
FSCK_CAN_IGNORE|
" %s\n"
" expected %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- (bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(cur.k)), buf1),
- (bch2_bpos_to_text(&PBUF(buf2), node_end), buf2)) &&
+ buf1.buf, buf2.buf) &&
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
bch_info(c, "Halting mark and sweep to start topology repair pass");
- return FSCK_ERR_START_TOPOLOGY_REPAIR;
+ ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
+ goto err;
} else {
set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
}
}
bch2_bkey_buf_copy(prev, c, cur.k);
+err:
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
struct bpos expected_start = !prev
? b->data->min_key
: bpos_successor(prev->key.k.p);
- char buf1[200], buf2[200];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
int ret = 0;
if (!prev) {
- struct printbuf out = PBUF(buf1);
- pr_buf(&out, "start of node: ");
- bch2_bpos_to_text(&out, b->data->min_key);
+ pr_buf(&buf1, "start of node: ");
+ bch2_bpos_to_text(&buf1, b->data->min_key);
} else {
- bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(&prev->key));
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(&prev->key));
}
- bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(&cur->key));
+ bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(&cur->key));
if (prev &&
bpos_cmp(expected_start, cur->data->min_key) > 0 &&
" node %s\n"
" next %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1, buf2))
- return DROP_PREV_NODE;
+ buf1.buf, buf2.buf)) {
+ ret = DROP_PREV_NODE;
+ goto out;
+ }
if (mustfix_fsck_err_on(bpos_cmp(prev->key.k.p,
bpos_predecessor(cur->data->min_key)), c,
" node %s\n"
" next %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1, buf2))
+ buf1.buf, buf2.buf))
ret = set_node_max(c, prev,
bpos_predecessor(cur->data->min_key));
} else {
" prev %s\n"
" node %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1, buf2))
- return DROP_THIS_NODE;
+ buf1.buf, buf2.buf)) {
+ ret = DROP_THIS_NODE;
+ goto out;
+ }
if (mustfix_fsck_err_on(bpos_cmp(expected_start, cur->data->min_key), c,
"btree node with incorrect min_key at btree %s level %u:\n"
" prev %s\n"
" node %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- buf1, buf2))
+ buf1.buf, buf2.buf))
ret = set_node_min(c, cur, expected_start);
}
+out:
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
static int btree_repair_node_end(struct bch_fs *c, struct btree *b,
struct btree *child)
{
- char buf1[200], buf2[200];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
int ret = 0;
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(&child->key));
+ bch2_bpos_to_text(&buf2, b->key.k.p);
+
if (mustfix_fsck_err_on(bpos_cmp(child->key.k.p, b->key.k.p), c,
"btree node with incorrect max_key at btree %s level %u:\n"
" %s\n"
" expected %s",
bch2_btree_ids[b->c.btree_id], b->c.level,
- (bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(&child->key)), buf1),
- (bch2_bpos_to_text(&PBUF(buf2), b->key.k.p), buf2))) {
+ buf1.buf, buf2.buf)) {
ret = set_node_max(c, child, b->key.k.p);
if (ret)
- return ret;
+ goto err;
}
+err:
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
struct bkey_buf prev_k, cur_k;
struct btree *prev = NULL, *cur = NULL;
bool have_child, dropped_children = false;
- char buf[200];
+ struct printbuf buf;
int ret = 0;
if (!b->c.level)
false);
ret = PTR_ERR_OR_ZERO(cur);
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(cur_k.k));
+
if (mustfix_fsck_err_on(ret == -EIO, c,
"Unreadable btree node at btree %s level %u:\n"
" %s",
bch2_btree_ids[b->c.btree_id],
b->c.level - 1,
- (bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(cur_k.k)), buf))) {
+ buf.buf)) {
bch2_btree_node_evict(c, cur_k.k);
ret = bch2_journal_key_delete(c, b->c.btree_id,
b->c.level, cur_k.k->k.p);
have_child = true;
}
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
+
if (mustfix_fsck_err_on(!have_child, c,
"empty interior btree node at btree %s level %u\n"
" %s",
bch2_btree_ids[b->c.btree_id],
- b->c.level,
- (bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(&b->key)), buf)))
+ b->c.level, buf.buf))
ret = DROP_THIS_NODE;
err:
fsck_err:
if (!ret && dropped_children)
goto again;
+ printbuf_exit(&buf);
return ret;
}
const union bch_extent_entry *entry;
struct extent_ptr_decoded p = { 0 };
bool do_update = false;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
/*
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) {
if (!p.ptr.cached) {
g->_mark.gen = p.ptr.gen;
g->gen_valid = true;
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen, g->mark.gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) {
if (!p.ptr.cached) {
g->_mark.gen = p.ptr.gen;
g->gen_valid = true;
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), g->mark.gen,
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
do_update = true;
if (fsck_err_on(!p.ptr.cached &&
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen, g->mark.gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
do_update = true;
if (data_type != BCH_DATA_btree && p.ptr.gen != g->mark.gen)
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[g->mark.data_type],
bch2_data_types[data_type],
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf))) {
if (data_type == BCH_DATA_btree) {
g->_mark.data_type = data_type;
set_bit(BCH_FS_NEED_ANOTHER_GC, &c->flags);
"pointer to nonexistent stripe %llu\n"
"while marking %s",
(u64) p.ec.idx,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
do_update = true;
if (fsck_err_on(!bch2_ptr_matches_stripe_m(m, p), c,
"pointer does not match stripe %llu\n"
"while marking %s",
(u64) p.ec.idx,
- (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, *k), buf.buf)))
do_update = true;
}
}
if (is_root) {
bch_err(c, "cannot update btree roots yet");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
new = kmalloc(bkey_bytes(k->k), GFP_KERNEL);
if (!new) {
bch_err(c, "%s: error allocating new key", __func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
bkey_reassemble(new, *k);
ret = bch2_journal_key_insert_take(c, btree_id, level, new);
if (ret) {
kfree(new);
- return ret;
+ goto err;
}
if (level)
bch2_btree_node_update_key_early(c, btree_id, level - 1, *k, new);
- bch2_bkey_val_to_text(&PBUF(buf), c, *k);
- bch_info(c, "updated %s", buf);
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(new));
- bch_info(c, "new key %s", buf);
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, *k);
+ bch_info(c, "updated %s", buf.buf);
+
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(new));
+ bch_info(c, "new key %s", buf.buf);
+
*k = bkey_i_to_s_c(new);
}
+err:
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
struct btree_and_journal_iter iter;
struct bkey_s_c k;
struct bkey_buf cur, prev;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
bch2_btree_and_journal_iter_init_node_iter(&iter, c, b);
" %s",
bch2_btree_ids[b->c.btree_id],
b->c.level - 1,
- (bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(cur.k)), buf)) &&
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(cur.k)), buf.buf)) &&
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
bch_info(c, "Halting mark and sweep to start topology repair pass");
bch2_bkey_buf_exit(&cur, c);
bch2_bkey_buf_exit(&prev, c);
bch2_btree_and_journal_iter_exit(&iter);
+ printbuf_exit(&buf);
return ret;
}
: bch2_expensive_debug_checks ? 0
: !btree_node_type_needs_gc(btree_id) ? 1
: 0;
- char buf[100];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
b = c->btree_roots[btree_id].b;
return 0;
six_lock_read(&b->c.lock, NULL, NULL);
+ printbuf_reset(&buf);
+ bch2_bpos_to_text(&buf, b->data->min_key);
if (mustfix_fsck_err_on(bpos_cmp(b->data->min_key, POS_MIN), c,
- "btree root with incorrect min_key: %s",
- (bch2_bpos_to_text(&PBUF(buf), b->data->min_key), buf))) {
+ "btree root with incorrect min_key: %s", buf.buf)) {
bch_err(c, "repair unimplemented");
ret = FSCK_ERR_EXIT;
goto fsck_err;
}
+ printbuf_reset(&buf);
+ bch2_bpos_to_text(&buf, b->data->max_key);
if (mustfix_fsck_err_on(bpos_cmp(b->data->max_key, SPOS_MAX), c,
- "btree root with incorrect max_key: %s",
- (bch2_bpos_to_text(&PBUF(buf), b->data->max_key), buf))) {
+ "btree root with incorrect max_key: %s", buf.buf)) {
bch_err(c, "repair unimplemented");
ret = FSCK_ERR_EXIT;
goto fsck_err;
if (ret < 0)
bch_err(c, "%s: ret %i", __func__, ret);
+ printbuf_exit(&buf);
return ret;
}
bool initial, bool metadata_only)
{
struct bch_dev *ca = NULL;
+ struct printbuf buf = PRINTBUF;
bool verify = !metadata_only && (!initial ||
(c->sb.compat & (1ULL << BCH_COMPAT_alloc_info)));
unsigned i, dev;
for (i = 0; i < c->replicas.nr; i++) {
struct bch_replicas_entry *e =
cpu_replicas_entry(&c->replicas, i);
- char buf[80];
if (metadata_only &&
(e->data_type == BCH_DATA_user ||
e->data_type == BCH_DATA_cached))
continue;
- bch2_replicas_entry_to_text(&PBUF(buf), e);
+ printbuf_reset(&buf);
+ bch2_replicas_entry_to_text(&buf, e);
- copy_fs_field(replicas[i], "%s", buf);
+ copy_fs_field(replicas[i], "%s", buf.buf);
}
}
bch_err(c, "%s: ret %i", __func__, ret);
percpu_up_write(&c->mark_lock);
+ printbuf_exit(&buf);
return ret;
}
struct bkey_s_c k;
struct reflink_gc *r;
size_t idx = 0;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
if (metadata_only)
"reflink key has wrong refcount:\n"
" %s\n"
" should be %u",
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf),
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf),
r->refcount)) {
struct bkey_i *new;
bch2_trans_iter_exit(&trans, &iter);
c->reflink_gc_nr = 0;
bch2_trans_exit(&trans);
+ printbuf_exit(&buf);
return ret;
}
struct bkey_s_c k;
struct gc_stripe *m;
const struct bch_stripe *s;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
unsigned i;
int ret = 0;
"stripe has wrong block sector count %u:\n"
" %s\n"
" should be %u", i,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf),
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf),
m ? m->block_sectors[i] : 0)) {
struct bkey_i_stripe *new;
bch2_trans_iter_exit(&trans, &iter);
bch2_trans_exit(&trans);
+
+ printbuf_exit(&buf);
return ret;
}
#define btree_err(type, c, ca, b, i, msg, ...) \
({ \
__label__ out; \
- char _buf[300]; \
- char *_buf2 = _buf; \
- struct printbuf out = PBUF(_buf); \
- \
- _buf2 = kmalloc(4096, GFP_ATOMIC); \
- if (_buf2) \
- out = _PBUF(_buf2, 4986); \
+ struct printbuf out = PRINTBUF; \
\
btree_err_msg(&out, c, ca, b, i, b->written, write); \
pr_buf(&out, ": " msg, ##__VA_ARGS__); \
if (type == BTREE_ERR_FIXABLE && \
write == READ && \
!test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags)) { \
- mustfix_fsck_err(c, "%s", _buf2); \
+ mustfix_fsck_err(c, "%s", out.buf); \
goto out; \
} \
\
switch (write) { \
case READ: \
- if (_buf2) \
- bch_err(c, "%s", _buf2); \
+ bch_err(c, "%s", out.buf); \
\
switch (type) { \
case BTREE_ERR_FIXABLE: \
} \
break; \
case WRITE: \
- bch_err(c, "corrupt metadata before write: %s", _buf2); \
+ bch_err(c, "corrupt metadata before write: %s", out.buf);\
\
if (bch2_fs_inconsistent(c)) { \
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
break; \
} \
out: \
- if (_buf2 != _buf) \
- kfree(_buf2); \
+ printbuf_exit(&out); \
true; \
})
{
unsigned version = le16_to_cpu(i->version);
const char *err;
- char buf1[100];
- char buf2[100];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
int ret = 0;
btree_err_on((version != BCH_BSET_VERSION_OLD &&
BTREE_ERR_FIXABLE, c, ca, b, i,
"bset past end of btree node")) {
i->u64s = 0;
- return 0;
+ ret = 0;
+ goto out;
}
btree_err_on(offset && !i->u64s,
btree_err_on(bpos_cmp(b->data->min_key, bp->min_key),
BTREE_ERR_MUST_RETRY, c, ca, b, NULL,
"incorrect min_key: got %s should be %s",
- (bch2_bpos_to_text(&PBUF(buf1), bn->min_key), buf1),
- (bch2_bpos_to_text(&PBUF(buf2), bp->min_key), buf2));
+ (printbuf_reset(&buf1),
+ bch2_bpos_to_text(&buf1, bn->min_key), buf1.buf),
+ (printbuf_reset(&buf2),
+ bch2_bpos_to_text(&buf2, bp->min_key), buf2.buf));
}
btree_err_on(bpos_cmp(bn->max_key, b->key.k.p),
BTREE_ERR_MUST_RETRY, c, ca, b, i,
"incorrect max key %s",
- (bch2_bpos_to_text(&PBUF(buf1), bn->max_key), buf1));
+ (printbuf_reset(&buf1),
+ bch2_bpos_to_text(&buf1, bn->max_key), buf1.buf));
if (write)
compat_btree_node(b->c.level, b->c.btree_id, version,
BSET_BIG_ENDIAN(i), write,
&bn->format);
}
+out:
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
{
unsigned version = le16_to_cpu(i->version);
struct bkey_packed *k, *prev = NULL;
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
bool updated_range = b->key.k.type == KEY_TYPE_btree_ptr_v2 &&
BTREE_PTR_RANGE_UPDATED(&bkey_i_to_btree_ptr_v2(&b->key)->v);
int ret = 0;
(!updated_range ? bch2_bkey_in_btree_node(b, u.s_c) : NULL) ?:
(write ? bch2_bkey_val_invalid(c, u.s_c) : NULL);
if (invalid) {
- char buf[160];
-
- bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
+ printbuf_reset(&buf1);
+ bch2_bkey_val_to_text(&buf1, c, u.s_c);
btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
- "invalid bkey: %s\n%s", invalid, buf);
+ "invalid bkey: %s\n%s", invalid, buf1.buf);
i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
memmove_u64s_down(k, bkey_next(k),
&b->format, k);
if (prev && bkey_iter_cmp(b, prev, k) > 0) {
- char buf1[80];
- char buf2[80];
struct bkey up = bkey_unpack_key(b, prev);
- bch2_bkey_to_text(&PBUF(buf1), &up);
- bch2_bkey_to_text(&PBUF(buf2), u.k);
+ printbuf_reset(&buf1);
+ bch2_bkey_to_text(&buf1, &up);
+ printbuf_reset(&buf2);
+ bch2_bkey_to_text(&buf2, u.k);
bch2_dump_bset(c, b, i, 0);
if (btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
"keys out of order: %s > %s",
- buf1, buf2)) {
+ buf1.buf, buf2.buf)) {
i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
memmove_u64s_down(k, bkey_next(k),
(u64 *) vstruct_end(i) - (u64 *) k);
k = bkey_next(k);
}
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
if (invalid ||
(bch2_inject_invalid_keys &&
!bversion_cmp(u.k->version, MAX_VERSION))) {
- char buf[160];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, u.s_c);
+ bch2_bkey_val_to_text(&buf, c, u.s_c);
btree_err(BTREE_ERR_FIXABLE, c, NULL, b, i,
"invalid bkey %s: %s", buf, invalid);
+ printbuf_exit(&buf);
btree_keys_account_key_drop(&b->nr, 0, k);
struct bch_dev *ca = bch_dev_bkey_exists(c, rb->pick.ptr.dev);
struct bio *bio = &rb->bio;
struct bch_io_failures failed = { .nr = 0 };
- char buf[200];
- struct printbuf out;
+ struct printbuf buf = PRINTBUF;
bool saw_error = false;
bool can_retry;
bio->bi_status = BLK_STS_REMOVED;
}
start:
- out = PBUF(buf);
- btree_pos_to_text(&out, c, b);
+ printbuf_reset(&buf);
+ btree_pos_to_text(&buf, c, b);
bch2_dev_io_err_on(bio->bi_status, ca, "btree read error %s for %s",
- bch2_blk_status_to_str(bio->bi_status), buf);
+ bch2_blk_status_to_str(bio->bi_status), buf.buf);
if (rb->have_ioref)
percpu_ref_put(&ca->io_ref);
rb->have_ioref = false;
bch2_time_stats_update(&c->times[BCH_TIME_btree_node_read],
rb->start_time);
bio_put(&rb->bio);
+ printbuf_exit(&buf);
if (saw_error && !btree_node_read_error(b))
bch2_btree_node_rewrite_async(c, b);
container_of(cl, struct btree_node_read_all, cl);
struct bch_fs *c = ra->c;
struct btree *b = ra->b;
+ struct printbuf buf = PRINTBUF;
bool dump_bset_maps = false;
bool have_retry = false;
int ret = 0, best = -1, write = READ;
fsck_err:
if (dump_bset_maps) {
for (i = 0; i < ra->nr; i++) {
- char buf[200];
- struct printbuf out = PBUF(buf);
struct btree_node *bn = ra->buf[i];
struct btree_node_entry *bne = NULL;
unsigned offset = 0, sectors;
if (ra->err[i])
continue;
+ printbuf_reset(&buf);
+
while (offset < btree_sectors(c)) {
if (!offset) {
sectors = vstruct_sectors(bn, c->block_bits);
sectors = vstruct_sectors(bne, c->block_bits);
}
- pr_buf(&out, " %u-%u", offset, offset + sectors);
+ pr_buf(&buf, " %u-%u", offset, offset + sectors);
if (bne && bch2_journal_seq_is_blacklisted(c,
le64_to_cpu(bne->keys.journal_seq), false))
- pr_buf(&out, "*");
+ pr_buf(&buf, "*");
offset += sectors;
}
bne = ra->buf[i] + (offset << 9);
if (bne->keys.seq == bn->keys.seq) {
if (!gap)
- pr_buf(&out, " GAP");
+ pr_buf(&buf, " GAP");
gap = true;
sectors = vstruct_sectors(bne, c->block_bits);
- pr_buf(&out, " %u-%u", offset, offset + sectors);
+ pr_buf(&buf, " %u-%u", offset, offset + sectors);
if (bch2_journal_seq_is_blacklisted(c,
le64_to_cpu(bne->keys.journal_seq), false))
- pr_buf(&out, "*");
+ pr_buf(&buf, "*");
}
offset++;
}
- bch_err(c, "replica %u:%s", i, buf);
+ bch_err(c, "replica %u:%s", i, buf.buf);
}
}
closure_debug_destroy(&ra->cl);
kfree(ra);
+ printbuf_exit(&buf);
clear_btree_node_read_in_flight(b);
wake_up_bit(&b->flags, BTREE_NODE_read_in_flight);
struct btree_read_bio *rb;
struct bch_dev *ca;
struct bio *bio;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret;
- btree_pos_to_text(&PBUF(buf), c, b);
+ btree_pos_to_text(&buf, c, b);
trace_btree_read(c, b);
if (bch2_verify_all_btree_replicas &&
!btree_node_read_all_replicas(c, b, sync))
- return;
+ goto out;
ret = bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key),
NULL, &pick);
if (bch2_fs_fatal_err_on(ret <= 0, c,
"btree node read error: no device to read from\n"
- " at %s", buf)) {
+ " at %s", buf.buf)) {
set_btree_node_read_error(b);
- return;
+ goto out;
}
ca = bch_dev_bkey_exists(c, pick.ptr.dev);
else
queue_work(c->io_complete_wq, &rb->work);
}
+out:
+ printbuf_exit(&buf);
}
int bch2_btree_root_read(struct bch_fs *c, enum btree_id id,
struct btree_node_iter tmp;
bool locked;
struct bkey_packed *p, *k;
- char buf1[100], buf2[100], buf3[100];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
+ struct printbuf buf3 = PRINTBUF;
const char *msg;
if (!bch2_debug_check_iterators)
btree_node_unlock(path, level);
return;
err:
- strcpy(buf2, "(none)");
- strcpy(buf3, "(none)");
-
- bch2_bpos_to_text(&PBUF(buf1), path->pos);
+ bch2_bpos_to_text(&buf1, path->pos);
if (p) {
struct bkey uk = bkey_unpack_key(l->b, p);
- bch2_bkey_to_text(&PBUF(buf2), &uk);
+ bch2_bkey_to_text(&buf2, &uk);
+ } else {
+ pr_buf(&buf2, "(none)");
}
if (k) {
struct bkey uk = bkey_unpack_key(l->b, k);
- bch2_bkey_to_text(&PBUF(buf3), &uk);
+ bch2_bkey_to_text(&buf3, &uk);
+ } else {
+ pr_buf(&buf3, "(none)");
}
panic("path should be %s key at level %u:\n"
"path pos %s\n"
"prev key %s\n"
"cur key %s\n",
- msg, level, buf1, buf2, buf3);
+ msg, level, buf1.buf, buf2.buf, buf3.buf);
}
static void bch2_btree_path_verify(struct btree_trans *trans,
if (!bkey_cmp(prev.k->p, k.k->p) &&
bch2_snapshot_is_ancestor(trans->c, iter->snapshot,
prev.k->p.snapshot) > 0) {
- char buf1[100], buf2[200];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
- bch2_bkey_to_text(&PBUF(buf1), k.k);
- bch2_bkey_to_text(&PBUF(buf2), prev.k);
+ bch2_bkey_to_text(&buf1, k.k);
+ bch2_bkey_to_text(&buf2, prev.k);
panic("iter snap %u\n"
"k %s\n"
"prev %s\n",
iter->snapshot,
- buf1, buf2);
+ buf1.buf, buf2.buf);
}
out:
bch2_trans_iter_exit(trans, ©);
{
struct btree_path *path;
unsigned idx;
- char buf[100];
+ struct printbuf buf = PRINTBUF;
trans_for_each_path_inorder(trans, path, idx) {
int cmp = cmp_int(path->btree_id, id) ?:
}
bch2_dump_trans_paths_updates(trans);
+ bch2_bpos_to_text(&buf, pos);
+
panic("not locked: %s %s%s\n",
- bch2_btree_ids[id],
- (bch2_bpos_to_text(&PBUF(buf), pos), buf),
+ bch2_btree_ids[id], buf.buf,
key_cache ? " cached" : "");
}
if (!k ||
bkey_deleted(k) ||
bkey_cmp_left_packed(l->b, k, &b->key.k.p)) {
- char buf1[100];
- char buf2[100];
- char buf3[100];
- char buf4[100];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
+ struct printbuf buf3 = PRINTBUF;
+ struct printbuf buf4 = PRINTBUF;
struct bkey uk = bkey_unpack_key(b, k);
bch2_dump_btree_node(c, l->b);
- bch2_bpos_to_text(&PBUF(buf1), path->pos);
- bch2_bkey_to_text(&PBUF(buf2), &uk);
- bch2_bpos_to_text(&PBUF(buf3), b->data->min_key);
- bch2_bpos_to_text(&PBUF(buf3), b->data->max_key);
+ bch2_bpos_to_text(&buf1, path->pos);
+ bch2_bkey_to_text(&buf2, &uk);
+ bch2_bpos_to_text(&buf3, b->data->min_key);
+ bch2_bpos_to_text(&buf3, b->data->max_key);
panic("parent iter doesn't point to new node:\n"
"iter pos %s %s\n"
"iter key %s\n"
"new node %s-%s\n",
- bch2_btree_ids[path->btree_id], buf1,
- buf2, buf3, buf4);
+ bch2_btree_ids[path->btree_id],
+ buf1.buf, buf2.buf, buf3.buf, buf4.buf);
}
if (!parent_locked)
{
struct btree_path *path;
struct btree_insert_entry *i;
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
unsigned idx;
- char buf1[300], buf2[300];
btree_trans_sort_paths(trans);
- trans_for_each_path_inorder(trans, path, idx)
+ trans_for_each_path_inorder(trans, path, idx) {
+ printbuf_reset(&buf1);
+
+ bch2_bpos_to_text(&buf1, path->pos);
+
printk(KERN_ERR "path: idx %u ref %u:%u%s%s btree %s pos %s locks %u %pS\n",
path->idx, path->ref, path->intent_ref,
path->should_be_locked ? " S" : "",
path->preserve ? " P" : "",
bch2_btree_ids[path->btree_id],
- (bch2_bpos_to_text(&PBUF(buf1), path->pos), buf1),
+ buf1.buf,
path->nodes_locked,
#ifdef CONFIG_BCACHEFS_DEBUG
(void *) path->ip_allocated
NULL
#endif
);
+ }
trans_for_each_update(trans, i) {
struct bkey u;
struct bkey_s_c old = bch2_btree_path_peek_slot(i->path, &u);
+ printbuf_reset(&buf1);
+ printbuf_reset(&buf2);
+ bch2_bkey_val_to_text(&buf1, trans->c, old);
+ bch2_bkey_val_to_text(&buf2, trans->c, bkey_i_to_s_c(i->k));
+
printk(KERN_ERR "update: btree %s %pS\n old %s\n new %s",
bch2_btree_ids[i->btree_id],
(void *) i->ip_allocated,
- (bch2_bkey_val_to_text(&PBUF(buf1), trans->c, old), buf1),
- (bch2_bkey_val_to_text(&PBUF(buf2), trans->c, bkey_i_to_s_c(i->k)), buf2));
+ buf1.buf, buf2.buf);
}
+
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
}
static struct btree_path *btree_path_alloc(struct btree_trans *trans,
struct bkey_s_c k;
struct bkey_s_c_btree_ptr_v2 bp;
struct bkey unpacked;
- char buf1[100], buf2[100];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
BUG_ON(!b->c.level);
if (bpos_cmp(next_node, bp.v->min_key)) {
bch2_dump_btree_node(c, b);
- panic("expected next min_key %s got %s\n",
- (bch2_bpos_to_text(&PBUF(buf1), next_node), buf1),
- (bch2_bpos_to_text(&PBUF(buf2), bp.v->min_key), buf2));
+ bch2_bpos_to_text(&buf1, next_node);
+ bch2_bpos_to_text(&buf2, bp.v->min_key);
+ panic("expected next min_key %s got %s\n", buf1.buf, buf2.buf);
}
bch2_btree_node_iter_advance(&iter, b);
if (bch2_btree_node_iter_end(&iter)) {
if (bpos_cmp(k.k->p, b->key.k.p)) {
bch2_dump_btree_node(c, b);
- panic("expected end %s got %s\n",
- (bch2_bpos_to_text(&PBUF(buf1), b->key.k.p), buf1),
- (bch2_bpos_to_text(&PBUF(buf2), k.k->p), buf2));
+ bch2_bpos_to_text(&buf1, b->key.k.p);
+ bch2_bpos_to_text(&buf2, k.k->p);
+ panic("expected end %s got %s\n", buf1.buf, buf2.buf);
}
break;
}
invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(insert), btree_node_type(b)) ?:
bch2_bkey_in_btree_node(b, bkey_i_to_s_c(insert));
if (invalid) {
- char buf[160];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(insert));
- bch2_fs_inconsistent(c, "inserting invalid bkey %s: %s", buf, invalid);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert));
+ bch2_fs_inconsistent(c, "inserting invalid bkey %s: %s", buf.buf, invalid);
+ printbuf_exit(&buf);
dump_stack();
}
}
if (bkey_cmp(bpos_successor(prev->data->max_key), next->data->min_key)) {
- char buf1[100], buf2[100];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
- bch2_bpos_to_text(&PBUF(buf1), prev->data->max_key);
- bch2_bpos_to_text(&PBUF(buf2), next->data->min_key);
+ bch2_bpos_to_text(&buf1, prev->data->max_key);
+ bch2_bpos_to_text(&buf2, next->data->min_key);
bch_err(c,
"btree topology error in btree merge:\n"
" prev ends at %s\n"
" next starts at %s",
- buf1, buf2);
+ buf1.buf, buf2.buf);
+ printbuf_exit(&buf1);
+ printbuf_exit(&buf2);
bch2_topology_error(c);
ret = -EIO;
goto err;
const char *invalid = bch2_bkey_invalid(c,
bkey_i_to_s_c(i->k), i->bkey_type);
if (invalid) {
- char buf[200];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(i->k));
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(i->k));
bch2_fs_fatal_error(c, "invalid bkey %s on insert from %s -> %ps: %s\n",
- buf, trans->fn, (void *) i->ip_allocated, invalid);
+ buf.buf, trans->fn, (void *) i->ip_allocated, invalid);
+ printbuf_exit(&buf);
return -EINVAL;
}
btree_insert_entry_checks(trans, i);
{
struct bch_fs_usage __percpu *fs_usage;
int idx, ret = 0;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
percpu_down_read(&c->mark_lock);
+ buf.atomic++;
idx = bch2_replicas_entry_idx(c, r);
if (idx < 0 &&
(test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) ||
fsck_err(c, "no replicas entry\n"
" while marking %s",
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))) {
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))) {
percpu_up_read(&c->mark_lock);
ret = bch2_mark_replicas(c, r);
- if (ret)
- return ret;
-
percpu_down_read(&c->mark_lock);
+
+ if (ret)
+ goto err;
idx = bch2_replicas_entry_idx(c, r);
}
if (idx < 0) {
err:
fsck_err:
percpu_up_read(&c->mark_lock);
+ printbuf_exit(&buf);
return ret;
}
u16 bucket_sectors = !ptr->cached
? dirty_sectors
: cached_sectors;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
+ int ret = 0;
if (gen_after(ptr->gen, b_gen)) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
ptr->dev, bucket_nr, b_gen,
bch2_data_types[bucket_data_type ?: ptr_data_type],
ptr->gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
- return -EIO;
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf));
+ ret = -EIO;
+ goto err;
}
if (gen_cmp(b_gen, ptr->gen) > BUCKET_GC_GEN_MAX) {
ptr->dev, bucket_nr, b_gen,
bch2_data_types[bucket_data_type ?: ptr_data_type],
ptr->gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
- return -EIO;
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf));
+ ret = -EIO;
+ goto err;
}
if (b_gen != ptr->gen && !ptr->cached) {
*bucket_gen(ca, bucket_nr),
bch2_data_types[bucket_data_type ?: ptr_data_type],
ptr->gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
- return -EIO;
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf));
+ ret = -EIO;
+ goto err;
}
- if (b_gen != ptr->gen)
- return 1;
+ if (b_gen != ptr->gen) {
+ ret = 1;
+ goto err;
+ }
if (bucket_data_type && ptr_data_type &&
bucket_data_type != ptr_data_type) {
ptr->dev, bucket_nr, b_gen,
bch2_data_types[bucket_data_type],
bch2_data_types[ptr_data_type],
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
- return -EIO;
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf));
+ ret = -EIO;
+ goto err;
}
if ((unsigned) (bucket_sectors + sectors) > U16_MAX) {
ptr->dev, bucket_nr, b_gen,
bch2_data_types[bucket_data_type ?: ptr_data_type],
bucket_sectors, sectors,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
- return -EIO;
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf));
+ ret = -EIO;
+ goto err;
}
-
- return 0;
+err:
+ printbuf_exit(&buf);
+ return ret;
}
static int mark_stripe_bucket(struct btree_trans *trans,
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
struct bucket *g;
struct bucket_mark new, old;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
BUG_ON(!(flags & BTREE_TRIGGER_GC));
/* * XXX doesn't handle deletion */
percpu_down_read(&c->mark_lock);
+ buf.atomic++;
g = PTR_GC_BUCKET(ca, ptr);
if (g->mark.dirty_sectors ||
bch2_fs_inconsistent(c,
"bucket %u:%zu gen %u: multiple stripes using same bucket\n%s",
ptr->dev, PTR_BUCKET_NR(ca, ptr), g->mark.gen,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf));
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf));
ret = -EINVAL;
goto err;
}
bch2_dev_usage_update(c, ca, old, new, journal_seq, true);
err:
percpu_up_read(&c->mark_lock);
-
- return 0;
+ printbuf_exit(&buf);
+ return ret;
}
static int __mark_pointer(struct btree_trans *trans,
if (r.e.nr_devs) {
ret = update_replicas(c, k, &r.e, dirty_sectors, journal_seq, true);
if (ret) {
- char buf[200];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, k);
- bch2_fs_fatal_error(c, "no replicas entry for %s", buf);
+ bch2_bkey_val_to_text(&buf, c, k);
+ bch2_fs_fatal_error(c, "no replicas entry for %s", buf.buf);
+ printbuf_exit(&buf);
return ret;
}
}
struct stripe *m = genradix_ptr(&c->stripes, idx);
if (!m || (old_s && !m->alive)) {
- char buf1[200], buf2[200];
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf1), c, old);
- bch2_bkey_val_to_text(&PBUF(buf2), c, new);
+ bch2_bkey_val_to_text(&buf1, c, old);
+ bch2_bkey_val_to_text(&buf2, c, new);
bch_err_ratelimited(c, "error marking nonexistent stripe %llu while marking\n"
"old %s\n"
- "new %s", idx, buf1, buf2);
+ "new %s", idx, buf1.buf, buf2.buf);
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
bch2_inconsistent_error(c);
return -1;
}
((s64) m->sectors * m->nr_redundant),
journal_seq, gc);
if (ret) {
- char buf[200];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, new);
- bch2_fs_fatal_error(c, "no replicas entry for %s", buf);
+ bch2_bkey_val_to_text(&buf, c, new);
+ bch2_fs_fatal_error(c, "no replicas entry for %s", buf.buf);
+ printbuf_exit(&buf);
return ret;
}
}
int add = !(flags & BTREE_TRIGGER_OVERWRITE) ? 1 : -1;
u64 next_idx = end;
s64 ret = 0;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
if (r_idx >= c->reflink_gc_nr)
goto not_found;
if (fsck_err(c, "pointer to missing indirect extent\n"
" %s\n"
" missing range %llu-%llu",
- (bch2_bkey_val_to_text(&PBUF(buf), c, p.s_c), buf),
+ (bch2_bkey_val_to_text(&buf, c, p.s_c), buf.buf),
*idx, next_idx)) {
struct bkey_i_error new;
*idx = next_idx;
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
{
struct bch_fs *c = trans->c;
struct btree_insert_entry *i;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
bch_err(c, "disk usage increased %lli more than %u sectors reserved",
should_not_have_added, disk_res_sectors);
struct bkey_s_c old = { &i->old_k, i->old_v };
pr_err("while inserting");
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(i->k));
- pr_err(" %s", buf);
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(i->k));
+ pr_err(" %s", buf.buf);
pr_err("overlapping with");
- bch2_bkey_val_to_text(&PBUF(buf), c, old);
- pr_err(" %s", buf);
+ printbuf_reset(&buf);
+ bch2_bkey_val_to_text(&buf, c, old);
+ pr_err(" %s", buf.buf);
}
+
__WARN();
+ printbuf_exit(&buf);
}
int bch2_trans_fs_usage_apply(struct btree_trans *trans,
struct bkey_i *n;
__le64 *refcount;
int add = !(flags & BTREE_TRIGGER_OVERWRITE) ? 1 : -1;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret;
bch2_trans_iter_init(trans, &iter, BTREE_ID_reflink, POS(0, *idx),
refcount = bkey_refcount(n);
if (!refcount) {
- bch2_bkey_val_to_text(&PBUF(buf), c, p.s_c);
+ bch2_bkey_val_to_text(&buf, c, p.s_c);
bch2_fs_inconsistent(c,
"nonexistent indirect extent at %llu while marking\n %s",
- *idx, buf);
+ *idx, buf.buf);
ret = -EIO;
goto err;
}
if (!*refcount && (flags & BTREE_TRIGGER_OVERWRITE)) {
- bch2_bkey_val_to_text(&PBUF(buf), c, p.s_c);
+ bch2_bkey_val_to_text(&buf, c, p.s_c);
bch2_fs_inconsistent(c,
"indirect extent refcount underflow at %llu while marking\n %s",
- *idx, buf);
+ *idx, buf.buf);
ret = -EIO;
goto err;
}
*idx = k.k->p.offset;
err:
bch2_trans_iter_exit(trans, &iter);
+ printbuf_exit(&buf);
return ret;
}
unsigned long now;
unsigned i;
+ out->atomic++;
spin_lock(&clock->timer_lock);
now = atomic64_read(&clock->now);
clock->timers.data[i]->fn,
clock->timers.data[i]->expire - now);
spin_unlock(&clock->timer_lock);
+ --out->atomic;
}
void bch2_io_clock_exit(struct io_clock *clock)
failed |= bch2_btree_verify_replica(c, b, p);
if (failed) {
- char buf[200];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(&b->key));
- bch2_fs_fatal_error(c, "btree node verify failed for : %s\n", buf);
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
+ bch2_fs_fatal_error(c, "btree node verify failed for : %s\n", buf.buf);
+ printbuf_exit(&buf);
}
out:
mutex_unlock(&c->verify_lock);
struct bch_fs *c;
enum btree_id id;
- char buf[1 << 12];
- size_t bytes; /* what's currently in buf */
+ struct printbuf buf;
char __user *ubuf; /* destination user buffer */
size_t size; /* size of requested read */
static int flush_buf(struct dump_iter *i)
{
- if (i->bytes) {
- size_t bytes = min(i->bytes, i->size);
- int err = copy_to_user(i->ubuf, i->buf, bytes);
+ if (i->buf.pos) {
+ size_t bytes = min_t(size_t, i->buf.pos, i->size);
+ int err = copy_to_user(i->ubuf, i->buf.buf, bytes);
if (err)
return err;
i->ret += bytes;
i->ubuf += bytes;
i->size -= bytes;
- i->bytes -= bytes;
- memmove(i->buf, i->buf + bytes, i->bytes);
+ i->buf.pos -= bytes;
+ memmove(i->buf.buf, i->buf.buf + bytes, i->buf.pos);
}
return 0;
i->from = POS_MIN;
i->c = container_of(bd, struct bch_fs, btree_debug[bd->id]);
i->id = bd->id;
+ i->buf = PRINTBUF;
return 0;
}
static int bch2_dump_release(struct inode *inode, struct file *file)
{
- kfree(file->private_data);
+ struct dump_iter *i = file->private_data;
+
+ printbuf_exit(&i->buf);
+ kfree(i);
return 0;
}
k = bch2_btree_iter_peek(&iter);
while (k.k && !(err = bkey_err(k))) {
- bch2_bkey_val_to_text(&PBUF(i->buf), i->c, k);
- i->bytes = strlen(i->buf);
- BUG_ON(i->bytes >= sizeof(i->buf));
- i->buf[i->bytes] = '\n';
- i->bytes++;
+ bch2_bkey_val_to_text(&i->buf, i->c, k);
+ pr_char(&i->buf, '\n');
k = bch2_btree_iter_next(&iter);
i->from = iter.pos;
bch2_trans_init(&trans, i->c, 0, 0);
for_each_btree_node(&trans, iter, i->id, i->from, 0, b, err) {
- bch2_btree_node_to_text(&PBUF(i->buf), i->c, b);
- i->bytes = strlen(i->buf);
+ bch2_btree_node_to_text(&i->buf, i->c, b);
err = flush_buf(i);
if (err)
break;
bch2_btree_node_iter_peek(&l->iter, l->b);
if (l->b != prev_node) {
- bch2_btree_node_to_text(&PBUF(i->buf), i->c, l->b);
- i->bytes = strlen(i->buf);
+ bch2_btree_node_to_text(&i->buf, i->c, l->b);
err = flush_buf(i);
if (err)
break;
}
prev_node = l->b;
- bch2_bfloat_to_text(&PBUF(i->buf), l->b, _k);
- i->bytes = strlen(i->buf);
+ bch2_bfloat_to_text(&i->buf, l->b, _k);
err = flush_buf(i);
if (err)
break;
struct bch_csum got = ec_block_checksum(buf, i, offset);
if (bch2_crc_cmp(want, got)) {
- char buf2[200];
+ struct printbuf buf2 = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(&buf->key.k_i));
+ bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(&buf->key.k_i));
bch_err_ratelimited(c,
"stripe checksum error for %ps at %u:%u: csum type %u, expected %llx got %llx\n%s",
(void *) _RET_IP_, i, j, v->csum_type,
- want.lo, got.lo, buf2);
+ want.lo, got.lo, buf2.buf);
+ printbuf_exit(&buf2);
clear_bit(i, buf->valid);
break;
}
{
struct bch_fs *c = root->d_sb->s_fs_info;
enum bch_opt_id i;
- char buf[512];
+ struct printbuf buf = PRINTBUF;
+ int ret = 0;
for (i = 0; i < bch2_opts_nr; i++) {
const struct bch_option *opt = &bch2_opt_table[i];
if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
continue;
- bch2_opt_to_text(&PBUF(buf), c, opt, v,
+ printbuf_reset(&buf);
+ bch2_opt_to_text(&buf, c, opt, v,
OPT_SHOW_MOUNT_STYLE);
seq_putc(seq, ',');
- seq_puts(seq, buf);
+ seq_puts(seq, buf.buf);
}
- return 0;
+ if (buf.allocation_failure)
+ ret = -ENOMEM;
+ printbuf_exit(&buf);
+ return ret;
}
static void bch2_put_super(struct super_block *sb)
struct bkey_s_c k)
{
struct bch_fs *c = trans->c;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
if (mustfix_fsck_err_on(!snapshot_t(c, k.k->p.snapshot)->equiv, c,
"key in missing snapshot: %s",
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))
- return bch2_btree_delete_at(trans, iter,
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
+ ret = bch2_btree_delete_at(trans, iter,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?: 1;
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
{
struct bch_fs *c = trans->c;
struct btree_iter iter = { NULL };
- char buf[200];
+ struct printbuf buf = PRINTBUF;
struct bkey_s_c k;
u64 hash;
int ret = 0;
if (fsck_err_on(k.k->type == desc.key_type &&
!desc.cmp_bkey(k, hash_k), c,
"duplicate hash table keys:\n%s",
- (bch2_bkey_val_to_text(&PBUF(buf), c,
- hash_k), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, hash_k),
+ buf.buf))) {
ret = bch2_hash_delete_at(trans, desc, hash_info, k_iter, 0) ?: 1;
break;
}
}
}
+out:
bch2_trans_iter_exit(trans, &iter);
+ printbuf_exit(&buf);
return ret;
bad_hash:
if (fsck_err(c, "hash table key at wrong offset: btree %u inode %llu offset %llu, "
"hashed to %llu\n%s",
desc.btree_id, hash_k.k->p.inode, hash_k.k->p.offset, hash,
- (bch2_bkey_val_to_text(&PBUF(buf), c, hash_k), buf)) == FSCK_ERR_IGNORE)
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, hash_k), buf.buf)) == FSCK_ERR_IGNORE)
return 0;
ret = hash_redo_key(trans, desc, hash_info, k_iter, hash_k);
bch_err(c, "hash_redo_key err %i", ret);
return ret;
}
- return -EINTR;
+ ret = -EINTR;
fsck_err:
- return ret;
+ goto out;
}
static int check_inode(struct btree_trans *trans,
struct bch_fs *c = trans->c;
struct bkey_s_c k;
struct inode_walker_entry *i;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
k = bch2_btree_iter_peek(iter);
if (!k.k)
- return 0;
+ goto out;
ret = bkey_err(k);
if (ret)
- return ret;
+ goto err;
ret = check_key_has_snapshot(trans, iter, k);
- if (ret)
- return ret < 0 ? ret : 0;
+ if (ret) {
+ ret = ret < 0 ? ret : 0;
+ goto out;
+ }
ret = snapshots_seen_update(c, s, k.k->p);
if (ret)
- return ret;
+ goto err;
if (k.k->type == KEY_TYPE_whiteout)
- return 0;
+ goto out;
if (inode->cur_inum != k.k->p.inode) {
ret = check_i_sectors(trans, inode);
if (ret)
- return ret;
+ goto err;
}
#if 0
if (bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) {
bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(prev.k));
bch2_bkey_val_to_text(&PBUF(buf2), c, k);
- if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2))
- return fix_overlapping_extent(trans, k, prev.k->k.p) ?: -EINTR;
+ if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2)) {
+ ret = fix_overlapping_extent(trans, k, prev.k->k.p) ?: -EINTR;
+ goto out;
+ }
}
#endif
ret = __walk_inode(trans, inode, k.k->p);
if (ret < 0)
- return ret;
+ goto err;
if (fsck_err_on(ret == INT_MAX, c,
"extent in missing inode:\n %s",
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))
- return bch2_btree_delete_at(trans, iter,
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+ ret = bch2_btree_delete_at(trans, iter,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+ goto out;
+ }
- if (ret == INT_MAX)
- return 0;
+ if (ret == INT_MAX) {
+ ret = 0;
+ goto out;
+ }
i = inode->d + ret;
ret = 0;
!S_ISLNK(i->inode.bi_mode), c,
"extent in non regular inode mode %o:\n %s",
i->inode.bi_mode,
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))
- return bch2_btree_delete_at(trans, iter,
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+ ret = bch2_btree_delete_at(trans, iter,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+ goto out;
+ }
if (!bch2_snapshot_internal_node(c, k.k->p.snapshot)) {
for_each_visible_inode(c, s, inode, k.k->p.snapshot, i) {
"extent type %u offset %llu past end of inode %llu, i_size %llu",
k.k->type, k.k->p.offset, k.k->p.inode, i->inode.bi_size)) {
bch2_fs_lazy_rw(c);
- return bch2_btree_delete_range_trans(trans, BTREE_ID_extents,
+ ret = bch2_btree_delete_range_trans(trans, BTREE_ID_extents,
SPOS(k.k->p.inode, round_up(i->inode.bi_size, block_bytes(c)) >> 9,
k.k->p.snapshot),
POS(k.k->p.inode, U64_MAX),
0, NULL) ?: -EINTR;
+ goto out;
}
}
}
bch2_bkey_buf_reassemble(&prev, c, k);
#endif
+out:
+err:
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
struct bch_fs *c = trans->c;
struct bkey_i_dirent *n;
bool backpointer_exists = true;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret = 0;
if (!target->bi_dir &&
"directory %llu with multiple links",
target->bi_inum)) {
ret = __remove_dirent(trans, d.k->p);
- if (ret)
- goto err;
- return 0;
+ goto out;
}
if (fsck_err_on(backpointer_exists &&
"incorrect d_type: got %s, should be %s:\n%s",
bch2_d_type_str(d.v->d_type),
bch2_d_type_str(inode_d_type(target)),
- (bch2_bkey_val_to_text(&PBUF(buf), c, d.s_c), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf))) {
n = bch2_trans_kmalloc(trans, bkey_bytes(d.k));
ret = PTR_ERR_OR_ZERO(n);
if (ret)
- return ret;
+ goto err;
bkey_reassemble(&n->k_i, d.s_c);
n->v.d_type = inode_d_type(target);
ret = bch2_trans_update(trans, iter, &n->k_i, 0);
if (ret)
- return ret;
+ goto err;
d = dirent_i_to_s_c(n);
}
n = bch2_trans_kmalloc(trans, bkey_bytes(d.k));
ret = PTR_ERR_OR_ZERO(n);
if (ret)
- return ret;
+ goto err;
bkey_reassemble(&n->k_i, d.s_c);
n->v.d_parent_subvol = cpu_to_le32(target->bi_parent_subvol);
ret = bch2_trans_update(trans, iter, &n->k_i, 0);
if (ret)
- return ret;
+ goto err;
d = dirent_i_to_s_c(n);
}
+out:
err:
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
struct bkey_s_c k;
struct bkey_s_c_dirent d;
struct inode_walker_entry *i;
- char buf[200];
- int ret;
+ struct printbuf buf = PRINTBUF;
+ int ret = 0;
k = bch2_btree_iter_peek(iter);
if (!k.k)
- return 0;
+ goto out;
ret = bkey_err(k);
if (ret)
- return ret;
+ goto err;
ret = check_key_has_snapshot(trans, iter, k);
- if (ret)
- return ret < 0 ? ret : 0;
+ if (ret) {
+ ret = ret < 0 ? ret : 0;
+ goto out;
+ }
ret = snapshots_seen_update(c, s, k.k->p);
if (ret)
- return ret;
+ goto err;
if (k.k->type == KEY_TYPE_whiteout)
- return 0;
+ goto out;
if (dir->cur_inum != k.k->p.inode) {
ret = check_subdir_count(trans, dir);
if (ret)
- return ret;
+ goto err;
}
ret = __walk_inode(trans, dir, k.k->p);
if (ret < 0)
- return ret;
+ goto err;
if (fsck_err_on(ret == INT_MAX, c,
"dirent in nonexisting directory:\n%s",
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))
- return bch2_btree_delete_at(trans, iter,
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+ ret = bch2_btree_delete_at(trans, iter,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+ goto out;
+ }
- if (ret == INT_MAX)
- return 0;
+ if (ret == INT_MAX) {
+ ret = 0;
+ goto out;
+ }
i = dir->d + ret;
ret = 0;
if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c,
"dirent in non directory inode type %s:\n%s",
bch2_d_type_str(inode_d_type(&i->inode)),
- (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf)))
- return bch2_btree_delete_at(trans, iter, 0);
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+ ret = bch2_btree_delete_at(trans, iter, 0);
+ goto out;
+ }
if (dir->first_this_inode)
*hash_info = bch2_hash_info_init(c, &dir->d[0].inode);
ret = hash_check_key(trans, bch2_dirent_hash_desc,
hash_info, iter, k);
if (ret < 0)
- return ret;
- if (ret) /* dirent has been deleted */
- return 0;
+ goto err;
+ if (ret) {
+ /* dirent has been deleted */
+ ret = 0;
+ goto out;
+ }
if (k.k->type != KEY_TYPE_dirent)
- return 0;
+ goto out;
d = bkey_s_c_to_dirent(k);
ret = __subvol_lookup(trans, target_subvol,
&target_snapshot, &target_inum);
if (ret && ret != -ENOENT)
- return ret;
+ goto err;
if (fsck_err_on(ret, c,
"dirent points to missing subvolume %llu",
- le64_to_cpu(d.v->d_child_subvol)))
- return __remove_dirent(trans, d.k->p);
+ le64_to_cpu(d.v->d_child_subvol))) {
+ ret = __remove_dirent(trans, d.k->p);
+ goto err;
+ }
ret = __lookup_inode(trans, target_inum,
&subvol_root, &target_snapshot);
if (ret && ret != -ENOENT)
- return ret;
+ goto err;
if (fsck_err_on(ret, c,
"subvolume %u points to missing subvolume root %llu",
target_subvol,
target_inum)) {
bch_err(c, "repair not implemented yet");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
if (fsck_err_on(subvol_root.bi_subvol != target_subvol, c,
subvol_root.bi_subvol = target_subvol;
ret = __write_inode(trans, &subvol_root, target_snapshot);
if (ret)
- return ret;
+ goto err;
}
ret = check_dirent_target(trans, iter, d, &subvol_root,
target_snapshot);
if (ret)
- return ret;
+ goto err;
} else {
ret = __get_visible_inodes(trans, target, s, le64_to_cpu(d.v->d_inum));
if (ret)
- return ret;
+ goto err;
if (fsck_err_on(!target->nr, c,
"dirent points to missing inode:\n%s",
- (bch2_bkey_val_to_text(&PBUF(buf), c,
- k), buf))) {
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k),
+ buf.buf))) {
ret = __remove_dirent(trans, d.k->p);
if (ret)
- return ret;
+ goto err;
}
for (i = target->d; i < target->d + target->nr; i++) {
ret = check_dirent_target(trans, iter, d,
&i->inode, i->snapshot);
if (ret)
- return ret;
+ goto err;
}
}
for_each_visible_inode(c, s, dir, d.k->p.snapshot, i)
i->count++;
+out:
+err:
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
struct bch_fs *c = trans->c;
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr.dev);
struct btree_iter iter;
- char buf[200];
+ struct printbuf buf = PRINTBUF;
int ret;
- bch2_bkey_val_to_text(&PBUF(buf), c, k);
- bch2_fs_inconsistent(c, "Attempting to read from stale dirty pointer: %s", buf);
+ bch2_bkey_val_to_text(&buf, c, k);
+ bch2_fs_inconsistent(c, "Attempting to read from stale dirty pointer: %s", buf.buf);
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
POS(ptr.dev, PTR_BUCKET_NR(ca, &ptr)),
ret = lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_slot(&iter)));
if (ret)
- return;
+ goto out;
- bch2_bkey_val_to_text(&PBUF(buf), c, k);
- bch_err(c, "%s", buf);
+ bch2_bkey_val_to_text(&buf, c, k);
+ bch_err(c, "%s", buf.buf);
bch_err(c, "memory gen: %u", *bucket_gen(ca, iter.pos.offset));
bch2_trans_iter_exit(trans, &iter);
+out:
+ printbuf_exit(&buf);
}
int __bch2_read_extent(struct btree_trans *trans, struct bch_read_bio *orig,
!can_discard &&
j->reservations.idx == j->reservations.unwritten_idx &&
(flags & JOURNAL_RES_GET_RESERVED)) {
- char *journal_debug_buf = kmalloc(4096, GFP_ATOMIC);
+ struct printbuf buf = PRINTBUF;
bch_err(c, "Journal stuck! Hava a pre-reservation but journal full");
- if (journal_debug_buf) {
- bch2_journal_debug_to_text(&_PBUF(journal_debug_buf, 4096), j);
- bch_err(c, "%s", journal_debug_buf);
- bch2_journal_pins_to_text(&_PBUF(journal_debug_buf, 4096), j);
- bch_err(c, "Journal pins:\n%s", journal_debug_buf);
- kfree(journal_debug_buf);
- }
+ bch2_journal_debug_to_text(&buf, j);
+ bch_err(c, "%s", buf.buf);
+
+ printbuf_reset(&buf);
+ bch2_journal_pins_to_text(&buf, j);
+ bch_err(c, "Journal pins:\n%s", buf.buf);
+ printbuf_exit(&buf);
bch2_fatal_error(c);
dump_stack();
}
unsigned long now = jiffies;
unsigned i;
+ out->atomic++;
+
rcu_read_lock();
s = READ_ONCE(j->reservations);
}
rcu_read_unlock();
+
+ --out->atomic;
}
void bch2_journal_debug_to_text(struct printbuf *out, struct journal *j)
u64 i;
spin_lock(&j->lock);
+ out->atomic++;
+
fifo_for_each_entry_ptr(pin_list, &j->pin, i) {
pr_buf(out, "%llu: count %u\n",
i, atomic_read(&pin_list->count));
pr_buf(out, "\t%px %ps\n",
pin, pin->flush);
}
+
+ --out->atomic;
spin_unlock(&j->lock);
}
invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(k),
__btree_node_type(level, btree_id));
if (invalid) {
- char buf[160];
+ struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(k));
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k));
mustfix_fsck_err(c, "invalid %s in %s entry offset %zi/%u: %s\n%s",
type, where,
(u64 *) k - entry->_data,
le16_to_cpu(entry->u64s),
- invalid, buf);
+ invalid, buf.buf);
+ printbuf_exit(&buf);
le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
memmove(k, bkey_next(k), next - (void *) bkey_next(k));
struct journal_replay *i, *t;
struct bch_dev *ca;
unsigned iter;
+ struct printbuf buf = PRINTBUF;
size_t keys = 0, entries = 0;
bool degraded = false;
u64 seq, last_seq = 0;
if (!last_seq) {
fsck_err(c, "journal read done, but no entries found after dropping non-flushes");
- return -1;
+ ret = -1;
+ goto err;
}
/* Drop blacklisted entries and entries older than last_seq: */
while (seq < le64_to_cpu(i->j.seq)) {
u64 missing_start, missing_end;
- char buf1[200], buf2[200];
+ struct printbuf buf1 = PRINTBUF, buf2 = PRINTBUF;
while (seq < le64_to_cpu(i->j.seq) &&
bch2_journal_seq_is_blacklisted(c, seq, false))
seq++;
if (i->list.prev != list) {
- struct printbuf out = PBUF(buf1);
struct journal_replay *p = list_prev_entry(i, list);
- bch2_journal_ptrs_to_text(&out, c, p);
- pr_buf(&out, " size %zu", vstruct_sectors(&p->j, c->block_bits));
+ bch2_journal_ptrs_to_text(&buf1, c, p);
+ pr_buf(&buf1, " size %zu", vstruct_sectors(&p->j, c->block_bits));
} else
- sprintf(buf1, "(none)");
- bch2_journal_ptrs_to_text(&PBUF(buf2), c, i);
+ pr_buf(&buf1, "(none)");
+ bch2_journal_ptrs_to_text(&buf2, c, i);
missing_end = seq - 1;
fsck_err(c, "journal entries %llu-%llu missing! (replaying %llu-%llu)\n"
" next at %s",
missing_start, missing_end,
last_seq, *blacklist_seq - 1,
- buf1, buf2);
+ buf1.buf, buf2.buf);
+
+ printbuf_exit(&buf1);
+ printbuf_exit(&buf2);
}
seq++;
.e.nr_required = 1,
};
unsigned ptr;
- char buf[80];
if (i->ignore)
continue;
ret = jset_validate_entries(c, &i->j, READ);
if (ret)
- goto fsck_err;
+ goto err;
for (ptr = 0; ptr < i->nr_ptrs; ptr++)
replicas.e.devs[replicas.e.nr_devs++] = i->ptrs[ptr].dev;
* the devices - this is wrong:
*/
+ printbuf_reset(&buf);
+ bch2_replicas_entry_to_text(&buf, &replicas.e);
+
if (!degraded &&
(test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) ||
fsck_err_on(!bch2_replicas_marked(c, &replicas.e), c,
"superblock not marked as containing replicas %s",
- (bch2_replicas_entry_to_text(&PBUF(buf),
- &replicas.e), buf)))) {
+ buf.buf))) {
ret = bch2_mark_replicas(c, &replicas.e);
if (ret)
- return ret;
+ goto err;
}
for_each_jset_key(k, _n, entry, &i->j)
if (*start_seq != *blacklist_seq)
bch_info(c, "dropped unflushed entries %llu-%llu",
*blacklist_seq, *start_seq - 1);
+err:
fsck_err:
+ printbuf_exit(&buf);
return ret;
}
struct jset_entry *start, *end;
struct jset *jset;
struct bio *bio;
- char *journal_debug_buf = NULL;
+ struct printbuf journal_debug_buf = PRINTBUF;
bool validate_before_checksum = false;
unsigned i, sectors, bytes, u64s, nr_rw_members = 0;
int ret;
goto retry_alloc;
}
- if (ret) {
- journal_debug_buf = kmalloc(4096, GFP_ATOMIC);
- if (journal_debug_buf)
- __bch2_journal_debug_to_text(&_PBUF(journal_debug_buf, 4096), j);
- }
+ if (ret)
+ __bch2_journal_debug_to_text(&journal_debug_buf, j);
/*
* write is allocated, no longer need to account for it in
if (ret) {
bch_err(c, "Unable to allocate journal write:\n%s",
- journal_debug_buf);
- kfree(journal_debug_buf);
+ journal_debug_buf.buf);
+ printbuf_exit(&journal_debug_buf);
bch2_fatal_error(c);
continue_at(cl, journal_write_done, c->io_complete_wq);
return;
if (!clean_ondisk &&
j->reservations.idx ==
j->reservations.unwritten_idx) {
- char *buf = kmalloc(4096, GFP_ATOMIC);
+ struct printbuf buf = PRINTBUF;
- bch_err(c, "journal stuck");
- if (buf) {
- __bch2_journal_debug_to_text(&_PBUF(buf, 4096), j);
- pr_err("\n%s", buf);
- kfree(buf);
- }
+ __bch2_journal_debug_to_text(&buf, j);
+ bch_err(c, "journal stuck\n%s", buf.buf);
+ printbuf_exit(&buf);
bch2_fatal_error(c);
ret = cur_entry_journal_stuck;
{
struct bch_fs_rebalance *r = &c->rebalance;
struct rebalance_work w = rebalance_work(c);
- char h1[21], h2[21];
- bch2_hprint(&PBUF(h1), w.dev_most_full_work << 9);
- bch2_hprint(&PBUF(h2), w.dev_most_full_capacity << 9);
- pr_buf(out, "fullest_dev (%i):\t%s/%s\n",
- w.dev_most_full_idx, h1, h2);
+ out->tabstops[0] = 20;
- bch2_hprint(&PBUF(h1), w.total_work << 9);
- bch2_hprint(&PBUF(h2), c->capacity << 9);
- pr_buf(out, "total work:\t\t%s/%s\n", h1, h2);
+ pr_buf(out, "fullest_dev (%i):", w.dev_most_full_idx);
+ pr_tab(out);
- pr_buf(out, "rate:\t\t\t%u\n", r->pd.rate.rate);
+ bch2_hprint(out, w.dev_most_full_work << 9);
+ pr_buf(out, "/");
+ bch2_hprint(out, w.dev_most_full_capacity << 9);
+ pr_newline(out);
+
+ pr_buf(out, "total work:");
+ pr_tab(out);
+
+ bch2_hprint(out, w.total_work << 9);
+ pr_buf(out, "/");
+ bch2_hprint(out, c->capacity << 9);
+ pr_newline(out);
+
+ pr_buf(out, "rate:");
+ pr_tab(out);
+ pr_buf(out, "%u", r->pd.rate.rate);
+ pr_newline(out);
switch (r->state) {
case REBALANCE_WAITING:
- pr_buf(out, "waiting\n");
+ pr_buf(out, "waiting");
break;
case REBALANCE_THROTTLED:
- bch2_hprint(&PBUF(h1),
+ pr_buf(out, "throttled for %lu sec or ",
+ (r->throttled_until_cputime - jiffies) / HZ);
+ bch2_hprint(out,
(r->throttled_until_iotime -
atomic64_read(&c->io_clock[WRITE].now)) << 9);
- pr_buf(out, "throttled for %lu sec or %s io\n",
- (r->throttled_until_cputime - jiffies) / HZ,
- h1);
+ pr_buf(out, " io");
break;
case REBALANCE_RUNNING:
- pr_buf(out, "running\n");
+ pr_buf(out, "running");
break;
}
+ pr_newline(out);
}
void bch2_rebalance_stop(struct bch_fs *c)
{
unsigned i;
struct bch_sb_field_clean *clean = *cleanp;
+ struct printbuf buf1 = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
int ret = 0;
if (mustfix_fsck_err_on(j->seq != clean->journal_seq, c,
}
for (i = 0; i < BTREE_ID_NR; i++) {
- char buf1[200], buf2[200];
struct bkey_i *k1, *k2;
unsigned l1 = 0, l2 = 0;
if (!k1 && !k2)
continue;
+ printbuf_reset(&buf1);
+ printbuf_reset(&buf2);
+
+ if (k1)
+ bch2_bkey_val_to_text(&buf1, c, bkey_i_to_s_c(k1));
+ else
+ pr_buf(&buf1, "(none)");
+
+ if (k2)
+ bch2_bkey_val_to_text(&buf2, c, bkey_i_to_s_c(k2));
+ else
+ pr_buf(&buf2, "(none)");
+
mustfix_fsck_err_on(!k1 || !k2 ||
IS_ERR(k1) ||
IS_ERR(k2) ||
"superblock btree root %u doesn't match journal after clean shutdown\n"
"sb: l=%u %s\n"
"journal: l=%u %s\n", i,
- l1, (bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(k1)), buf1),
- l2, (bch2_bkey_val_to_text(&PBUF(buf2), c, bkey_i_to_s_c(k2)), buf2));
+ l1, buf1.buf,
+ l2, buf2.buf);
}
fsck_err:
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf1);
return ret;
}
if (dflags & ~flags) {
if (print) {
- char buf[100];
+ struct printbuf buf = PRINTBUF;
- bch2_replicas_entry_to_text(&PBUF(buf), e);
+ bch2_replicas_entry_to_text(&buf, e);
bch_err(c, "insufficient devices online (%u) for replicas entry %s",
- nr_online, buf);
+ nr_online, buf.buf);
+ printbuf_exit(&buf);
}
ret = false;
break;
{
u64 offset = opt_get(*opts, sb);
struct bch_sb_layout layout;
- char *_err;
- struct printbuf err;
+ struct printbuf err = PRINTBUF;
__le64 *i;
int ret;
- _err = kmalloc(4096, GFP_KERNEL);
- if (!_err)
- return -ENOMEM;
- err = _PBUF(_err, 4096);
-
pr_verbose_init(*opts, "");
memset(sb, 0, sizeof(*sb));
goto err;
printk(KERN_ERR "bcachefs (%s): error reading default superblock: %s",
- path, _err);
- err = _PBUF(_err, 4096);
+ path, err.buf);
+ printbuf_reset(&err);
/*
* Error reading primary superblock - read location of backup
ret = bch2_sb_validate(sb, &err);
if (ret) {
printk(KERN_ERR "bcachefs (%s): error validating superblock: %s",
- path, _err);
+ path, err.buf);
goto err_no_print;
}
out:
pr_verbose_init(*opts, "ret %i", ret);
- kfree(_err);
+ printbuf_exit(&err);
return ret;
err:
printk(KERN_ERR "bcachefs (%s): error reading superblock: %s",
- path, _err);
+ path, err.buf);
err_no_print:
bch2_free_super(sb);
goto out;
{
struct closure *cl = &c->sb_write;
struct bch_dev *ca;
+ struct printbuf err = PRINTBUF;
unsigned i, sb = 0, nr_wrote;
struct bch_devs_mask sb_written;
bool wrote, can_mount_without_written, can_mount_with_written;
bch2_sb_from_fs(c, ca);
for_each_online_member(ca, c, i) {
- struct printbuf buf = { NULL, NULL };
+ printbuf_reset(&err);
- ret = bch2_sb_validate(&ca->disk_sb, &buf);
+ ret = bch2_sb_validate(&ca->disk_sb, &err);
if (ret) {
- char *_buf = kmalloc(4096, GFP_NOFS);
- if (_buf) {
- buf = _PBUF(_buf, 4096);
- bch2_sb_validate(&ca->disk_sb, &buf);
- }
-
- bch2_fs_inconsistent(c, "sb invalid before write: %s", _buf);
- kfree(_buf);
+ bch2_fs_inconsistent(c, "sb invalid before write: %s", err.buf);
percpu_ref_put(&ca->io_ref);
goto out;
}
out:
/* Make new options visible after they're persistent: */
bch2_sb_update(c);
+ printbuf_exit(&err);
return ret;
}
static void print_mount_opts(struct bch_fs *c)
{
enum bch_opt_id i;
- char buf[512];
- struct printbuf p = PBUF(buf);
+ struct printbuf p = PRINTBUF;
bool first = true;
- strcpy(buf, "(null)");
-
if (c->opts.read_only) {
pr_buf(&p, "ro");
first = false;
bch2_opt_to_text(&p, c, opt, v, OPT_SHOW_MOUNT_STYLE);
}
- bch_info(c, "mounted with opts: %s", buf);
+ if (!p.pos)
+ pr_buf(&p, "(null)");
+
+ bch_info(c, "mounted with opts: %s", p.buf);
+ printbuf_exit(&p);
}
int bch2_fs_start(struct bch_fs *c)
data = bch2_dev_has_data(c, ca);
if (data) {
- char data_has_str[100];
+ struct printbuf data_has = PRINTBUF;
- bch2_flags_to_text(&PBUF(data_has_str),
- bch2_data_types, data);
- bch_err(ca, "Remove failed, still has data (%s)", data_has_str);
+ bch2_flags_to_text(&data_has, bch2_data_types, data);
+ bch_err(ca, "Remove failed, still has data (%s)", data_has.buf);
+ printbuf_exit(&data_has);
ret = -EBUSY;
goto err;
}
struct bch_sb_field_members *mi;
struct bch_member dev_mi;
unsigned dev_idx, nr_devices, u64s;
- char *_errbuf;
- struct printbuf errbuf;
+ struct printbuf errbuf = PRINTBUF;
int ret;
- _errbuf = kmalloc(4096, GFP_KERNEL);
- if (!_errbuf)
- return -ENOMEM;
-
- errbuf = _PBUF(_errbuf, 4096);
-
ret = bch2_read_super(path, &opts, &sb);
if (ret) {
bch_err(c, "device add error: error reading super: %i", ret);
if (ca)
bch2_dev_free(ca);
bch2_free_super(&sb);
- kfree(_errbuf);
+ printbuf_exit(&errbuf);
return ret;
err_late:
up_write(&c->state_lock);
struct bch_sb_field_members *mi;
unsigned i, best_sb = 0;
const char *err;
- char *_errbuf = NULL;
- struct printbuf errbuf;
+ struct printbuf errbuf = PRINTBUF;
int ret = 0;
if (!try_module_get(THIS_MODULE))
goto err;
}
- _errbuf = kmalloc(4096, GFP_KERNEL);
- if (!_errbuf) {
- ret = -ENOMEM;
- goto err;
- }
-
- errbuf = _PBUF(_errbuf, 4096);
-
sb = kcalloc(nr_devices, sizeof(*sb), GFP_KERNEL);
if (!sb) {
ret = -ENOMEM;
}
out:
kfree(sb);
- kfree(_errbuf);
+ printbuf_exit(&errbuf);
module_put(THIS_MODULE);
pr_verbose_init(opts, "ret %i", PTR_ERR_OR_ZERO(c));
return c;
}
#define SHOW(fn) \
+static ssize_t fn ## _to_text(struct printbuf *, \
+ struct kobject *, struct attribute *);\
+ \
static ssize_t fn ## _show(struct kobject *kobj, struct attribute *attr,\
char *buf) \
+{ \
+ struct printbuf out = PRINTBUF; \
+ ssize_t ret = fn ## _to_text(&out, kobj, attr); \
+ \
+ if (!ret && out.allocation_failure) \
+ ret = -ENOMEM; \
+ \
+ if (!ret) { \
+ ret = min_t(size_t, out.pos, PAGE_SIZE - 1); \
+ memcpy(buf, out.buf, ret); \
+ } \
+ printbuf_exit(&out); \
+ return ret; \
+} \
+ \
+static ssize_t fn ## _to_text(struct printbuf *out, struct kobject *kobj,\
+ struct attribute *attr)
#define STORE(fn) \
static ssize_t fn ## _store(struct kobject *kobj, struct attribute *attr,\
#define sysfs_printf(file, fmt, ...) \
do { \
if (attr == &sysfs_ ## file) \
- return scnprintf(buf, PAGE_SIZE, fmt "\n", __VA_ARGS__);\
+ pr_buf(out, fmt "\n", __VA_ARGS__); \
} while (0)
#define sysfs_print(file, var) \
do { \
if (attr == &sysfs_ ## file) \
- return snprint(buf, PAGE_SIZE, var); \
+ snprint(out, var); \
} while (0)
#define sysfs_hprint(file, val) \
do { \
- if (attr == &sysfs_ ## file) { \
- bch2_hprint(&out, val); \
- pr_buf(&out, "\n"); \
- return out.pos - buf; \
- } \
+ if (attr == &sysfs_ ## file) \
+ bch2_hprint(out, val); \
} while (0)
#define var_printf(_var, fmt) sysfs_printf(_var, fmt, var(_var))
SHOW(bch2_fs)
{
struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
- struct printbuf out = _PBUF(buf, PAGE_SIZE);
sysfs_print(minor, c->minor);
sysfs_printf(internal_uuid, "%pU", c->sb.uuid.b);
sysfs_printf(btree_gc_periodic, "%u", (int) c->btree_gc_periodic);
- if (attr == &sysfs_gc_gens_pos) {
- bch2_gc_gens_pos_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_gc_gens_pos)
+ bch2_gc_gens_pos_to_text(out, c);
sysfs_printf(copy_gc_enabled, "%i", c->copy_gc_enabled);
max(0LL, c->copygc_wait -
atomic64_read(&c->io_clock[WRITE].now)) << 9);
- if (attr == &sysfs_rebalance_work) {
- bch2_rebalance_work_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_rebalance_work)
+ bch2_rebalance_work_to_text(out, c);
sysfs_print(promote_whole_extents, c->promote_whole_extents);
/* Debugging: */
- if (attr == &sysfs_journal_debug) {
- bch2_journal_debug_to_text(&out, &c->journal);
- return out.pos - buf;
- }
+ if (attr == &sysfs_journal_debug)
+ bch2_journal_debug_to_text(out, &c->journal);
- if (attr == &sysfs_journal_pins) {
- bch2_journal_pins_to_text(&out, &c->journal);
- return out.pos - buf;
- }
+ if (attr == &sysfs_journal_pins)
+ bch2_journal_pins_to_text(out, &c->journal);
- if (attr == &sysfs_btree_updates) {
- bch2_btree_updates_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_btree_updates)
+ bch2_btree_updates_to_text(out, c);
- if (attr == &sysfs_dirty_btree_nodes) {
- bch2_dirty_btree_nodes_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_dirty_btree_nodes)
+ bch2_dirty_btree_nodes_to_text(out, c);
- if (attr == &sysfs_btree_cache) {
- bch2_btree_cache_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_btree_cache)
+ bch2_btree_cache_to_text(out, c);
- if (attr == &sysfs_btree_key_cache) {
- bch2_btree_key_cache_to_text(&out, &c->btree_key_cache);
- return out.pos - buf;
- }
+ if (attr == &sysfs_btree_key_cache)
+ bch2_btree_key_cache_to_text(out, &c->btree_key_cache);
- if (attr == &sysfs_btree_transactions) {
- bch2_btree_trans_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_btree_transactions)
+ bch2_btree_trans_to_text(out, c);
- if (attr == &sysfs_stripes_heap) {
- bch2_stripes_heap_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_stripes_heap)
+ bch2_stripes_heap_to_text(out, c);
- if (attr == &sysfs_open_buckets) {
- bch2_open_buckets_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_open_buckets)
+ bch2_open_buckets_to_text(out, c);
- if (attr == &sysfs_compression_stats) {
- bch2_compression_stats_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_compression_stats)
+ bch2_compression_stats_to_text(out, c);
- if (attr == &sysfs_new_stripes) {
- bch2_new_stripes_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_new_stripes)
+ bch2_new_stripes_to_text(out, c);
- if (attr == &sysfs_io_timers_read) {
- bch2_io_timers_to_text(&out, &c->io_clock[READ]);
- return out.pos - buf;
- }
- if (attr == &sysfs_io_timers_write) {
- bch2_io_timers_to_text(&out, &c->io_clock[WRITE]);
- return out.pos - buf;
- }
+ if (attr == &sysfs_io_timers_read)
+ bch2_io_timers_to_text(out, &c->io_clock[READ]);
- if (attr == &sysfs_data_jobs) {
- data_progress_to_text(&out, c);
- return out.pos - buf;
- }
+ if (attr == &sysfs_io_timers_write)
+ bch2_io_timers_to_text(out, &c->io_clock[WRITE]);
+
+ if (attr == &sysfs_data_jobs)
+ data_progress_to_text(out, c);
return 0;
}
SHOW(bch2_fs_internal)
{
struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
- return bch2_fs_show(&c->kobj, attr, buf);
+ return bch2_fs_to_text(out, &c->kobj, attr);
}
STORE(bch2_fs_internal)
SHOW(bch2_fs_opts_dir)
{
- 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);
- bch2_opt_to_text(&out, c, opt, v, OPT_SHOW_FULL_LIST);
- pr_buf(&out, "\n");
+ bch2_opt_to_text(out, c, opt, v, OPT_SHOW_FULL_LIST);
+ pr_char(out, '\n');
- return out.pos - buf;
+ return 0;
}
STORE(bch2_fs_opts_dir)
SHOW(bch2_fs_time_stats)
{
struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
- struct printbuf out = _PBUF(buf, PAGE_SIZE);
#define x(name) \
- if (attr == &sysfs_time_stat_##name) { \
- bch2_time_stats_to_text(&out, &c->times[BCH_TIME_##name]);\
- return out.pos - buf; \
- }
+ if (attr == &sysfs_time_stat_##name) \
+ bch2_time_stats_to_text(out, &c->times[BCH_TIME_##name]);
BCH_TIME_STATS()
#undef x
{
struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
struct bch_fs *c = ca->fs;
- struct printbuf out = _PBUF(buf, PAGE_SIZE);
sysfs_printf(uuid, "%pU\n", ca->uuid.b);
if (attr == &sysfs_label) {
if (ca->mi.group) {
mutex_lock(&c->sb_lock);
- bch2_disk_path_to_text(&out, c->disk_sb.sb,
+ bch2_disk_path_to_text(out, c->disk_sb.sb,
ca->mi.group - 1);
mutex_unlock(&c->sb_lock);
}
- pr_buf(&out, "\n");
- return out.pos - buf;
+ pr_char(out, '\n');
}
if (attr == &sysfs_has_data) {
- bch2_flags_to_text(&out, bch2_data_types,
+ bch2_flags_to_text(out, bch2_data_types,
bch2_dev_has_data(c, ca));
- pr_buf(&out, "\n");
- return out.pos - buf;
+ pr_char(out, '\n');
}
if (attr == &sysfs_state_rw) {
- bch2_string_opt_to_text(&out, bch2_member_states,
+ bch2_string_opt_to_text(out, bch2_member_states,
ca->mi.state);
- pr_buf(&out, "\n");
- return out.pos - buf;
+ pr_char(out, '\n');
}
- if (attr == &sysfs_iodone) {
- dev_iodone_to_text(&out, ca);
- return out.pos - buf;
- }
+ if (attr == &sysfs_iodone)
+ dev_iodone_to_text(out, ca);
sysfs_print(io_latency_read, atomic64_read(&ca->cur_latency[READ]));
sysfs_print(io_latency_write, atomic64_read(&ca->cur_latency[WRITE]));
- if (attr == &sysfs_io_latency_stats_read) {
- bch2_time_stats_to_text(&out, &ca->io_latency[READ]);
- return out.pos - buf;
- }
- if (attr == &sysfs_io_latency_stats_write) {
- bch2_time_stats_to_text(&out, &ca->io_latency[WRITE]);
- return out.pos - buf;
- }
+ if (attr == &sysfs_io_latency_stats_read)
+ bch2_time_stats_to_text(out, &ca->io_latency[READ]);
+
+ if (attr == &sysfs_io_latency_stats_write)
+ bch2_time_stats_to_text(out, &ca->io_latency[WRITE]);
sysfs_printf(congested, "%u%%",
clamp(atomic_read(&ca->congested), 0, CONGESTED_MAX)
* 100 / CONGESTED_MAX);
- if (attr == &sysfs_reserve_stats) {
- reserve_stats_to_text(&out, ca);
- return out.pos - buf;
- }
- if (attr == &sysfs_alloc_debug) {
- dev_alloc_debug_to_text(&out, ca);
- return out.pos - buf;
- }
+ if (attr == &sysfs_reserve_stats)
+ reserve_stats_to_text(out, ca);
+
+ if (attr == &sysfs_alloc_debug)
+ dev_alloc_debug_to_text(out, ca);
return 0;
}
u64 nr, unsigned nr_threads)
{
struct test_job j = { .c = c, .nr = nr, .nr_threads = nr_threads };
- char name_buf[20], nr_buf[20], per_sec_buf[20];
+ char name_buf[20];
+ struct printbuf nr_buf = PRINTBUF;
+ struct printbuf per_sec_buf = PRINTBUF;
unsigned i;
u64 time;
time = j.finish - j.start;
scnprintf(name_buf, sizeof(name_buf), "%s:", testname);
- bch2_hprint(&PBUF(nr_buf), nr);
- bch2_hprint(&PBUF(per_sec_buf), div64_u64(nr * NSEC_PER_SEC, time));
+ bch2_hprint(&nr_buf, nr);
+ bch2_hprint(&per_sec_buf, div64_u64(nr * NSEC_PER_SEC, time));
printk(KERN_INFO "%-12s %s with %u threads in %5llu sec, %5llu nsec per iter, %5s per sec\n",
- name_buf, nr_buf, nr_threads,
+ name_buf, nr_buf.buf, nr_threads,
div_u64(time, NSEC_PER_SEC),
div_u64(time * nr_threads, nr),
- per_sec_buf);
+ per_sec_buf.buf);
+ printbuf_exit(&per_sec_buf);
+ printbuf_exit(&nr_buf);
return j.ret;
}
STRTO_H(strtoull, unsigned long long)
STRTO_H(strtou64, u64)
+static int bch2_printbuf_realloc(struct printbuf *out, unsigned extra)
+{
+ unsigned new_size = roundup_pow_of_two(out->size + extra);
+ char *buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_ATOMIC);
+
+ if (!buf) {
+ out->allocation_failure = true;
+ return -ENOMEM;
+ }
+
+ out->buf = buf;
+ out->size = new_size;
+ return 0;
+}
+
+void bch2_pr_buf(struct printbuf *out, const char *fmt, ...)
+{
+ va_list args;
+ int len;
+
+ do {
+ va_start(args, fmt);
+ len = vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, args);
+ va_end(args);
+ } while (len + 1 >= printbuf_remaining(out) &&
+ !bch2_printbuf_realloc(out, len + 1));
+
+ len = min_t(size_t, len,
+ printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0);
+ out->pos += len;
+}
+
void bch2_hprint(struct printbuf *buf, s64 v)
{
int u, t = 0;
unsigned bit, nr = 0;
bool first = true;
- if (out->pos != out->end)
- *out->pos = '\0';
-
while (list[nr])
nr++;
};
struct printbuf {
- char *pos;
- char *end;
- char *last_newline;
- char *last_field;
+ char *buf;
+ unsigned size;
+ unsigned pos;
+ unsigned last_newline;
+ unsigned last_field;
unsigned indent;
- enum printbuf_units units;
- unsigned tabstop;
- unsigned tabstops[4];
+ enum printbuf_units units:8;
+ u8 atomic;
+ bool allocation_failure:1;
+ u8 tabstop;
+ u8 tabstops[4];
};
+#define PRINTBUF ((struct printbuf) { NULL })
+
+static inline void printbuf_exit(struct printbuf *buf)
+{
+ kfree(buf->buf);
+ buf->buf = ERR_PTR(-EINTR); /* poison value */
+}
+
+static inline void printbuf_reset(struct printbuf *buf)
+{
+ buf->pos = 0;
+ buf->last_newline = 0;
+ buf->last_field = 0;
+ buf->indent = 0;
+ buf->tabstop = 0;
+}
+
static inline size_t printbuf_remaining(struct printbuf *buf)
{
- return buf->end - buf->pos;
+ return buf->size - buf->pos;
}
static inline size_t printbuf_linelen(struct printbuf *buf)
return buf->pos - buf->last_newline;
}
-#define _PBUF(_buf, _len) \
- ((struct printbuf) { \
- .pos = _buf, \
- .end = _buf + _len, \
- .last_newline = _buf, \
- .last_field = _buf, \
- })
+void bch2_pr_buf(struct printbuf *out, const char *fmt, ...);
-#define PBUF(_buf) _PBUF(_buf, sizeof(_buf))
-
-
-#define pr_buf(_out, ...) \
-do { \
- (_out)->pos += scnprintf((_out)->pos, printbuf_remaining(_out), \
- __VA_ARGS__); \
-} while (0)
+#define pr_buf(_out, ...) bch2_pr_buf(_out, __VA_ARGS__)
static inline void pr_char(struct printbuf *out, char c)
{
- if (printbuf_remaining(out) > 1) {
- *out->pos = c;
- out->pos++;
- }
+ bch2_pr_buf(out, "%c", c);
}
static inline void pr_indent_push(struct printbuf *buf, unsigned spaces)
{
if (buf->last_newline + buf->indent == buf->pos) {
buf->pos -= spaces;
- buf->pos = '\0';
+ buf->buf[buf->pos] = '\0';
}
buf->indent -= spaces;
}
BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops));
if (shift > 0) {
- memmove(buf->last_field + shift,
- buf->last_field,
+ memmove(buf->buf + buf->last_field + shift,
+ buf->buf + buf->last_field,
move);
- memset(buf->last_field, ' ', shift);
+ memset(buf->buf + buf->last_field, ' ', shift);
buf->pos += shift;
- *buf->pos = 0;
+ buf->buf[buf->pos] = 0;
}
buf->last_field = buf->pos;
_r; \
})
-#define snprint(buf, size, var) \
- snprintf(buf, size, \
+#define snprint(out, var) \
+ pr_buf(out, \
type_is(var, int) ? "%i\n" \
: type_is(var, unsigned) ? "%u\n" \
: type_is(var, long) ? "%li\n" \
sysfs_print(name##_rate_d_term, (var)->d_term); \
sysfs_print(name##_rate_p_term_inverse, (var)->p_term_inverse); \
\
- if (attr == &sysfs_##name##_rate_debug) { \
- bch2_pd_controller_debug_to_text(&out, var); \
- return out.pos - buf; \
- } \
+ if (attr == &sysfs_##name##_rate_debug) \
+ bch2_pd_controller_debug_to_text(out, var); \
} while (0)
#define sysfs_pd_controller_store(name, var) \
bch2_inode_opts_to_opts(bch2_inode_opts_get(&inode->ei_inode));
const struct bch_option *opt;
int id, inode_opt_id;
- char buf[512];
- struct printbuf out = PBUF(buf);
- unsigned val_len;
+ struct printbuf out = PRINTBUF;
+ int ret;
u64 v;
id = bch2_opt_lookup(name);
v = bch2_opt_get_by_id(&opts, id);
bch2_opt_to_text(&out, c, opt, v, 0);
- val_len = out.pos - buf;
+ ret = out.pos;
- if (buffer && val_len > size)
- return -ERANGE;
+ if (out.allocation_failure) {
+ ret = -ENOMEM;
+ } else if (buffer) {
+ if (out.pos > size)
+ ret = -ERANGE;
+ else
+ memcpy(buffer, out.buf, out.pos);
+ }
- if (buffer)
- memcpy(buffer, buf, val_len);
- return val_len;
+ printbuf_exit(&out);
+ return ret;
}
static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler,