Skip to content

Commit 13c1e58

Browse files
author
Kent Overstreet
committed
bcachefs: Improve -o norecovery; opts.recovery_pass_limit
This adds opts.recovery_pass_limit, and redoes -o norecovery to make use of it; this fixes some issues with -o norecovery so it can be safely used for data recovery. Norecovery means "don't do journal replay"; it's an important data recovery tool when we're getting stuck in journal replay. When using it this way we need to make sure we don't free journal keys after startup, so we continue to overlay them: thus it needs to imply retain_recovery_info, as well as nochanges. recovery_pass_limit is an explicit option for telling recovery to exit after a specific recovery pass; this is a much cleaner way of implementing -o norecovery, as well as being a useful debug feature in its own right. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 060ff30 commit 13c1e58

File tree

6 files changed

+26
-14
lines changed

6 files changed

+26
-14
lines changed

fs/bcachefs/opts.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "disk_groups.h"
88
#include "error.h"
99
#include "opts.h"
10+
#include "recovery_passes.h"
1011
#include "super-io.h"
1112
#include "util.h"
1213

@@ -205,6 +206,9 @@ const struct bch_option bch2_opt_table[] = {
205206
#define OPT_STR(_choices) .type = BCH_OPT_STR, \
206207
.min = 0, .max = ARRAY_SIZE(_choices), \
207208
.choices = _choices
209+
#define OPT_STR_NOLIMIT(_choices) .type = BCH_OPT_STR, \
210+
.min = 0, .max = U64_MAX, \
211+
.choices = _choices
208212
#define OPT_FN(_fn) .type = BCH_OPT_FN, .fn = _fn
209213

210214
#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help) \

fs/bcachefs/opts.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,12 @@ enum fsck_err_opts {
362362
OPT_FS|OPT_MOUNT, \
363363
OPT_BOOL(), \
364364
BCH2_NO_SB_OPT, false, \
365-
NULL, "Don't replay the journal") \
365+
NULL, "Exit recovery immediately prior to journal replay")\
366+
x(recovery_pass_last, u8, \
367+
OPT_FS|OPT_MOUNT, \
368+
OPT_STR_NOLIMIT(bch2_recovery_passes), \
369+
BCH2_NO_SB_OPT, 0, \
370+
NULL, "Exit recovery after specified pass") \
366371
x(keep_journal, u8, \
367372
0, \
368373
OPT_BOOL(), \

fs/bcachefs/recovery.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ int bch2_journal_replay(struct bch_fs *c)
269269
bch2_trans_put(trans);
270270
trans = NULL;
271271

272-
if (!c->opts.keep_journal)
272+
if (!c->opts.keep_journal &&
273+
c->recovery_pass_done >= BCH_RECOVERY_PASS_journal_replay)
273274
bch2_journal_keys_put_initial(c);
274275

275276
replay_now_at(j, j->replay_journal_seq_end);
@@ -584,11 +585,8 @@ int bch2_fs_recovery(struct bch_fs *c)
584585
goto err;
585586
}
586587

587-
if (c->opts.fsck && c->opts.norecovery) {
588-
bch_err(c, "cannot select both norecovery and fsck");
589-
ret = -EINVAL;
590-
goto err;
591-
}
588+
if (c->opts.norecovery)
589+
c->opts.recovery_pass_last = BCH_RECOVERY_PASS_journal_replay - 1;
592590

593591
if (!c->opts.nochanges) {
594592
mutex_lock(&c->sb_lock);

fs/bcachefs/recovery_passes.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const char * const bch2_recovery_passes[] = {
2727

2828
static int bch2_check_allocations(struct bch_fs *c)
2929
{
30-
return bch2_gc(c, true, c->opts.norecovery);
30+
return bch2_gc(c, true, false);
3131
}
3232

3333
static int bch2_set_may_go_rw(struct bch_fs *c)
@@ -144,8 +144,6 @@ static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pa
144144
{
145145
struct recovery_pass_fn *p = recovery_pass_fns + pass;
146146

147-
if (c->opts.norecovery && pass > BCH_RECOVERY_PASS_snapshots_read)
148-
return false;
149147
if (c->recovery_passes_explicit & BIT_ULL(pass))
150148
return true;
151149
if ((p->when & PASS_FSCK) && c->opts.fsck)
@@ -201,6 +199,10 @@ int bch2_run_recovery_passes(struct bch_fs *c)
201199
int ret = 0;
202200

203201
while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
202+
if (c->opts.recovery_pass_last &&
203+
c->curr_recovery_pass > c->opts.recovery_pass_last)
204+
break;
205+
204206
if (should_run_recovery_pass(c, c->curr_recovery_pass)) {
205207
unsigned pass = c->curr_recovery_pass;
206208

@@ -213,8 +215,10 @@ int bch2_run_recovery_passes(struct bch_fs *c)
213215

214216
c->recovery_passes_complete |= BIT_ULL(c->curr_recovery_pass);
215217
}
216-
c->curr_recovery_pass++;
218+
217219
c->recovery_pass_done = max(c->recovery_pass_done, c->curr_recovery_pass);
220+
221+
c->curr_recovery_pass++;
218222
}
219223

220224
return ret;

fs/bcachefs/snapshot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool __bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor)
131131
rcu_read_lock();
132132
struct snapshot_table *t = rcu_dereference(c->snapshots);
133133

134-
if (unlikely(c->recovery_pass_done <= BCH_RECOVERY_PASS_check_snapshots)) {
134+
if (unlikely(c->recovery_pass_done < BCH_RECOVERY_PASS_check_snapshots)) {
135135
ret = __bch2_snapshot_is_ancestor_early(t, id, ancestor);
136136
goto out;
137137
}

fs/bcachefs/super.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ void bch2_fs_read_only(struct bch_fs *c)
365365
!test_bit(BCH_FS_emergency_ro, &c->flags) &&
366366
test_bit(BCH_FS_started, &c->flags) &&
367367
test_bit(BCH_FS_clean_shutdown, &c->flags) &&
368-
!c->opts.norecovery) {
368+
c->recovery_pass_done >= BCH_RECOVERY_PASS_journal_replay) {
369369
BUG_ON(c->journal.last_empty_seq != journal_cur_seq(&c->journal));
370370
BUG_ON(atomic_read(&c->btree_cache.dirty));
371371
BUG_ON(atomic_long_read(&c->btree_key_cache.nr_dirty));
@@ -510,7 +510,8 @@ static int __bch2_fs_read_write(struct bch_fs *c, bool early)
510510

511511
int bch2_fs_read_write(struct bch_fs *c)
512512
{
513-
if (c->opts.norecovery)
513+
if (c->opts.recovery_pass_last &&
514+
c->opts.recovery_pass_last < BCH_RECOVERY_PASS_journal_replay)
514515
return -BCH_ERR_erofs_norecovery;
515516

516517
if (c->opts.nochanges)

0 commit comments

Comments
 (0)