BCH_FS_CLEAN_SHUTDOWN,
 
        /* fsck passes: */
-       BCH_FS_TOPOLOGY_REPAIR_DONE,
        BCH_FS_FSCK_DONE,
        BCH_FS_INITIAL_GC_UNFIXED,      /* kill when we enumerate fsck errors */
        BCH_FS_NEED_ANOTHER_GC,
        x(stripes_read,                 PASS_ALWAYS)                                            \
        x(initialize_subvolumes,        0)                                                      \
        x(snapshots_read,               PASS_ALWAYS)                                            \
+       x(check_topology,               0)                                                      \
        x(check_allocations,            PASS_FSCK)                                              \
        x(set_may_go_rw,                PASS_ALWAYS|PASS_SILENT)                                \
        x(journal_replay,               PASS_ALWAYS)                                            \
 static inline int bch2_run_explicit_recovery_pass(struct bch_fs *c,
                                                  enum bch_recovery_pass pass)
 {
-       BUG_ON(c->curr_recovery_pass < pass);
-
        c->recovery_passes_explicit |= BIT_ULL(pass);
-       c->curr_recovery_pass = pass;
-       return -BCH_ERR_restart_recovery;
+
+       if (c->curr_recovery_pass >= pass) {
+               c->curr_recovery_pass = pass;
+               return -BCH_ERR_restart_recovery;
+       } else {
+               return 0;
+       }
 }
 
 #define BKEY_PADDED_ONSTACK(key, pad)                          \
 
 #define DROP_THIS_NODE         10
 #define DROP_PREV_NODE         11
 
+static bool should_restart_for_topology_repair(struct bch_fs *c)
+{
+       return c->opts.fix_errors != FSCK_FIX_no &&
+               !(c->recovery_passes_explicit & BIT_ULL(BCH_RECOVERY_PASS_check_topology));
+}
+
 static inline void __gc_pos_set(struct bch_fs *c, struct gc_pos new_pos)
 {
        preempt_disable();
                                  "  cur %s",
                                  bch2_btree_ids[b->c.btree_id], b->c.level,
                                  buf1.buf, buf2.buf) &&
-                           !test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
+                           should_restart_for_topology_repair(c)) {
                                bch_info(c, "Halting mark and sweep to start topology repair pass");
-                               ret = -BCH_ERR_need_topology_repair;
+                               ret = bch2_run_explicit_recovery_pass(c, BCH_RECOVERY_PASS_check_topology);
                                goto err;
                        } else {
                                set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
                          "  expected %s",
                          bch2_btree_ids[b->c.btree_id], b->c.level,
                          buf1.buf, buf2.buf) &&
-                   !test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
+                   should_restart_for_topology_repair(c)) {
                        bch_info(c, "Halting mark and sweep to start topology repair pass");
-                       ret = -BCH_ERR_need_topology_repair;
+                       ret = bch2_run_explicit_recovery_pass(c, BCH_RECOVERY_PASS_check_topology);
                        goto err;
                } else {
                        set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
        return ret;
 }
 
-static int bch2_repair_topology(struct bch_fs *c)
+int bch2_check_topology(struct bch_fs *c)
 {
        struct btree_trans trans;
        struct btree *b;
                                          b->c.level - 1,
                                          (printbuf_reset(&buf),
                                           bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(cur.k)), buf.buf)) &&
-                                   !test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
-                                       ret = -BCH_ERR_need_topology_repair;
+                                   should_restart_for_topology_repair(c)) {
                                        bch_info(c, "Halting mark and sweep to start topology repair pass");
+                                       ret = bch2_run_explicit_recovery_pass(c, BCH_RECOVERY_PASS_check_topology);
                                        goto fsck_err;
                                } else {
                                        /* Continue marking when opted to not
 
        bch2_mark_superblocks(c);
 
-       if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
-           (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) &&
-            c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations &&
-            c->opts.fix_errors != FSCK_FIX_no)) {
-               bch_info(c, "Starting topology repair pass");
-               ret = bch2_repair_topology(c);
-               if (ret)
-                       goto out;
-               bch_info(c, "Topology repair pass done");
-
-               set_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags);
-       }
-
        ret = bch2_gc_btrees(c, initial, metadata_only);
 
-       if (ret == -BCH_ERR_need_topology_repair &&
-           !test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags) &&
-           c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations) {
-               set_bit(BCH_FS_NEED_ANOTHER_GC, &c->flags);
-               SET_BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb, true);
-               ret = 0;
-       }
-
-       if (ret == -BCH_ERR_need_topology_repair)
-               ret = -BCH_ERR_fsck_errors_not_fixed;
-
        if (ret)
                goto out;
 
 
 
 #include "btree_types.h"
 
+int bch2_check_topology(struct bch_fs *);
 int bch2_gc(struct bch_fs *, bool, bool);
 int bch2_gc_gens(struct bch_fs *);
 void bch2_gc_thread_stop(struct bch_fs *);
 
        case BTREE_ERR_BAD_NODE:
                bch2_print_string_as_lines(KERN_ERR, out.buf);
                bch2_topology_error(c);
-               ret = -BCH_ERR_need_topology_repair;
+               ret = bch2_run_explicit_recovery_pass(c, BCH_RECOVERY_PASS_check_topology) ?: -EIO;
                break;
        case BTREE_ERR_INCOMPATIBLE:
                bch2_print_string_as_lines(KERN_ERR, out.buf);
                btree_pos_to_text(&buf, c, b);
                bch_err(c, "%s", buf.buf);
 
-               if (test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags))
+               if (c->recovery_passes_explicit & BIT_ULL(BCH_RECOVERY_PASS_check_topology) &&
+                   c->curr_recovery_pass > BCH_RECOVERY_PASS_check_topology)
                        bch2_fatal_error(c);
 
                set_btree_node_read_error(b);
 
        x(BCH_ERR_fsck,                 fsck_repair_unimplemented)              \
        x(BCH_ERR_fsck,                 fsck_repair_impossible)                 \
        x(0,                            restart_recovery)                       \
-       x(0,                            need_topology_repair)                   \
        x(0,                            unwritten_extent_update)                \
        x(EINVAL,                       device_state_not_allowed)               \
        x(EINVAL,                       member_info_missing)                    \
 
 
 void bch2_topology_error(struct bch_fs *c)
 {
-       if (!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags))
-               return;
-
        set_bit(BCH_FS_TOPOLOGY_ERROR, &c->flags);
        if (test_bit(BCH_FS_FSCK_DONE, &c->flags))
                bch2_inconsistent_error(c);
 
 static int bch2_run_recovery_passes(struct bch_fs *c)
 {
        int ret = 0;
-again:
+
        while (c->curr_recovery_pass < ARRAY_SIZE(recovery_passes)) {
                ret = bch2_run_recovery_pass(c, c->curr_recovery_pass);
+               if (bch2_err_matches(ret, BCH_ERR_restart_recovery))
+                       continue;
                if (ret)
                        break;
                c->curr_recovery_pass++;
        }
 
-       if (bch2_err_matches(ret, BCH_ERR_restart_recovery))
-               goto again;
-
        return ret;
 }
 
        if (ret)
                goto err;
 
+       if (c->opts.fsck &&
+           (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
+            BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb)))
+               c->recovery_passes_explicit |= BIT_ULL(BCH_RECOVERY_PASS_check_topology);
+
        ret = bch2_run_recovery_passes(c);
        if (ret)
                goto err;