#define BCH_VERSION_MINOR(_v)          ((__u16) ((_v) & ~(~0U << 10)))
 #define BCH_VERSION(_major, _minor)    (((_major) << 10)|(_minor) << 0)
 
-#define RECOVERY_PASS_ALL_FSCK         (1ULL << 63)
-
 /*
  * field 1:            version name
  * field 2:            BCH_VERSION(major, minor)
  * field 3:            recovery passess required on upgrade
  */
 #define BCH_METADATA_VERSIONS()                                                \
-       x(bkey_renumber,                BCH_VERSION(0, 10),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(inode_btree_change,           BCH_VERSION(0, 11),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(snapshot,                     BCH_VERSION(0, 12),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(inode_backpointers,           BCH_VERSION(0, 13),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(btree_ptr_sectors_written,    BCH_VERSION(0, 14),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(snapshot_2,                   BCH_VERSION(0, 15),             \
-         BIT_ULL(BCH_RECOVERY_PASS_fs_upgrade_for_subvolumes)|         \
-         BIT_ULL(BCH_RECOVERY_PASS_initialize_subvolumes)|             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(reflink_p_fix,                BCH_VERSION(0, 16),             \
-         BIT_ULL(BCH_RECOVERY_PASS_fix_reflink_p))                     \
-       x(subvol_dirent,                BCH_VERSION(0, 17),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(inode_v2,                     BCH_VERSION(0, 18),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(freespace,                    BCH_VERSION(0, 19),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(alloc_v4,                     BCH_VERSION(0, 20),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(new_data_types,               BCH_VERSION(0, 21),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(backpointers,                 BCH_VERSION(0, 22),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(inode_v3,                     BCH_VERSION(0, 23),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(unwritten_extents,            BCH_VERSION(0, 24),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(bucket_gens,                  BCH_VERSION(0, 25),             \
-         BIT_ULL(BCH_RECOVERY_PASS_bucket_gens_init)|                  \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(lru_v2,                       BCH_VERSION(0, 26),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(fragmentation_lru,            BCH_VERSION(0, 27),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(no_bps_in_alloc_keys,         BCH_VERSION(0, 28),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(snapshot_trees,               BCH_VERSION(0, 29),             \
-         RECOVERY_PASS_ALL_FSCK)                                       \
-       x(major_minor,                  BCH_VERSION(1,  0),             \
-         0)                                                            \
-       x(snapshot_skiplists,           BCH_VERSION(1,  1),             \
-         BIT_ULL(BCH_RECOVERY_PASS_check_snapshots))                   \
-       x(deleted_inodes,               BCH_VERSION(1,  2),             \
-         BIT_ULL(BCH_RECOVERY_PASS_check_inodes))                      \
-       x(rebalance_work,               BCH_VERSION(1,  3),             \
-         BIT_ULL(BCH_RECOVERY_PASS_set_fs_needs_rebalance))            \
-       x(member_seq,                   BCH_VERSION(1,  4),             \
-         0)
+       x(bkey_renumber,                BCH_VERSION(0, 10))             \
+       x(inode_btree_change,           BCH_VERSION(0, 11))             \
+       x(snapshot,                     BCH_VERSION(0, 12))             \
+       x(inode_backpointers,           BCH_VERSION(0, 13))             \
+       x(btree_ptr_sectors_written,    BCH_VERSION(0, 14))             \
+       x(snapshot_2,                   BCH_VERSION(0, 15))             \
+       x(reflink_p_fix,                BCH_VERSION(0, 16))             \
+       x(subvol_dirent,                BCH_VERSION(0, 17))             \
+       x(inode_v2,                     BCH_VERSION(0, 18))             \
+       x(freespace,                    BCH_VERSION(0, 19))             \
+       x(alloc_v4,                     BCH_VERSION(0, 20))             \
+       x(new_data_types,               BCH_VERSION(0, 21))             \
+       x(backpointers,                 BCH_VERSION(0, 22))             \
+       x(inode_v3,                     BCH_VERSION(0, 23))             \
+       x(unwritten_extents,            BCH_VERSION(0, 24))             \
+       x(bucket_gens,                  BCH_VERSION(0, 25))             \
+       x(lru_v2,                       BCH_VERSION(0, 26))             \
+       x(fragmentation_lru,            BCH_VERSION(0, 27))             \
+       x(no_bps_in_alloc_keys,         BCH_VERSION(0, 28))             \
+       x(snapshot_trees,               BCH_VERSION(0, 29))             \
+       x(major_minor,                  BCH_VERSION(1,  0))             \
+       x(snapshot_skiplists,           BCH_VERSION(1,  1))             \
+       x(deleted_inodes,               BCH_VERSION(1,  2))             \
+       x(rebalance_work,               BCH_VERSION(1,  3))             \
+       x(member_seq,                   BCH_VERSION(1,  4))
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
-#define x(t, n, upgrade_passes)        bcachefs_metadata_version_##t = n,
+#define x(t, n)        bcachefs_metadata_version_##t = n,
        BCH_METADATA_VERSIONS()
 #undef x
        bcachefs_metadata_version_max
 
        return ret;
 }
 
-static u64 check_version_upgrade(struct bch_fs *c)
+static bool check_version_upgrade(struct bch_fs *c)
 {
        unsigned latest_compatible = bch2_latest_compatible_version(c->sb.version);
        unsigned latest_version = bcachefs_metadata_version_current;
                bch2_version_to_text(&buf, new_version);
                prt_newline(&buf);
 
-               u64 recovery_passes = bch2_upgrade_recovery_passes(c, old_version, new_version);
-               if (recovery_passes) {
-                       prt_str(&buf, "  running recovery passes: ");
-                       prt_bitflags(&buf, bch2_recovery_passes, recovery_passes);
+               struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
+               __le64 passes = ext->recovery_passes_required[0];
+               bch2_sb_set_upgrade(c, old_version, new_version);
+               passes = ext->recovery_passes_required[0] & ~passes;
 
-                       struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
-                       ext->recovery_passes_required[0] |=
-                               cpu_to_le64(bch2_recovery_passes_to_stable(recovery_passes));
-                       c->opts.fix_errors = FSCK_FIX_yes;
+               if (passes) {
+                       prt_str(&buf, "  running recovery passes: ");
+                       prt_bitflags(&buf, bch2_recovery_passes,
+                                    bch2_recovery_passes_from_stable(le64_to_cpu(passes)));
                }
 
                bch_info(c, "%s", buf.buf);
 
 #include "sb-errors.h"
 #include "super-io.h"
 
+#define RECOVERY_PASS_ALL_FSCK         BIT_ULL(63)
+
 /*
- * Downgrade table:
- * When dowgrading past certain versions, we need to run certain recovery passes
- * and fix certain errors:
+ * Upgrade, downgrade tables - run certain recovery passes, fix certain errors
  *
  * x(version, recovery_passes, errors...)
  */
+#define UPGRADE_TABLE()                                                \
+       x(backpointers,                                         \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(inode_v3,                                             \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(unwritten_extents,                                    \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(bucket_gens,                                          \
+         BIT_ULL(BCH_RECOVERY_PASS_bucket_gens_init)|          \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(lru_v2,                                               \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(fragmentation_lru,                                    \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(no_bps_in_alloc_keys,                                 \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(snapshot_trees,                                       \
+         RECOVERY_PASS_ALL_FSCK)                               \
+       x(snapshot_skiplists,                                   \
+         BIT_ULL(BCH_RECOVERY_PASS_check_snapshots))           \
+       x(deleted_inodes,                                       \
+         BIT_ULL(BCH_RECOVERY_PASS_check_inodes),              \
+         BCH_FSCK_ERR_unlinked_inode_not_on_deleted_list)      \
+       x(rebalance_work,                                       \
+         BIT_ULL(BCH_RECOVERY_PASS_set_fs_needs_rebalance))
 
 #define DOWNGRADE_TABLE()
 
-struct downgrade_entry {
+struct upgrade_downgrade_entry {
        u64             recovery_passes;
        u16             version;
        u16             nr_errors;
        const u16       *errors;
 };
 
-#define x(ver, passes, ...) static const u16 ver_##errors[] = { __VA_ARGS__ };
+#define x(ver, passes, ...) static const u16 upgrade_##ver##_errors[] = { __VA_ARGS__ };
+UPGRADE_TABLE()
+#undef x
+
+static const struct upgrade_downgrade_entry upgrade_table[] = {
+#define x(ver, passes, ...) {                                  \
+       .recovery_passes        = passes,                       \
+       .version                = bcachefs_metadata_version_##ver,\
+       .nr_errors              = ARRAY_SIZE(upgrade_##ver##_errors),   \
+       .errors                 = upgrade_##ver##_errors,       \
+},
+UPGRADE_TABLE()
+#undef x
+};
+
+void bch2_sb_set_upgrade(struct bch_fs *c,
+                        unsigned old_version,
+                        unsigned new_version)
+{
+       lockdep_assert_held(&c->sb_lock);
+
+       struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
+
+       for (const struct upgrade_downgrade_entry *i = upgrade_table;
+            i < upgrade_table + ARRAY_SIZE(upgrade_table);
+            i++)
+               if (i->version > old_version && i->version <= new_version) {
+                       u64 passes = i->recovery_passes;
+
+                       if (passes & RECOVERY_PASS_ALL_FSCK)
+                               passes |= bch2_fsck_recovery_passes();
+                       passes &= ~RECOVERY_PASS_ALL_FSCK;
+
+                       ext->recovery_passes_required[0] |=
+                               cpu_to_le64(bch2_recovery_passes_to_stable(passes));
+
+                       for (const u16 *e = i->errors;
+                            e < i->errors + i->nr_errors;
+                            e++) {
+                               __set_bit(*e, c->sb.errors_silent);
+                               ext->errors_silent[*e / 64] |= cpu_to_le64(BIT_ULL(*e % 64));
+                       }
+               }
+}
+
+#define x(ver, passes, ...) static const u16 downgrade_ver_##errors[] = { __VA_ARGS__ };
 DOWNGRADE_TABLE()
 #undef x
 
-static const struct downgrade_entry downgrade_table[] = {
+static const struct upgrade_downgrade_entry downgrade_table[] = {
 #define x(ver, passes, ...) {                                  \
        .recovery_passes        = passes,                       \
        .version                = bcachefs_metadata_version_##ver,\
-       .nr_errors              = ARRAY_SIZE(ver_##errors),     \
-       .errors                 = ver_##errors,                 \
+       .nr_errors              = ARRAY_SIZE(downgrade_##ver##_errors), \
+       .errors                 = downgrade_##ver##_errors,     \
 },
 DOWNGRADE_TABLE()
 #undef x
        darray_char table = {};
        int ret = 0;
 
-       for (const struct downgrade_entry *src = downgrade_table;
+       for (const struct upgrade_downgrade_entry *src = downgrade_table;
             src < downgrade_table + ARRAY_SIZE(downgrade_table);
             src++) {
                if (BCH_VERSION_MAJOR(src->version) != BCH_VERSION_MAJOR(le16_to_cpu(c->disk_sb.sb->version)))