diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-03-06 10:53:25 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:09:56 +0300 |
commit | b65499b7b16b99575f1e7921da402b3b59c47de6 (patch) | |
tree | e39a571ca69316adaa908a9b2b21050d288313d3 | |
parent | a345b0f393da49be9d1110ec9e43066191f0e466 (diff) | |
download | linux-b65499b7b16b99575f1e7921da402b3b59c47de6.tar.xz |
bcachefs: bch2_btree_node_ondisk_to_text()
Pulling out a helper from cmd_list.c, as the rest is being rewritten in
Rust but we're not ready to rewrite lower-level btree code in Rust.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/bkey.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/debug.c | 119 | ||||
-rw-r--r-- | fs/bcachefs/debug.h | 2 |
3 files changed, 123 insertions, 2 deletions
diff --git a/fs/bcachefs/bkey.h b/fs/bcachefs/bkey.h index dbe4873cad02..29f44d0060d8 100644 --- a/fs/bcachefs/bkey.h +++ b/fs/bcachefs/bkey.h @@ -505,7 +505,7 @@ static inline struct bpos bkey_unpack_pos(const struct btree *b, /* Disassembled bkeys */ -static inline struct bkey_s_c bkey_disassemble(struct btree *b, +static inline struct bkey_s_c bkey_disassemble(const struct btree *b, const struct bkey_packed *k, struct bkey *u) { @@ -515,7 +515,7 @@ static inline struct bkey_s_c bkey_disassemble(struct btree *b, } /* non const version: */ -static inline struct bkey_s __bkey_disassemble(struct btree *b, +static inline struct bkey_s __bkey_disassemble(const struct btree *b, struct bkey_packed *k, struct bkey *u) { diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c index 0035fe875a47..d1563caf7fb7 100644 --- a/fs/bcachefs/debug.c +++ b/fs/bcachefs/debug.c @@ -181,6 +181,125 @@ out: bch2_btree_node_io_unlock(b); } +void bch2_btree_node_ondisk_to_text(struct printbuf *out, struct bch_fs *c, + const struct btree *b) +{ + struct btree_node *n_ondisk = NULL; + struct extent_ptr_decoded pick; + struct bch_dev *ca; + struct bio *bio = NULL; + unsigned offset = 0; + int ret; + + if (bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key), NULL, &pick) <= 0) { + prt_printf(out, "error getting device to read from: invalid device\n"); + return; + } + + ca = bch_dev_bkey_exists(c, pick.ptr.dev); + if (!bch2_dev_get_ioref(ca, READ)) { + prt_printf(out, "error getting device to read from: not online\n"); + return; + } + + n_ondisk = kvpmalloc(btree_bytes(c), GFP_KERNEL); + if (!n_ondisk) { + prt_printf(out, "memory allocation failure\n"); + goto out; + } + + bio = bio_alloc_bioset(ca->disk_sb.bdev, + buf_pages(n_ondisk, btree_bytes(c)), + REQ_OP_READ|REQ_META, + GFP_NOIO, + &c->btree_bio); + bio->bi_iter.bi_sector = pick.ptr.offset; + bch2_bio_map(bio, n_ondisk, btree_bytes(c)); + + ret = submit_bio_wait(bio); + if (ret) { + prt_printf(out, "IO error reading btree node: %s\n", bch2_err_str(ret)); + goto out; + } + + while (offset < btree_sectors(c)) { + struct bset *i; + struct nonce nonce; + struct bch_csum csum; + struct bkey_packed *k; + unsigned sectors; + + if (!offset) { + i = &n_ondisk->keys; + + if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i))) { + prt_printf(out, "unknown checksum type at offset %u: %llu\n", + offset, BSET_CSUM_TYPE(i)); + goto out; + } + + nonce = btree_nonce(i, offset << 9); + csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, n_ondisk); + + if (bch2_crc_cmp(csum, n_ondisk->csum)) { + prt_printf(out, "invalid checksum\n"); + goto out; + } + + bset_encrypt(c, i, offset << 9); + + sectors = vstruct_sectors(n_ondisk, c->block_bits); + } else { + struct btree_node_entry *bne = (void *) n_ondisk + (offset << 9); + + i = &bne->keys; + + if (i->seq != n_ondisk->keys.seq) + break; + + if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i))) { + prt_printf(out, "unknown checksum type at offset %u: %llu\n", + offset, BSET_CSUM_TYPE(i)); + goto out; + } + + nonce = btree_nonce(i, offset << 9); + csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, bne); + + if (bch2_crc_cmp(csum, bne->csum)) { + prt_printf(out, "invalid checksum"); + goto out; + } + + bset_encrypt(c, i, offset << 9); + + sectors = vstruct_sectors(bne, c->block_bits); + } + + prt_printf(out, " offset %u version %u, journal seq %llu\n", + offset, + le16_to_cpu(i->version), + le64_to_cpu(i->journal_seq)); + offset += sectors; + + printbuf_indent_add(out, 4); + + for (k = i->start; k != vstruct_last(i); k = bkey_p_next(k)) { + struct bkey u; + + bch2_bkey_val_to_text(out, c, bkey_disassemble(b, k, &u)); + prt_newline(out); + } + + printbuf_indent_sub(out, 4); + } +out: + if (bio) + bio_put(bio); + kvpfree(n_ondisk, btree_bytes(c)); + percpu_ref_put(&ca->io_ref); +} + #ifdef CONFIG_DEBUG_FS /* XXX: bch_fs refcounting */ diff --git a/fs/bcachefs/debug.h b/fs/bcachefs/debug.h index 0b86736e5e1b..2c37143b5fd1 100644 --- a/fs/bcachefs/debug.h +++ b/fs/bcachefs/debug.h @@ -9,6 +9,8 @@ struct btree; struct bch_fs; void __bch2_btree_verify(struct bch_fs *, struct btree *); +void bch2_btree_node_ondisk_to_text(struct printbuf *, struct bch_fs *, + const struct btree *); static inline void bch2_btree_verify(struct bch_fs *c, struct btree *b) { |