diff --git a/.bcachefs_revision b/.bcachefs_revision index 330c6bdd..4600d638 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -fd637ebda030609b15a473f01f1ef54bbe818f27 +76f72a0cc7392f83567b3f477496d6efe8a98f6b diff --git a/libbcachefs/bcachefs.h b/libbcachefs/bcachefs.h index 5a8440cc..fa959376 100644 --- a/libbcachefs/bcachefs.h +++ b/libbcachefs/bcachefs.h @@ -521,6 +521,18 @@ struct journal_seq_blacklist_table { } entries[0]; }; +struct journal_keys { + struct journal_key { + enum btree_id btree_id:8; + unsigned level:8; + struct bkey_i *k; + u32 journal_seq; + u32 journal_offset; + } *d; + size_t nr; + u64 journal_seq_base; +}; + struct bch_fs { struct closure cl; @@ -787,6 +799,8 @@ struct bch_fs { mempool_t btree_bounce_pool; struct journal journal; + struct list_head journal_entries; + struct journal_keys journal_keys; u64 last_bucket_seq_cleanup; diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c index 936e6366..822541e6 100644 --- a/libbcachefs/fsck.c +++ b/libbcachefs/fsck.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "bcachefs.h" +#include "bkey_on_stack.h" #include "btree_update.h" #include "dirent.h" #include "error.h" @@ -469,10 +470,12 @@ static int check_extents(struct bch_fs *c) struct btree_trans trans; struct btree_iter *iter; struct bkey_s_c k; - struct bkey prev = KEY(0, 0, 0); + struct bkey_on_stack prev; u64 i_sectors; int ret = 0; + bkey_on_stack_init(&prev); + prev.k->k = KEY(0, 0, 0); bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0); bch_verbose(c, "checking extents"); @@ -482,24 +485,24 @@ static int check_extents(struct bch_fs *c) BTREE_ITER_INTENT); retry: for_each_btree_key_continue(iter, 0, k, ret) { - if (bkey_cmp(prev.p, bkey_start_pos(k.k)) > 0) { - char buf1[100]; - char buf2[100]; + if (bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) { + char buf1[200]; + char buf2[200]; - bch2_bkey_to_text(&PBUF(buf1), &prev); - bch2_bkey_to_text(&PBUF(buf2), k.k); + 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: %s, %s", buf1, buf2)) { + if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2)) { ret = __bch2_trans_do(&trans, NULL, NULL, BTREE_INSERT_NOFAIL| BTREE_INSERT_LAZY_RW, bch2_fix_overlapping_extent(&trans, - iter, k, prev.p)); + iter, k, prev.k->k.p)); if (ret) goto err; } } - prev = *k.k; + bkey_on_stack_reassemble(&prev, c, k); ret = walk_inode(&trans, &w, k.k->p.inode); if (ret) @@ -525,7 +528,8 @@ retry: !(w.inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY) && w.inode.bi_sectors != (i_sectors = bch2_count_inode_sectors(&trans, w.cur_inum)), - c, "i_sectors wrong: got %llu, should be %llu", + c, "inode %llu has incorrect i_sectors: got %llu, should be %llu", + w.inode.bi_inum, w.inode.bi_sectors, i_sectors)) { struct bkey_inode_buf p; @@ -567,6 +571,7 @@ err: fsck_err: if (ret == -EINTR) goto retry; + bkey_on_stack_exit(&prev, c); return bch2_trans_exit(&trans) ?: ret; } diff --git a/libbcachefs/opts.h b/libbcachefs/opts.h index 1c05effa..ba490335 100644 --- a/libbcachefs/opts.h +++ b/libbcachefs/opts.h @@ -255,6 +255,11 @@ enum opt_type { OPT_BOOL(), \ NO_SB_OPT, false, \ NULL, "Don't replay the journal") \ + x(keep_journal, u8, \ + OPT_MOUNT, \ + OPT_BOOL(), \ + NO_SB_OPT, false, \ + NULL, "Don't free journal entries/keys after startup")\ x(noexcl, u8, \ OPT_MOUNT, \ OPT_BOOL(), \ diff --git a/libbcachefs/recovery.c b/libbcachefs/recovery.c index 2b428ee7..320fea2b 100644 --- a/libbcachefs/recovery.c +++ b/libbcachefs/recovery.c @@ -198,7 +198,7 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *i /* sort and dedup all keys in the journal: */ -static void journal_entries_free(struct list_head *list) +void bch2_journal_entries_free(struct list_head *list) { while (!list_empty(list)) { @@ -236,7 +236,7 @@ static int journal_sort_seq_cmp(const void *_l, const void *_r) bkey_cmp(l->k->k.p, r->k->k.p); } -static void journal_keys_free(struct journal_keys *keys) +void bch2_journal_keys_free(struct journal_keys *keys) { kvfree(keys->d); keys->d = NULL; @@ -801,8 +801,6 @@ int bch2_fs_recovery(struct bch_fs *c) const char *err = "cannot allocate memory"; struct bch_sb_field_clean *clean = NULL; u64 journal_seq; - LIST_HEAD(journal_entries); - struct journal_keys journal_keys = { NULL }; bool wrote = false, write_sb = false; int ret; @@ -824,30 +822,30 @@ int bch2_fs_recovery(struct bch_fs *c) if (!c->sb.clean || c->opts.fsck) { struct jset *j; - ret = bch2_journal_read(c, &journal_entries); + ret = bch2_journal_read(c, &c->journal_entries); if (ret) goto err; - if (mustfix_fsck_err_on(c->sb.clean && !journal_empty(&journal_entries), c, + if (mustfix_fsck_err_on(c->sb.clean && !journal_empty(&c->journal_entries), c, "filesystem marked clean but journal not empty")) { c->sb.compat &= ~(1ULL << BCH_COMPAT_FEAT_ALLOC_INFO); SET_BCH_SB_CLEAN(c->disk_sb.sb, false); c->sb.clean = false; } - if (!c->sb.clean && list_empty(&journal_entries)) { + if (!c->sb.clean && list_empty(&c->journal_entries)) { bch_err(c, "no journal entries found"); ret = BCH_FSCK_REPAIR_IMPOSSIBLE; goto err; } - journal_keys = journal_keys_sort(&journal_entries); - if (!journal_keys.d) { + c->journal_keys = journal_keys_sort(&c->journal_entries); + if (!c->journal_keys.d) { ret = -ENOMEM; goto err; } - j = &list_last_entry(&journal_entries, + j = &list_last_entry(&c->journal_entries, struct journal_replay, list)->j; ret = verify_superblock_clean(c, &clean, j); @@ -866,7 +864,7 @@ int bch2_fs_recovery(struct bch_fs *c) goto err; } - ret = journal_replay_early(c, clean, &journal_entries); + ret = journal_replay_early(c, clean, &c->journal_entries); if (ret) goto err; @@ -884,15 +882,15 @@ int bch2_fs_recovery(struct bch_fs *c) ret = bch2_blacklist_table_initialize(c); - if (!list_empty(&journal_entries)) { + if (!list_empty(&c->journal_entries)) { ret = verify_journal_entries_not_blacklisted_or_missing(c, - &journal_entries); + &c->journal_entries); if (ret) goto err; } ret = bch2_fs_journal_start(&c->journal, journal_seq, - &journal_entries); + &c->journal_entries); if (ret) goto err; @@ -902,14 +900,14 @@ int bch2_fs_recovery(struct bch_fs *c) bch_verbose(c, "starting alloc read"); err = "error reading allocation information"; - ret = bch2_alloc_read(c, &journal_keys); + ret = bch2_alloc_read(c, &c->journal_keys); if (ret) goto err; bch_verbose(c, "alloc read done"); bch_verbose(c, "starting stripes_read"); err = "error reading stripes"; - ret = bch2_stripes_read(c, &journal_keys); + ret = bch2_stripes_read(c, &c->journal_keys); if (ret) goto err; bch_verbose(c, "stripes_read done"); @@ -925,7 +923,7 @@ int bch2_fs_recovery(struct bch_fs *c) */ bch_info(c, "starting metadata mark and sweep"); err = "error in mark and sweep"; - ret = bch2_gc(c, &journal_keys, true, true); + ret = bch2_gc(c, &c->journal_keys, true, true); if (ret) goto err; bch_verbose(c, "mark and sweep done"); @@ -936,7 +934,7 @@ int bch2_fs_recovery(struct bch_fs *c) test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags)) { bch_info(c, "starting mark and sweep"); err = "error in mark and sweep"; - ret = bch2_gc(c, &journal_keys, true, false); + ret = bch2_gc(c, &c->journal_keys, true, false); if (ret) goto err; bch_verbose(c, "mark and sweep done"); @@ -957,7 +955,7 @@ int bch2_fs_recovery(struct bch_fs *c) bch_verbose(c, "starting journal replay"); err = "journal replay failed"; - ret = bch2_journal_replay(c, journal_keys); + ret = bch2_journal_replay(c, c->journal_keys); if (ret) goto err; bch_verbose(c, "journal replay done"); @@ -1053,8 +1051,10 @@ fsck_err: set_bit(BCH_FS_FSCK_DONE, &c->flags); bch2_flush_fsck_errs(c); - journal_keys_free(&journal_keys); - journal_entries_free(&journal_entries); + if (!c->opts.keep_journal) { + bch2_journal_keys_free(&c->journal_keys); + bch2_journal_entries_free(&c->journal_entries); + } kfree(clean); if (ret) bch_err(c, "Error in recovery: %s (%i)", err, ret); diff --git a/libbcachefs/recovery.h b/libbcachefs/recovery.h index fa1f2818..19f2f172 100644 --- a/libbcachefs/recovery.h +++ b/libbcachefs/recovery.h @@ -2,18 +2,6 @@ #ifndef _BCACHEFS_RECOVERY_H #define _BCACHEFS_RECOVERY_H -struct journal_keys { - struct journal_key { - enum btree_id btree_id:8; - unsigned level:8; - struct bkey_i *k; - u32 journal_seq; - u32 journal_offset; - } *d; - size_t nr; - u64 journal_seq_base; -}; - #define for_each_journal_key(keys, i) \ for (i = (keys).d; i < (keys).d + (keys).nr; (i)++) @@ -56,6 +44,9 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *, struct journal_keys *, struct btree *); +void bch2_journal_keys_free(struct journal_keys *); +void bch2_journal_entries_free(struct list_head *); + int bch2_fs_recovery(struct bch_fs *); int bch2_fs_initialize(struct bch_fs *); diff --git a/libbcachefs/super.c b/libbcachefs/super.c index b990c16b..d2c275ce 100644 --- a/libbcachefs/super.c +++ b/libbcachefs/super.c @@ -500,6 +500,8 @@ static void bch2_fs_free(struct bch_fs *c) bch2_io_clock_exit(&c->io_clock[WRITE]); bch2_io_clock_exit(&c->io_clock[READ]); bch2_fs_compress_exit(c); + bch2_journal_keys_free(&c->journal_keys); + bch2_journal_entries_free(&c->journal_entries); percpu_free_rwsem(&c->mark_lock); kfree(c->usage_scratch); free_percpu(c->usage[1]); @@ -689,6 +691,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) INIT_WORK(&c->journal_seq_blacklist_gc_work, bch2_blacklist_entries_gc); + INIT_LIST_HEAD(&c->journal_entries); + INIT_LIST_HEAD(&c->fsck_errors); mutex_init(&c->fsck_error_lock);