diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-12 21:44:33 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-12 21:44:33 -0500 |
commit | 4697efb7a01affe650dbc9a4e81a8203d0316d96 (patch) | |
tree | 9f3c397dcf29fa2903f787609c3897568a9a52eb /cmd_list_journal.c | |
parent | e160e9b97986d908bce40ab40ee5d930453a3bf1 (diff) |
cmd_list_journal: Add filter options
Instead of having to use grep, this adds the ability to print out only
transactions that update a particular key, or to filter out entirely
keys except those updating certain btrees.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'cmd_list_journal.c')
-rw-r--r-- | cmd_list_journal.c | 239 |
1 files changed, 178 insertions, 61 deletions
diff --git a/cmd_list_journal.c b/cmd_list_journal.c index e89f7de9..ee467d43 100644 --- a/cmd_list_journal.c +++ b/cmd_list_journal.c @@ -1,4 +1,5 @@ #include <fcntl.h> +#include <getopt.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> @@ -21,10 +22,12 @@ static void list_journal_usage(void) "Usage: bcachefs list_journal [OPTION]... <devices>\n" "\n" "Options:\n" - " -a Read entire journal, not just dirty entries\n" - " -n Number of journal entries to print, starting from the most recent\n" - " -v Verbose mode\n" - " -h Display this help and exit\n" + " -a Read entire journal, not just dirty entries\n" + " -n, --nr-entries=nr Number of journal entries to print, starting from the most recent\n" + " -t, --transaction-filter=bbpos Filter transactions not updating <bbpos>\n" + " -k, --key-filter=btree Filter keys not updating btree\n" + " -v, --verbose Verbose mode\n" + " -h, --help Display this help and exit\n" "Report bugs to <linux-bcachefs@vger.kernel.org>"); } @@ -39,48 +42,83 @@ static void star_start_of_lines(char *buf) p[1] = '*'; } -int cmd_list_journal(int argc, char *argv[]) +static inline bool entry_is_transaction_start(struct jset_entry *entry) { - struct bch_opts opts = bch2_opts_empty(); - u32 nr_entries = U32_MAX; - int opt; + return entry->type == BCH_JSET_ENTRY_log && !entry->level; +} - opt_set(opts, nochanges, true); - opt_set(opts, norecovery, true); - opt_set(opts, degraded, true); - opt_set(opts, errors, BCH_ON_ERROR_continue); - opt_set(opts, fix_errors, FSCK_OPT_YES); - opt_set(opts, keep_journal, true); - opt_set(opts, read_journal_only,true); +typedef DARRAY(struct bbpos) d_bbpos; +typedef DARRAY(enum btree_id) d_btree_id; - while ((opt = getopt(argc, argv, "an:vh")) != -1) - switch (opt) { - case 'a': - opt_set(opts, read_entire_journal, true); - break; - case 'n': - nr_entries = kstrtouint(optarg, 10, &nr_entries); - opt_set(opts, read_entire_journal, true); - break; - case 'v': - opt_set(opts, verbose, true); - break; - case 'h': - list_journal_usage(); - exit(EXIT_SUCCESS); +static bool bkey_matches_filter(d_bbpos filter, struct jset_entry *entry, struct bkey_i *k) +{ + struct bbpos *i; + + darray_for_each(filter, i) { + if (i->btree != entry->btree_id) + continue; + + if (!btree_node_type_is_extents(i->btree)) { + if (bkey_eq(i->pos, k->k.p)) + return true; + } else { + if (bkey_ge(i->pos, bkey_start_pos(&k->k)) && + bkey_lt(i->pos, k->k.p)) + return true; } - args_shift(optind); + } + return false; +} - if (!argc) - die("Please supply device(s) to open"); +static bool should_print_transaction(struct jset_entry *entry, struct jset_entry *end, + d_bbpos filter) +{ + if (!filter.nr) + return true; - struct bch_fs *c = bch2_fs_open(argv, argc, opts); - if (IS_ERR(c)) - die("error opening %s: %s", argv[0], bch2_err_str(PTR_ERR(c))); + for (entry = vstruct_next(entry); + entry != end && !entry_is_transaction_start(entry); + entry = vstruct_next(entry)) { + if (entry->type == BCH_JSET_ENTRY_btree_root || + entry->type == BCH_JSET_ENTRY_btree_keys) { + struct bkey_i *k; + + vstruct_for_each(entry, k) + if (bkey_matches_filter(filter, entry, k)) + return true; + } + } + return false; +} + +static bool should_print_entry(struct jset_entry *entry, d_btree_id filter) +{ + struct bkey_i *k; + enum btree_id *id; + + if (!filter.nr) + return true; + + if (entry->type != BCH_JSET_ENTRY_btree_root && + entry->type != BCH_JSET_ENTRY_btree_keys && + entry->type != BCH_JSET_ENTRY_overwrite) + return true; + + vstruct_for_each(entry, k) + darray_for_each(filter, id) + if (entry->btree_id == *id) + return true; + + return false; +} + +static void journal_entries_print(struct bch_fs *c, unsigned nr_entries, + d_bbpos transaction_filter, + d_btree_id key_filter) +{ struct journal_replay *p, **_p; struct genradix_iter iter; - struct jset_entry *entry; struct printbuf buf = PRINTBUF; genradix_for_each(&c->journal_entries, iter, _p) { @@ -95,46 +133,125 @@ int cmd_list_journal(int argc, char *argv[]) bch2_journal_seq_is_blacklisted(c, le64_to_cpu(p->j.seq), false); - if (blacklisted) - printf("blacklisted "); - - printf("journal entry %llu\n", le64_to_cpu(p->j.seq)); + if (!transaction_filter.nr) { + if (blacklisted) + printf("blacklisted "); - printbuf_reset(&buf); + printf("journal entry %llu\n", le64_to_cpu(p->j.seq)); - prt_printf(&buf, - " version %u\n" - " last seq %llu\n" - " flush %u\n" - " written at ", - le32_to_cpu(p->j.version), - le64_to_cpu(p->j.last_seq), - !JSET_NO_FLUSH(&p->j)); - bch2_journal_ptrs_to_text(&buf, c, p); + printbuf_reset(&buf); - if (blacklisted) - star_start_of_lines(buf.buf); - printf("%s\n", buf.buf); + prt_printf(&buf, + " version %u\n" + " last seq %llu\n" + " flush %u\n" + " written at ", + le32_to_cpu(p->j.version), + le64_to_cpu(p->j.last_seq), + !JSET_NO_FLUSH(&p->j)); + bch2_journal_ptrs_to_text(&buf, c, p); - vstruct_for_each(&p->j, entry) { + if (blacklisted) + star_start_of_lines(buf.buf); + printf("%s\n", buf.buf); printbuf_reset(&buf); + } + + struct jset_entry *entry = p->j.start; + struct jset_entry *end = vstruct_last(&p->j); + while (entry != end) { /* * log entries denote the start of a new transaction * commit: */ - if (entry->type == BCH_JSET_ENTRY_log && !entry->level) + if (entry_is_transaction_start(entry)) { + if (!should_print_transaction(entry, end, transaction_filter)) { + do { + entry = vstruct_next(entry); + } while (entry != end && !entry_is_transaction_start(entry)); + + continue; + } + prt_newline(&buf); - printbuf_indent_add(&buf, 4); - bch2_journal_entry_to_text(&buf, c, entry); + } - if (blacklisted) - star_start_of_lines(buf.buf); - printf("%s\n", buf.buf); + if (should_print_entry(entry, key_filter)) { + printbuf_indent_add(&buf, 4); + bch2_journal_entry_to_text(&buf, c, entry); + + if (blacklisted) + star_start_of_lines(buf.buf); + printf("%s\n", buf.buf); + printbuf_reset(&buf); + } + + entry = vstruct_next(entry); } } printbuf_exit(&buf); +} + +int cmd_list_journal(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "nr-entries", required_argument, NULL, 'n' }, + { "transaction-filter", required_argument, NULL, 't' }, + { "key-filter", required_argument, NULL, 'k' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { NULL } + }; + struct bch_opts opts = bch2_opts_empty(); + u32 nr_entries = U32_MAX; + d_bbpos transaction_filter = { 0 }; + d_btree_id key_filter = { 0 }; + int opt; + + opt_set(opts, nochanges, true); + opt_set(opts, norecovery, true); + opt_set(opts, degraded, true); + opt_set(opts, errors, BCH_ON_ERROR_continue); + opt_set(opts, fix_errors, FSCK_OPT_YES); + opt_set(opts, keep_journal, true); + opt_set(opts, read_journal_only,true); + + while ((opt = getopt_long(argc, argv, "an:t:k:vh", + longopts, NULL)) != -1) + switch (opt) { + case 'a': + opt_set(opts, read_entire_journal, true); + break; + case 'n': + if (kstrtouint(optarg, 10, &nr_entries)) + die("error parsing nr_entries"); + opt_set(opts, read_entire_journal, true); + break; + case 't': + darray_push(&transaction_filter, bbpos_parse(optarg)); + break; + case 'k': + darray_push(&key_filter, read_string_list_or_die(optarg, bch2_btree_ids, "btree id")); + break; + case 'v': + opt_set(opts, verbose, true); + break; + case 'h': + list_journal_usage(); + exit(EXIT_SUCCESS); + } + args_shift(optind); + + if (!argc) + die("Please supply device(s) to open"); + + struct bch_fs *c = bch2_fs_open(argv, argc, opts); + if (IS_ERR(c)) + die("error opening %s: %s", argv[0], bch2_err_str(PTR_ERR(c))); + + journal_entries_print(c, nr_entries, transaction_filter, key_filter); bch2_fs_stop(c); return 0; } |