On upgrade from before bcachefs_metadata_version_backpointer_bucket_gen we'll typically skip the write buffer flush, because we expect many invalid/missing backpointers and it's faster to just repair them.
When we find backpointers that sum up to more than the bucket sector counters, that's a special situation - we need to walk those backpointers to kill the bad ones, and so that case needs a write buffer flush to avoid an infinite loop. Reported-by: Jérôme Poulin <jeromepou...@gmail.com> Signed-off-by: Kent Overstreet <kent.overstr...@linux.dev> --- fs/bcachefs/backpointers.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/bcachefs/backpointers.c b/fs/bcachefs/backpointers.c index 77d93beb3c8f..9d0c3cb634e8 100644 --- a/fs/bcachefs/backpointers.c +++ b/fs/bcachefs/backpointers.c @@ -943,20 +943,24 @@ static int check_bucket_backpointer_mismatch(struct btree_trans *trans, struct b if (sectors[ALLOC_dirty] != a->dirty_sectors || sectors[ALLOC_cached] != a->cached_sectors || sectors[ALLOC_stripe] != a->stripe_sectors) { - if (c->sb.version_upgrade_complete >= bcachefs_metadata_version_backpointer_bucket_gen) { + if (sectors[ALLOC_dirty] > a->dirty_sectors || + sectors[ALLOC_cached] > a->cached_sectors || + sectors[ALLOC_stripe] > a->stripe_sectors) { ret = bch2_backpointers_maybe_flush(trans, alloc_k, last_flushed); if (ret) goto err; - } - if (sectors[ALLOC_dirty] > a->dirty_sectors || - sectors[ALLOC_cached] > a->cached_sectors || - sectors[ALLOC_stripe] > a->stripe_sectors) { ret = check_bucket_backpointers_to_extents(trans, ca, alloc_k.k->p) ?: bch_err_throw(c, transaction_restart_nested); goto err; } + if (c->sb.version_upgrade_complete >= bcachefs_metadata_version_backpointer_bucket_gen) { + ret = bch2_backpointers_maybe_flush(trans, alloc_k, last_flushed); + if (ret) + goto err; + } + bool empty = (sectors[ALLOC_dirty] + sectors[ALLOC_stripe] + sectors[ALLOC_cached]) == 0; -- 2.50.0