From a9a46467e618c5f040107cd87ebe7afa7863bc3c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 24 Aug 2020 16:26:22 -0400 Subject: [PATCH] Assorted debug and fsck improvements This adds a new list mode to "bcachefs list", for printing out nodes as they exist on disk (before being merge sorted). Also some improvements to fsck return values. Signed-off-by: Kent Overstreet --- cmd_debug.c | 125 ++++++++++++++++++++++++++++++++ cmd_fsck.c | 31 +++++--- libbcachefs.c | 16 +++- mount/src/libbcachefs_wrapper.h | 8 +- tools-util.c | 8 +- tools-util.h | 2 +- 6 files changed, 172 insertions(+), 18 deletions(-) diff --git a/cmd_debug.c b/cmd_debug.c index aa06e8c5..46164476 100644 --- a/cmd_debug.c +++ b/cmd_debug.c @@ -11,8 +11,10 @@ #include "libbcachefs/bcachefs.h" #include "libbcachefs/bset.h" #include "libbcachefs/btree_cache.h" +#include "libbcachefs/btree_io.h" #include "libbcachefs/btree_iter.h" #include "libbcachefs/buckets.h" +#include "libbcachefs/checksum.h" #include "libbcachefs/error.h" #include "libbcachefs/journal.h" #include "libbcachefs/journal_io.h" @@ -237,6 +239,125 @@ static void list_nodes(struct bch_fs *c, enum btree_id btree_id, bch2_trans_exit(&trans); } +static void print_node_ondisk(struct bch_fs *c, struct btree *b) +{ + struct btree_node *n_ondisk; + struct extent_ptr_decoded pick; + struct bch_dev *ca; + struct bio *bio; + unsigned offset = 0; + + if (bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key), NULL, &pick) <= 0) { + printf("error getting device to read from\n"); + return; + } + + ca = bch_dev_bkey_exists(c, pick.ptr.dev); + if (!bch2_dev_get_ioref(ca, READ)) { + printf("error getting device to read from\n"); + return; + } + + n_ondisk = malloc(btree_bytes(c)); + + bio = bio_alloc_bioset(GFP_NOIO, + buf_pages(n_ondisk, btree_bytes(c)), + &c->btree_bio); + bio_set_dev(bio, ca->disk_sb.bdev); + bio->bi_opf = REQ_OP_READ|REQ_META; + bio->bi_iter.bi_sector = pick.ptr.offset; + bch2_bio_map(bio, n_ondisk, btree_bytes(c)); + + submit_bio_wait(bio); + + bio_put(bio); + percpu_ref_put(&ca->io_ref); + + while (offset < c->opts.btree_node_size) { + 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))) + die("unknown checksum type"); + + 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)) + die("invalid checksum\n"); + + 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))) + die("unknown checksum type"); + + nonce = btree_nonce(i, offset << 9); + csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, bne); + + if (bch2_crc_cmp(csum, bne->csum)) + die("invalid checksum"); + + bset_encrypt(c, i, offset << 9); + + sectors = vstruct_sectors(bne, c->block_bits); + } + + fprintf(stdout, " offset %u journal seq %llu\n", + offset, le64_to_cpu(i->journal_seq)); + offset += sectors; + + for (k = i->start; + k != vstruct_last(i); + k = bkey_next_skip_noops(k, vstruct_last(i))) { + struct bkey u; + char buf[4096]; + + bch2_bkey_val_to_text(&PBUF(buf), c, bkey_disassemble(b, k, &u)); + fprintf(stdout, " %s\n", buf); + } + } + + free(n_ondisk); +} + +static void list_nodes_ondisk(struct bch_fs *c, enum btree_id btree_id, + struct bpos start, struct bpos end) +{ + struct btree_trans trans; + struct btree_iter *iter; + struct btree *b; + char buf[4096]; + + bch2_trans_init(&trans, c, 0, 0); + + for_each_btree_node(&trans, iter, btree_id, start, 0, b) { + if (bkey_cmp(b->key.k.p, end) > 0) + break; + + bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(&b->key)); + fputs(buf, stdout); + putchar('\n'); + + print_node_ondisk(c, b); + } + bch2_trans_exit(&trans); +} + static void list_nodes_keys(struct bch_fs *c, enum btree_id btree_id, struct bpos start, struct bpos end) { @@ -306,6 +427,7 @@ static const char * const list_modes[] = { "keys", "formats", "nodes", + "nodes_ondisk", "nodes_keys", NULL }; @@ -383,6 +505,9 @@ int cmd_list(int argc, char *argv[]) list_nodes(c, btree_id, start, end); break; case 3: + list_nodes_ondisk(c, btree_id, start, end); + break; + case 4: list_nodes_keys(c, btree_id, start, end); break; default: diff --git a/cmd_fsck.c b/cmd_fsck.c index 736a4ca5..5756ee76 100644 --- a/cmd_fsck.c +++ b/cmd_fsck.c @@ -67,25 +67,36 @@ int cmd_fsck(int argc, char *argv[]) break; case 'h': usage(); - exit(EXIT_SUCCESS); + exit(16); } args_shift(optind); - if (!argc) - die("Please supply device(s) to check"); + if (!argc) { + fprintf(stderr, "Please supply device(s) to check\n"); + exit(8); + } - for (i = 0; i < argc; i++) - if (dev_mounted_rw(argv[i])) - die("%s is mounted read-write - aborting", argv[i]); + for (i = 0; i < argc; i++) { + switch (dev_mounted(argv[i])) { + case 1: + ret |= 2; + break; + case 2: + fprintf(stderr, "%s is mounted read-write - aborting\n", argv[i]); + exit(8); + } + } struct bch_fs *c = bch2_fs_open(argv, argc, opts); - if (IS_ERR(c)) - die("error opening %s: %s", argv[0], strerror(-PTR_ERR(c))); + if (IS_ERR(c)) { + fprintf(stderr, "error opening %s: %s\n", argv[0], strerror(-PTR_ERR(c))); + exit(8); + } if (test_bit(BCH_FS_ERRORS_FIXED, &c->flags)) - ret = 2; + ret |= 1; if (test_bit(BCH_FS_ERROR, &c->flags)) - ret = 4; + ret |= 4; bch2_fs_stop(c); return ret; diff --git a/libbcachefs.c b/libbcachefs.c index 260e6c7a..7ff02b88 100644 --- a/libbcachefs.c +++ b/libbcachefs.c @@ -21,6 +21,7 @@ #include "libbcachefs/btree_cache.h" #include "libbcachefs/checksum.h" #include "libbcachefs/disk_groups.h" +#include "libbcachefs/journal_seq_blacklist.h" #include "libbcachefs/opts.h" #include "libbcachefs/replicas.h" #include "libbcachefs/super-io.h" @@ -623,6 +624,17 @@ static void bch2_sb_print_clean(struct bch_sb *sb, struct bch_sb_field *f, static void bch2_sb_print_journal_seq_blacklist(struct bch_sb *sb, struct bch_sb_field *f, enum units units) { + struct bch_sb_field_journal_seq_blacklist *bl = field_to_type(f, journal_seq_blacklist); + unsigned i, nr = blacklist_nr_entries(bl); + + for (i = 0; i < nr; i++) { + struct journal_seq_blacklist_entry *e = + bl->start + i; + + printf(" %llu-%llu\n", + le64_to_cpu(e->start), + le64_to_cpu(e->end)); + } } typedef void (*sb_field_print_fn)(struct bch_sb *, struct bch_sb_field *, enum units); @@ -1040,7 +1052,9 @@ struct bch_opts bch2_parse_opts(struct bch_opt_strs strs) ret = bch2_opt_parse(NULL, &bch2_opt_table[i], strs.by_id[i], &v); if (ret < 0) - die("Invalid %s: %s", strs.by_id[i], strerror(-ret)); + die("Invalid %s: %s", + bch2_opt_table[i].attr.name, + strerror(-ret)); bch2_opt_set_by_id(&opts, i, v); } diff --git a/mount/src/libbcachefs_wrapper.h b/mount/src/libbcachefs_wrapper.h index fd76a6c0..9d9754c1 100644 --- a/mount/src/libbcachefs_wrapper.h +++ b/mount/src/libbcachefs_wrapper.h @@ -1,4 +1,4 @@ -#include -#include -#include -#include +#include "../libbcachefs/super-io.h" +#include "../libbcachefs/checksum.h" +#include "../libbcachefs/bcachefs_format.h" +#include "../crypto.h" diff --git a/tools-util.c b/tools-util.c index 1a656ed1..88e923cb 100644 --- a/tools-util.c +++ b/tools-util.c @@ -653,9 +653,13 @@ found: return ret; } -bool dev_mounted_rw(char *dev) +int dev_mounted(char *dev) { struct mntent *mnt = dev_to_mount(dev); - return mnt && !hasmntopt(mnt, "ro"); + if (!mnt) + return 0; + if (hasmntopt(mnt, "ro")) + return 1; + return 2; } diff --git a/tools-util.h b/tools-util.h index e5c35084..d6814bcd 100644 --- a/tools-util.h +++ b/tools-util.h @@ -155,7 +155,7 @@ u32 crc32c(u32, const void *, size_t); char *dev_to_name(dev_t); char *dev_to_path(dev_t); struct mntent *dev_to_mount(char *); -bool dev_mounted_rw(char *); +int dev_mounted(char *); #define args_shift(_nr) \ do { \