mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
bcachefs: Make sure __bch2_run_explicit_recovery_pass() signals to rewind
We should always signal to rewind if the requested pass hasn't been run, even if called multiple times. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
8ea098f248
commit
61ab7cbbaa
@ -1044,6 +1044,7 @@ struct bch_fs {
|
|||||||
* for signaling to the toplevel code which pass we want to run now.
|
* for signaling to the toplevel code which pass we want to run now.
|
||||||
*/
|
*/
|
||||||
enum bch_recovery_pass curr_recovery_pass;
|
enum bch_recovery_pass curr_recovery_pass;
|
||||||
|
enum bch_recovery_pass next_recovery_pass;
|
||||||
/* bitmask of recovery passes that we actually ran */
|
/* bitmask of recovery passes that we actually ran */
|
||||||
u64 recovery_passes_complete;
|
u64 recovery_passes_complete;
|
||||||
/* never rewinds version of curr_recovery_pass */
|
/* never rewinds version of curr_recovery_pass */
|
||||||
|
@ -103,27 +103,31 @@ u64 bch2_recovery_passes_from_stable(u64 v)
|
|||||||
static int __bch2_run_explicit_recovery_pass(struct bch_fs *c,
|
static int __bch2_run_explicit_recovery_pass(struct bch_fs *c,
|
||||||
enum bch_recovery_pass pass)
|
enum bch_recovery_pass pass)
|
||||||
{
|
{
|
||||||
if (c->opts.recovery_passes & BIT_ULL(pass))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (c->curr_recovery_pass == ARRAY_SIZE(recovery_pass_fns))
|
if (c->curr_recovery_pass == ARRAY_SIZE(recovery_pass_fns))
|
||||||
return -BCH_ERR_not_in_recovery;
|
return -BCH_ERR_not_in_recovery;
|
||||||
|
|
||||||
|
if (c->recovery_passes_complete & BIT_ULL(pass))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bool print = !(c->opts.recovery_passes & BIT_ULL(pass));
|
||||||
|
|
||||||
if (pass < BCH_RECOVERY_PASS_set_may_go_rw &&
|
if (pass < BCH_RECOVERY_PASS_set_may_go_rw &&
|
||||||
c->curr_recovery_pass >= BCH_RECOVERY_PASS_set_may_go_rw) {
|
c->curr_recovery_pass >= BCH_RECOVERY_PASS_set_may_go_rw) {
|
||||||
bch_info(c, "need recovery pass %s (%u), but already rw",
|
if (print)
|
||||||
bch2_recovery_passes[pass], pass);
|
bch_info(c, "need recovery pass %s (%u), but already rw",
|
||||||
|
bch2_recovery_passes[pass], pass);
|
||||||
return -BCH_ERR_cannot_rewind_recovery;
|
return -BCH_ERR_cannot_rewind_recovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
bch_info(c, "running explicit recovery pass %s (%u), currently at %s (%u)",
|
if (print)
|
||||||
bch2_recovery_passes[pass], pass,
|
bch_info(c, "running explicit recovery pass %s (%u), currently at %s (%u)",
|
||||||
bch2_recovery_passes[c->curr_recovery_pass], c->curr_recovery_pass);
|
bch2_recovery_passes[pass], pass,
|
||||||
|
bch2_recovery_passes[c->curr_recovery_pass], c->curr_recovery_pass);
|
||||||
|
|
||||||
c->opts.recovery_passes |= BIT_ULL(pass);
|
c->opts.recovery_passes |= BIT_ULL(pass);
|
||||||
|
|
||||||
if (c->curr_recovery_pass >= pass) {
|
if (c->curr_recovery_pass > pass) {
|
||||||
c->curr_recovery_pass = pass;
|
c->next_recovery_pass = pass;
|
||||||
c->recovery_passes_complete &= (1ULL << pass) >> 1;
|
c->recovery_passes_complete &= (1ULL << pass) >> 1;
|
||||||
return -BCH_ERR_restart_recovery;
|
return -BCH_ERR_restart_recovery;
|
||||||
} else {
|
} else {
|
||||||
@ -264,7 +268,9 @@ int bch2_run_recovery_passes(struct bch_fs *c)
|
|||||||
*/
|
*/
|
||||||
c->opts.recovery_passes_exclude &= ~BCH_RECOVERY_PASS_set_may_go_rw;
|
c->opts.recovery_passes_exclude &= ~BCH_RECOVERY_PASS_set_may_go_rw;
|
||||||
|
|
||||||
while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
|
while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns) && !ret) {
|
||||||
|
c->next_recovery_pass = c->curr_recovery_pass + 1;
|
||||||
|
|
||||||
spin_lock_irq(&c->recovery_pass_lock);
|
spin_lock_irq(&c->recovery_pass_lock);
|
||||||
unsigned pass = c->curr_recovery_pass;
|
unsigned pass = c->curr_recovery_pass;
|
||||||
|
|
||||||
@ -285,31 +291,25 @@ int bch2_run_recovery_passes(struct bch_fs *c)
|
|||||||
ret = bch2_run_recovery_pass(c, pass) ?:
|
ret = bch2_run_recovery_pass(c, pass) ?:
|
||||||
bch2_journal_flush(&c->journal);
|
bch2_journal_flush(&c->journal);
|
||||||
|
|
||||||
|
if (!ret && !test_bit(BCH_FS_error, &c->flags))
|
||||||
|
bch2_clear_recovery_pass_required(c, pass);
|
||||||
|
|
||||||
spin_lock_irq(&c->recovery_pass_lock);
|
spin_lock_irq(&c->recovery_pass_lock);
|
||||||
if (c->curr_recovery_pass < pass) {
|
if (c->next_recovery_pass < c->curr_recovery_pass) {
|
||||||
/*
|
/*
|
||||||
* bch2_run_explicit_recovery_pass() was called: we
|
* bch2_run_explicit_recovery_pass() was called: we
|
||||||
* can't always catch -BCH_ERR_restart_recovery because
|
* can't always catch -BCH_ERR_restart_recovery because
|
||||||
* it may have been called from another thread (btree
|
* it may have been called from another thread (btree
|
||||||
* node read completion)
|
* node read completion)
|
||||||
*/
|
*/
|
||||||
spin_unlock_irq(&c->recovery_pass_lock);
|
ret = 0;
|
||||||
continue;
|
c->recovery_passes_complete &= ~(~0ULL << c->curr_recovery_pass);
|
||||||
} else if (c->curr_recovery_pass == pass) {
|
|
||||||
c->curr_recovery_pass++;
|
|
||||||
} else {
|
} else {
|
||||||
BUG();
|
c->recovery_passes_complete |= BIT_ULL(pass);
|
||||||
|
c->recovery_pass_done = max(c->recovery_pass_done, pass);
|
||||||
}
|
}
|
||||||
|
c->curr_recovery_pass = c->next_recovery_pass;
|
||||||
spin_unlock_irq(&c->recovery_pass_lock);
|
spin_unlock_irq(&c->recovery_pass_lock);
|
||||||
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
|
|
||||||
c->recovery_passes_complete |= BIT_ULL(pass);
|
|
||||||
c->recovery_pass_done = max(c->recovery_pass_done, pass);
|
|
||||||
|
|
||||||
if (!test_bit(BCH_FS_error, &c->flags))
|
|
||||||
bch2_clear_recovery_pass_required(c, pass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user