quota.o                 \
        rebalance.o             \
        recovery.o              \
+       recovery_passes.o       \
        reflink.o               \
        replicas.o              \
        sb-clean.o              \
 
 #include "fifo.h"
 #include "nocow_locking_types.h"
 #include "opts.h"
-#include "recovery_types.h"
+#include "recovery_passes_types.h"
 #include "sb-errors_types.h"
 #include "seqmutex.h"
 #include "time_stats.h"
 
 #include "journal.h"
 #include "keylist.h"
 #include "move.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "reflink.h"
 #include "replicas.h"
 #include "super-io.h"
 
 #include "journal.h"
 #include "journal_reclaim.h"
 #include "keylist.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "replicas.h"
 #include "super-io.h"
 #include "trace.h"
 
 #include "chardev.h"
 #include "journal.h"
 #include "move.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "replicas.h"
 #include "super.h"
 #include "super-io.h"
 
 // SPDX-License-Identifier: GPL-2.0
 #include "bcachefs.h"
 #include "error.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "super.h"
 #include "thread_with_file.h"
 
 
 #include "fsck.h"
 #include "inode.h"
 #include "keylist.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "snapshot.h"
 #include "super.h"
 #include "xattr.h"
 
 // SPDX-License-Identifier: GPL-2.0
 
 #include "bcachefs.h"
-#include "backpointers.h"
-#include "bkey_buf.h"
 #include "alloc_background.h"
-#include "btree_gc.h"
+#include "bkey_buf.h"
 #include "btree_journal_iter.h"
 #include "btree_update.h"
 #include "btree_update_interior.h"
 #include "btree_io.h"
 #include "buckets.h"
 #include "dirent.h"
-#include "ec.h"
 #include "errcode.h"
 #include "error.h"
 #include "fs-common.h"
-#include "fsck.h"
 #include "journal_io.h"
 #include "journal_reclaim.h"
 #include "journal_seq_blacklist.h"
-#include "lru.h"
 #include "logged_ops.h"
 #include "move.h"
 #include "quota.h"
 #include "rebalance.h"
 #include "recovery.h"
+#include "recovery_passes.h"
 #include "replicas.h"
 #include "sb-clean.h"
 #include "sb-downgrade.h"
 #include "snapshot.h"
-#include "subvolume.h"
 #include "super-io.h"
 
 #include <linux/sort.h>
        return cmp_int(l->journal_seq, r->journal_seq);
 }
 
-static int bch2_journal_replay(struct bch_fs *c)
+int bch2_journal_replay(struct bch_fs *c)
 {
        struct journal_keys *keys = &c->journal_keys;
        DARRAY(struct journal_key *) keys_sorted = { 0 };
        return ret;
 }
 
-static int bch2_initialize_subvolumes(struct bch_fs *c)
-{
-       struct bkey_i_snapshot_tree     root_tree;
-       struct bkey_i_snapshot          root_snapshot;
-       struct bkey_i_subvolume         root_volume;
-       int ret;
-
-       bkey_snapshot_tree_init(&root_tree.k_i);
-       root_tree.k.p.offset            = 1;
-       root_tree.v.master_subvol       = cpu_to_le32(1);
-       root_tree.v.root_snapshot       = cpu_to_le32(U32_MAX);
-
-       bkey_snapshot_init(&root_snapshot.k_i);
-       root_snapshot.k.p.offset = U32_MAX;
-       root_snapshot.v.flags   = 0;
-       root_snapshot.v.parent  = 0;
-       root_snapshot.v.subvol  = cpu_to_le32(BCACHEFS_ROOT_SUBVOL);
-       root_snapshot.v.tree    = cpu_to_le32(1);
-       SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot.v, true);
-
-       bkey_subvolume_init(&root_volume.k_i);
-       root_volume.k.p.offset = BCACHEFS_ROOT_SUBVOL;
-       root_volume.v.flags     = 0;
-       root_volume.v.snapshot  = cpu_to_le32(U32_MAX);
-       root_volume.v.inode     = cpu_to_le64(BCACHEFS_ROOT_INO);
-
-       ret =   bch2_btree_insert(c, BTREE_ID_snapshot_trees,   &root_tree.k_i, NULL, 0) ?:
-               bch2_btree_insert(c, BTREE_ID_snapshots,        &root_snapshot.k_i, NULL, 0) ?:
-               bch2_btree_insert(c, BTREE_ID_subvolumes,       &root_volume.k_i, NULL, 0);
-       bch_err_fn(c, ret);
-       return ret;
-}
-
-static int __bch2_fs_upgrade_for_subvolumes(struct btree_trans *trans)
-{
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       struct bch_inode_unpacked inode;
-       int ret;
-
-       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
-                              SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0);
-       ret = bkey_err(k);
-       if (ret)
-               return ret;
-
-       if (!bkey_is_inode(k.k)) {
-               bch_err(trans->c, "root inode not found");
-               ret = -BCH_ERR_ENOENT_inode;
-               goto err;
-       }
-
-       ret = bch2_inode_unpack(k, &inode);
-       BUG_ON(ret);
-
-       inode.bi_subvol = BCACHEFS_ROOT_SUBVOL;
-
-       ret = bch2_inode_write(trans, &iter, &inode);
-err:
-       bch2_trans_iter_exit(trans, &iter);
-       return ret;
-}
-
-/* set bi_subvol on root inode */
-noinline_for_stack
-static int bch2_fs_upgrade_for_subvolumes(struct bch_fs *c)
-{
-       int ret = bch2_trans_do(c, NULL, NULL, BCH_TRANS_COMMIT_lazy_rw,
-                               __bch2_fs_upgrade_for_subvolumes(trans));
-       bch_err_fn(c, ret);
-       return ret;
-}
-
-const char * const bch2_recovery_passes[] = {
-#define x(_fn, ...)    #_fn,
-       BCH_RECOVERY_PASSES()
-#undef x
-       NULL
-};
-
-static int bch2_check_allocations(struct bch_fs *c)
-{
-       return bch2_gc(c, true, c->opts.norecovery);
-}
-
-static int bch2_set_may_go_rw(struct bch_fs *c)
-{
-       struct journal_keys *keys = &c->journal_keys;
-
-       /*
-        * After we go RW, the journal keys buffer can't be modified (except for
-        * setting journal_key->overwritten: it will be accessed by multiple
-        * threads
-        */
-       move_gap(keys, keys->nr);
-
-       set_bit(BCH_FS_may_go_rw, &c->flags);
-
-       if (keys->nr || c->opts.fsck || !c->sb.clean)
-               return bch2_fs_read_write_early(c);
-       return 0;
-}
-
-struct recovery_pass_fn {
-       int             (*fn)(struct bch_fs *);
-       unsigned        when;
-};
-
-static struct recovery_pass_fn recovery_pass_fns[] = {
-#define x(_fn, _id, _when)     { .fn = bch2_##_fn, .when = _when },
-       BCH_RECOVERY_PASSES()
-#undef x
-};
-
-u64 bch2_recovery_passes_to_stable(u64 v)
-{
-       static const u8 map[] = {
-#define x(n, id, ...)  [BCH_RECOVERY_PASS_##n] = BCH_RECOVERY_PASS_STABLE_##n,
-       BCH_RECOVERY_PASSES()
-#undef x
-       };
-
-       u64 ret = 0;
-       for (unsigned i = 0; i < ARRAY_SIZE(map); i++)
-               if (v & BIT_ULL(i))
-                       ret |= BIT_ULL(map[i]);
-       return ret;
-}
-
-u64 bch2_recovery_passes_from_stable(u64 v)
-{
-       static const u8 map[] = {
-#define x(n, id, ...)  [BCH_RECOVERY_PASS_STABLE_##n] = BCH_RECOVERY_PASS_##n,
-       BCH_RECOVERY_PASSES()
-#undef x
-       };
-
-       u64 ret = 0;
-       for (unsigned i = 0; i < ARRAY_SIZE(map); i++)
-               if (v & BIT_ULL(i))
-                       ret |= BIT_ULL(map[i]);
-       return ret;
-}
-
 static bool check_version_upgrade(struct bch_fs *c)
 {
        unsigned latest_version = bcachefs_metadata_version_current;
        return false;
 }
 
-u64 bch2_fsck_recovery_passes(void)
-{
-       u64 ret = 0;
-
-       for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++)
-               if (recovery_pass_fns[i].when & PASS_FSCK)
-                       ret |= BIT_ULL(i);
-       return ret;
-}
-
-static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
-{
-       struct recovery_pass_fn *p = recovery_pass_fns + pass;
-
-       if (c->opts.norecovery && pass > BCH_RECOVERY_PASS_snapshots_read)
-               return false;
-       if (c->recovery_passes_explicit & BIT_ULL(pass))
-               return true;
-       if ((p->when & PASS_FSCK) && c->opts.fsck)
-               return true;
-       if ((p->when & PASS_UNCLEAN) && !c->sb.clean)
-               return true;
-       if (p->when & PASS_ALWAYS)
-               return true;
-       return false;
-}
-
-static int bch2_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
-{
-       struct recovery_pass_fn *p = recovery_pass_fns + pass;
-       int ret;
-
-       if (!(p->when & PASS_SILENT))
-               bch2_print(c, KERN_INFO bch2_log_msg(c, "%s..."),
-                          bch2_recovery_passes[pass]);
-       ret = p->fn(c);
-       if (ret)
-               return ret;
-       if (!(p->when & PASS_SILENT))
-               bch2_print(c, KERN_CONT " done\n");
-
-       return 0;
-}
-
-static int bch2_run_recovery_passes(struct bch_fs *c)
-{
-       int ret = 0;
-
-       while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
-               if (should_run_recovery_pass(c, c->curr_recovery_pass)) {
-                       unsigned pass = c->curr_recovery_pass;
-
-                       ret = bch2_run_recovery_pass(c, c->curr_recovery_pass);
-                       if (bch2_err_matches(ret, BCH_ERR_restart_recovery) ||
-                           (ret && c->curr_recovery_pass < pass))
-                               continue;
-                       if (ret)
-                               break;
-
-                       c->recovery_passes_complete |= BIT_ULL(c->curr_recovery_pass);
-               }
-               c->curr_recovery_pass++;
-               c->recovery_pass_done = max(c->recovery_pass_done, c->curr_recovery_pass);
-       }
-
-       return ret;
-}
-
-int bch2_run_online_recovery_passes(struct bch_fs *c)
-{
-       int ret = 0;
-
-       for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++) {
-               struct recovery_pass_fn *p = recovery_pass_fns + i;
-
-               if (!(p->when & PASS_ONLINE))
-                       continue;
-
-               ret = bch2_run_recovery_pass(c, i);
-               if (bch2_err_matches(ret, BCH_ERR_restart_recovery)) {
-                       i = c->curr_recovery_pass;
-                       continue;
-               }
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-
 int bch2_fs_recovery(struct bch_fs *c)
 {
        struct bch_sb_field_clean *clean = NULL;
        }
        mutex_unlock(&c->sb_lock);
 
-       c->curr_recovery_pass = ARRAY_SIZE(recovery_pass_fns);
+       c->curr_recovery_pass = BCH_RECOVERY_PASS_NR;
        set_bit(BCH_FS_may_go_rw, &c->flags);
 
        for (unsigned i = 0; i < BTREE_ID_NR; i++)
        if (ret)
                goto err;
 
-       c->recovery_pass_done = ARRAY_SIZE(recovery_pass_fns) - 1;
+       c->recovery_pass_done = BCH_RECOVERY_PASS_NR - 1;
 
        if (enabled_qtypes(c)) {
                ret = bch2_fs_quota_read(c);
 
 #ifndef _BCACHEFS_RECOVERY_H
 #define _BCACHEFS_RECOVERY_H
 
-extern const char * const bch2_recovery_passes[];
-
-u64 bch2_recovery_passes_to_stable(u64 v);
-u64 bch2_recovery_passes_from_stable(u64 v);
-
-/*
- * For when we need to rewind recovery passes and run a pass we skipped:
- */
-static inline int bch2_run_explicit_recovery_pass(struct bch_fs *c,
-                                                 enum bch_recovery_pass pass)
-{
-       if (c->recovery_passes_explicit & BIT_ULL(pass))
-               return 0;
-
-       bch_info(c, "running explicit recovery pass %s (%u), currently at %s (%u)",
-                bch2_recovery_passes[pass], pass,
-                bch2_recovery_passes[c->curr_recovery_pass], c->curr_recovery_pass);
-
-       c->recovery_passes_explicit |= BIT_ULL(pass);
-
-       if (c->curr_recovery_pass >= pass) {
-               c->curr_recovery_pass = pass;
-               c->recovery_passes_complete &= (1ULL << pass) >> 1;
-               return -BCH_ERR_restart_recovery;
-       } else {
-               return 0;
-       }
-}
-
-int bch2_run_online_recovery_passes(struct bch_fs *);
-u64 bch2_fsck_recovery_passes(void);
+int bch2_journal_replay(struct bch_fs *);
 
 int bch2_fs_recovery(struct bch_fs *);
 int bch2_fs_initialize(struct bch_fs *);
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+
+#include "bcachefs.h"
+#include "alloc_background.h"
+#include "backpointers.h"
+#include "btree_gc.h"
+#include "ec.h"
+#include "fsck.h"
+#include "inode.h"
+#include "journal.h"
+#include "lru.h"
+#include "logged_ops.h"
+#include "rebalance.h"
+#include "recovery.h"
+#include "recovery_passes.h"
+#include "snapshot.h"
+#include "subvolume.h"
+#include "super.h"
+
+const char * const bch2_recovery_passes[] = {
+#define x(_fn, ...)    #_fn,
+       BCH_RECOVERY_PASSES()
+#undef x
+       NULL
+};
+
+static int bch2_check_allocations(struct bch_fs *c)
+{
+       return bch2_gc(c, true, c->opts.norecovery);
+}
+
+static int bch2_set_may_go_rw(struct bch_fs *c)
+{
+       struct journal_keys *keys = &c->journal_keys;
+
+       /*
+        * After we go RW, the journal keys buffer can't be modified (except for
+        * setting journal_key->overwritten: it will be accessed by multiple
+        * threads
+        */
+       move_gap(keys, keys->nr);
+
+       set_bit(BCH_FS_may_go_rw, &c->flags);
+
+       if (keys->nr || c->opts.fsck || !c->sb.clean)
+               return bch2_fs_read_write_early(c);
+       return 0;
+}
+
+struct recovery_pass_fn {
+       int             (*fn)(struct bch_fs *);
+       unsigned        when;
+};
+
+static struct recovery_pass_fn recovery_pass_fns[] = {
+#define x(_fn, _id, _when)     { .fn = bch2_##_fn, .when = _when },
+       BCH_RECOVERY_PASSES()
+#undef x
+};
+
+u64 bch2_recovery_passes_to_stable(u64 v)
+{
+       static const u8 map[] = {
+#define x(n, id, ...)  [BCH_RECOVERY_PASS_##n] = BCH_RECOVERY_PASS_STABLE_##n,
+       BCH_RECOVERY_PASSES()
+#undef x
+       };
+
+       u64 ret = 0;
+       for (unsigned i = 0; i < ARRAY_SIZE(map); i++)
+               if (v & BIT_ULL(i))
+                       ret |= BIT_ULL(map[i]);
+       return ret;
+}
+
+u64 bch2_recovery_passes_from_stable(u64 v)
+{
+       static const u8 map[] = {
+#define x(n, id, ...)  [BCH_RECOVERY_PASS_STABLE_##n] = BCH_RECOVERY_PASS_##n,
+       BCH_RECOVERY_PASSES()
+#undef x
+       };
+
+       u64 ret = 0;
+       for (unsigned i = 0; i < ARRAY_SIZE(map); i++)
+               if (v & BIT_ULL(i))
+                       ret |= BIT_ULL(map[i]);
+       return ret;
+}
+
+/*
+ * For when we need to rewind recovery passes and run a pass we skipped:
+ */
+int bch2_run_explicit_recovery_pass(struct bch_fs *c,
+                                   enum bch_recovery_pass pass)
+{
+       if (c->recovery_passes_explicit & BIT_ULL(pass))
+               return 0;
+
+       bch_info(c, "running explicit recovery pass %s (%u), currently at %s (%u)",
+                bch2_recovery_passes[pass], pass,
+                bch2_recovery_passes[c->curr_recovery_pass], c->curr_recovery_pass);
+
+       c->recovery_passes_explicit |= BIT_ULL(pass);
+
+       if (c->curr_recovery_pass >= pass) {
+               c->curr_recovery_pass = pass;
+               c->recovery_passes_complete &= (1ULL << pass) >> 1;
+               return -BCH_ERR_restart_recovery;
+       } else {
+               return 0;
+       }
+}
+
+u64 bch2_fsck_recovery_passes(void)
+{
+       u64 ret = 0;
+
+       for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++)
+               if (recovery_pass_fns[i].when & PASS_FSCK)
+                       ret |= BIT_ULL(i);
+       return ret;
+}
+
+static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
+{
+       struct recovery_pass_fn *p = recovery_pass_fns + pass;
+
+       if (c->opts.norecovery && pass > BCH_RECOVERY_PASS_snapshots_read)
+               return false;
+       if (c->recovery_passes_explicit & BIT_ULL(pass))
+               return true;
+       if ((p->when & PASS_FSCK) && c->opts.fsck)
+               return true;
+       if ((p->when & PASS_UNCLEAN) && !c->sb.clean)
+               return true;
+       if (p->when & PASS_ALWAYS)
+               return true;
+       return false;
+}
+
+static int bch2_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
+{
+       struct recovery_pass_fn *p = recovery_pass_fns + pass;
+       int ret;
+
+       if (!(p->when & PASS_SILENT))
+               bch2_print(c, KERN_INFO bch2_log_msg(c, "%s..."),
+                          bch2_recovery_passes[pass]);
+       ret = p->fn(c);
+       if (ret)
+               return ret;
+       if (!(p->when & PASS_SILENT))
+               bch2_print(c, KERN_CONT " done\n");
+
+       return 0;
+}
+
+int bch2_run_online_recovery_passes(struct bch_fs *c)
+{
+       int ret = 0;
+
+       for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++) {
+               struct recovery_pass_fn *p = recovery_pass_fns + i;
+
+               if (!(p->when & PASS_ONLINE))
+                       continue;
+
+               ret = bch2_run_recovery_pass(c, i);
+               if (bch2_err_matches(ret, BCH_ERR_restart_recovery)) {
+                       i = c->curr_recovery_pass;
+                       continue;
+               }
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+int bch2_run_recovery_passes(struct bch_fs *c)
+{
+       int ret = 0;
+
+       while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
+               if (should_run_recovery_pass(c, c->curr_recovery_pass)) {
+                       unsigned pass = c->curr_recovery_pass;
+
+                       ret = bch2_run_recovery_pass(c, c->curr_recovery_pass);
+                       if (bch2_err_matches(ret, BCH_ERR_restart_recovery) ||
+                           (ret && c->curr_recovery_pass < pass))
+                               continue;
+                       if (ret)
+                               break;
+
+                       c->recovery_passes_complete |= BIT_ULL(c->curr_recovery_pass);
+               }
+               c->curr_recovery_pass++;
+               c->recovery_pass_done = max(c->recovery_pass_done, c->curr_recovery_pass);
+       }
+
+       return ret;
+}
 
--- /dev/null
+#ifndef _BCACHEFS_RECOVERY_PASSES_H
+#define _BCACHEFS_RECOVERY_PASSES_H
+
+extern const char * const bch2_recovery_passes[];
+
+u64 bch2_recovery_passes_to_stable(u64 v);
+u64 bch2_recovery_passes_from_stable(u64 v);
+
+u64 bch2_fsck_recovery_passes(void);
+
+int bch2_run_explicit_recovery_pass(struct bch_fs *, enum bch_recovery_pass);
+
+int bch2_run_online_recovery_passes(struct bch_fs *);
+int bch2_run_recovery_passes(struct bch_fs *);
+
+#endif /* _BCACHEFS_RECOVERY_PASSES_H */
 
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _BCACHEFS_RECOVERY_TYPES_H
-#define _BCACHEFS_RECOVERY_TYPES_H
+#ifndef _BCACHEFS_RECOVERY_PASSES_TYPES_H
+#define _BCACHEFS_RECOVERY_PASSES_TYPES_H
 
 #define PASS_SILENT            BIT(0)
 #define PASS_FSCK              BIT(1)
 #define x(n, id, when) BCH_RECOVERY_PASS_##n,
        BCH_RECOVERY_PASSES()
 #undef x
+       BCH_RECOVERY_PASS_NR
 };
 
 /* But we also need stable identifiers that can be used in the superblock */
 #undef x
 };
 
-#endif /* _BCACHEFS_RECOVERY_TYPES_H */
+#endif /* _BCACHEFS_RECOVERY_PASSES_TYPES_H */
 
 
 #include "bcachefs.h"
 #include "darray.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "sb-downgrade.h"
 #include "sb-errors.h"
 #include "super-io.h"
 
        return ret;
 }
 
+int bch2_initialize_subvolumes(struct bch_fs *c)
+{
+       struct bkey_i_snapshot_tree     root_tree;
+       struct bkey_i_snapshot          root_snapshot;
+       struct bkey_i_subvolume         root_volume;
+       int ret;
+
+       bkey_snapshot_tree_init(&root_tree.k_i);
+       root_tree.k.p.offset            = 1;
+       root_tree.v.master_subvol       = cpu_to_le32(1);
+       root_tree.v.root_snapshot       = cpu_to_le32(U32_MAX);
+
+       bkey_snapshot_init(&root_snapshot.k_i);
+       root_snapshot.k.p.offset = U32_MAX;
+       root_snapshot.v.flags   = 0;
+       root_snapshot.v.parent  = 0;
+       root_snapshot.v.subvol  = cpu_to_le32(BCACHEFS_ROOT_SUBVOL);
+       root_snapshot.v.tree    = cpu_to_le32(1);
+       SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot.v, true);
+
+       bkey_subvolume_init(&root_volume.k_i);
+       root_volume.k.p.offset = BCACHEFS_ROOT_SUBVOL;
+       root_volume.v.flags     = 0;
+       root_volume.v.snapshot  = cpu_to_le32(U32_MAX);
+       root_volume.v.inode     = cpu_to_le64(BCACHEFS_ROOT_INO);
+
+       ret =   bch2_btree_insert(c, BTREE_ID_snapshot_trees,   &root_tree.k_i, NULL, 0) ?:
+               bch2_btree_insert(c, BTREE_ID_snapshots,        &root_snapshot.k_i, NULL, 0) ?:
+               bch2_btree_insert(c, BTREE_ID_subvolumes,       &root_volume.k_i, NULL, 0);
+       bch_err_fn(c, ret);
+       return ret;
+}
+
+static int __bch2_fs_upgrade_for_subvolumes(struct btree_trans *trans)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       struct bch_inode_unpacked inode;
+       int ret;
+
+       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
+                              SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0);
+       ret = bkey_err(k);
+       if (ret)
+               return ret;
+
+       if (!bkey_is_inode(k.k)) {
+               bch_err(trans->c, "root inode not found");
+               ret = -BCH_ERR_ENOENT_inode;
+               goto err;
+       }
+
+       ret = bch2_inode_unpack(k, &inode);
+       BUG_ON(ret);
+
+       inode.bi_subvol = BCACHEFS_ROOT_SUBVOL;
+
+       ret = bch2_inode_write(trans, &iter, &inode);
+err:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
+
+/* set bi_subvol on root inode */
+int bch2_fs_upgrade_for_subvolumes(struct bch_fs *c)
+{
+       int ret = bch2_trans_do(c, NULL, NULL, BCH_TRANS_COMMIT_lazy_rw,
+                               __bch2_fs_upgrade_for_subvolumes(trans));
+       bch_err_fn(c, ret);
+       return ret;
+}
+
 int bch2_fs_subvolumes_init(struct bch_fs *c)
 {
        INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work);
 
 int bch2_subvolume_unlink(struct btree_trans *, u32);
 int bch2_subvolume_create(struct btree_trans *, u64, u32, u32, u32 *, u32 *, bool);
 
+int bch2_initialize_subvolumes(struct bch_fs *);
+int bch2_fs_upgrade_for_subvolumes(struct bch_fs *);
+
 int bch2_fs_subvolumes_init(struct bch_fs *);
 
 #endif /* _BCACHEFS_SUBVOLUME_H */
 
 #include "journal.h"
 #include "journal_sb.h"
 #include "journal_seq_blacklist.h"
-#include "recovery.h"
+#include "recovery_passes.h"
 #include "replicas.h"
 #include "quota.h"
 #include "sb-clean.h"