Commit f1d786a0 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Add an option for keeping journal entries after startup

This will be used by the userspace debug tools.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 2f194e16
...@@ -523,6 +523,18 @@ struct journal_seq_blacklist_table { ...@@ -523,6 +523,18 @@ struct journal_seq_blacklist_table {
} entries[0]; } 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 bch_fs {
struct closure cl; struct closure cl;
...@@ -791,6 +803,8 @@ struct bch_fs { ...@@ -791,6 +803,8 @@ struct bch_fs {
mempool_t btree_bounce_pool; mempool_t btree_bounce_pool;
struct journal journal; struct journal journal;
struct list_head journal_entries;
struct journal_keys journal_keys;
u64 last_bucket_seq_cleanup; u64 last_bucket_seq_cleanup;
......
...@@ -255,6 +255,11 @@ enum opt_type { ...@@ -255,6 +255,11 @@ enum opt_type {
OPT_BOOL(), \ OPT_BOOL(), \
NO_SB_OPT, false, \ NO_SB_OPT, false, \
NULL, "Don't replay the journal") \ 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, \ x(noexcl, u8, \
OPT_MOUNT, \ OPT_MOUNT, \
OPT_BOOL(), \ OPT_BOOL(), \
......
...@@ -198,7 +198,7 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *i ...@@ -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: */ /* 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)) { while (!list_empty(list)) {
...@@ -236,7 +236,7 @@ static int journal_sort_seq_cmp(const void *_l, const void *_r) ...@@ -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); 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); kvfree(keys->d);
keys->d = NULL; keys->d = NULL;
...@@ -802,8 +802,6 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -802,8 +802,6 @@ int bch2_fs_recovery(struct bch_fs *c)
const char *err = "cannot allocate memory"; const char *err = "cannot allocate memory";
struct bch_sb_field_clean *clean = NULL; struct bch_sb_field_clean *clean = NULL;
u64 journal_seq; u64 journal_seq;
LIST_HEAD(journal_entries);
struct journal_keys journal_keys = { NULL };
bool wrote = false, write_sb = false; bool wrote = false, write_sb = false;
int ret; int ret;
...@@ -825,30 +823,30 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -825,30 +823,30 @@ int bch2_fs_recovery(struct bch_fs *c)
if (!c->sb.clean || c->opts.fsck) { if (!c->sb.clean || c->opts.fsck) {
struct jset *j; struct jset *j;
ret = bch2_journal_read(c, &journal_entries); ret = bch2_journal_read(c, &c->journal_entries);
if (ret) if (ret)
goto err; 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")) { "filesystem marked clean but journal not empty")) {
c->sb.compat &= ~(1ULL << BCH_COMPAT_FEAT_ALLOC_INFO); c->sb.compat &= ~(1ULL << BCH_COMPAT_FEAT_ALLOC_INFO);
SET_BCH_SB_CLEAN(c->disk_sb.sb, false); SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
c->sb.clean = 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"); bch_err(c, "no journal entries found");
ret = BCH_FSCK_REPAIR_IMPOSSIBLE; ret = BCH_FSCK_REPAIR_IMPOSSIBLE;
goto err; goto err;
} }
journal_keys = journal_keys_sort(&journal_entries); c->journal_keys = journal_keys_sort(&c->journal_entries);
if (!journal_keys.d) { if (!c->journal_keys.d) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
j = &list_last_entry(&journal_entries, j = &list_last_entry(&c->journal_entries,
struct journal_replay, list)->j; struct journal_replay, list)->j;
ret = verify_superblock_clean(c, &clean, j); ret = verify_superblock_clean(c, &clean, j);
...@@ -867,7 +865,7 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -867,7 +865,7 @@ int bch2_fs_recovery(struct bch_fs *c)
goto err; goto err;
} }
ret = journal_replay_early(c, clean, &journal_entries); ret = journal_replay_early(c, clean, &c->journal_entries);
if (ret) if (ret)
goto err; goto err;
...@@ -885,15 +883,15 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -885,15 +883,15 @@ int bch2_fs_recovery(struct bch_fs *c)
ret = bch2_blacklist_table_initialize(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, ret = verify_journal_entries_not_blacklisted_or_missing(c,
&journal_entries); &c->journal_entries);
if (ret) if (ret)
goto err; goto err;
} }
ret = bch2_fs_journal_start(&c->journal, journal_seq, ret = bch2_fs_journal_start(&c->journal, journal_seq,
&journal_entries); &c->journal_entries);
if (ret) if (ret)
goto err; goto err;
...@@ -903,14 +901,14 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -903,14 +901,14 @@ int bch2_fs_recovery(struct bch_fs *c)
bch_verbose(c, "starting alloc read"); bch_verbose(c, "starting alloc read");
err = "error reading allocation information"; err = "error reading allocation information";
ret = bch2_alloc_read(c, &journal_keys); ret = bch2_alloc_read(c, &c->journal_keys);
if (ret) if (ret)
goto err; goto err;
bch_verbose(c, "alloc read done"); bch_verbose(c, "alloc read done");
bch_verbose(c, "starting stripes_read"); bch_verbose(c, "starting stripes_read");
err = "error reading stripes"; err = "error reading stripes";
ret = bch2_stripes_read(c, &journal_keys); ret = bch2_stripes_read(c, &c->journal_keys);
if (ret) if (ret)
goto err; goto err;
bch_verbose(c, "stripes_read done"); bch_verbose(c, "stripes_read done");
...@@ -926,7 +924,7 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -926,7 +924,7 @@ int bch2_fs_recovery(struct bch_fs *c)
*/ */
bch_info(c, "starting metadata mark and sweep"); bch_info(c, "starting metadata mark and sweep");
err = "error in 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) if (ret)
goto err; goto err;
bch_verbose(c, "mark and sweep done"); bch_verbose(c, "mark and sweep done");
...@@ -937,7 +935,7 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -937,7 +935,7 @@ int bch2_fs_recovery(struct bch_fs *c)
test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags)) { test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags)) {
bch_info(c, "starting mark and sweep"); bch_info(c, "starting mark and sweep");
err = "error in 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) if (ret)
goto err; goto err;
bch_verbose(c, "mark and sweep done"); bch_verbose(c, "mark and sweep done");
...@@ -958,7 +956,7 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -958,7 +956,7 @@ int bch2_fs_recovery(struct bch_fs *c)
bch_verbose(c, "starting journal replay"); bch_verbose(c, "starting journal replay");
err = "journal replay failed"; err = "journal replay failed";
ret = bch2_journal_replay(c, journal_keys); ret = bch2_journal_replay(c, c->journal_keys);
if (ret) if (ret)
goto err; goto err;
bch_verbose(c, "journal replay done"); bch_verbose(c, "journal replay done");
...@@ -1054,8 +1052,10 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -1054,8 +1052,10 @@ int bch2_fs_recovery(struct bch_fs *c)
set_bit(BCH_FS_FSCK_DONE, &c->flags); set_bit(BCH_FS_FSCK_DONE, &c->flags);
bch2_flush_fsck_errs(c); bch2_flush_fsck_errs(c);
journal_keys_free(&journal_keys); if (!c->opts.keep_journal) {
journal_entries_free(&journal_entries); bch2_journal_keys_free(&c->journal_keys);
bch2_journal_entries_free(&c->journal_entries);
}
kfree(clean); kfree(clean);
if (ret) if (ret)
bch_err(c, "Error in recovery: %s (%i)", err, ret); bch_err(c, "Error in recovery: %s (%i)", err, ret);
......
...@@ -2,18 +2,6 @@ ...@@ -2,18 +2,6 @@
#ifndef _BCACHEFS_RECOVERY_H #ifndef _BCACHEFS_RECOVERY_H
#define _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) \ #define for_each_journal_key(keys, i) \
for (i = (keys).d; i < (keys).d + (keys).nr; (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 *, ...@@ -56,6 +44,9 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *,
struct journal_keys *, struct journal_keys *,
struct btree *); 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_recovery(struct bch_fs *);
int bch2_fs_initialize(struct bch_fs *); int bch2_fs_initialize(struct bch_fs *);
......
...@@ -468,6 +468,8 @@ static void bch2_fs_free(struct bch_fs *c) ...@@ -468,6 +468,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[WRITE]);
bch2_io_clock_exit(&c->io_clock[READ]); bch2_io_clock_exit(&c->io_clock[READ]);
bch2_fs_compress_exit(c); 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); percpu_free_rwsem(&c->mark_lock);
free_percpu(c->online_reserved); free_percpu(c->online_reserved);
kfree(c->usage_scratch); kfree(c->usage_scratch);
...@@ -657,6 +659,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) ...@@ -657,6 +659,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
INIT_WORK(&c->journal_seq_blacklist_gc_work, INIT_WORK(&c->journal_seq_blacklist_gc_work,
bch2_blacklist_entries_gc); bch2_blacklist_entries_gc);
INIT_LIST_HEAD(&c->journal_entries);
INIT_LIST_HEAD(&c->fsck_errors); INIT_LIST_HEAD(&c->fsck_errors);
mutex_init(&c->fsck_error_lock); mutex_init(&c->fsck_error_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment