2023-12-29 15:25:07 -05:00
// SPDX-License-Identifier: GPL-2.0
/*
* Superblock section that contains a list of recovery passes to run when
* downgrading past a given version
*/
# include "bcachefs.h"
# include "darray.h"
# include "recovery.h"
# include "sb-downgrade.h"
# include "sb-errors.h"
# include "super-io.h"
2024-01-03 21:01:37 -05:00
# define RECOVERY_PASS_ALL_FSCK BIT_ULL(63)
2023-12-29 15:25:07 -05:00
/*
2024-01-03 21:01:37 -05:00
* Upgrade , downgrade tables - run certain recovery passes , fix certain errors
2023-12-29 15:25:07 -05:00
*
* x ( version , recovery_passes , errors . . . )
*/
2024-01-03 21:01:37 -05:00
# 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 , \
2024-01-03 23:29:02 -05:00
BIT_ULL ( BCH_RECOVERY_PASS_check_snapshots ) , \
BCH_FSCK_ERR_snapshot_bad_depth , \
BCH_FSCK_ERR_snapshot_bad_skiplist ) \
2024-01-03 21:01:37 -05:00
x ( deleted_inodes , \
BIT_ULL ( BCH_RECOVERY_PASS_check_inodes ) , \
BCH_FSCK_ERR_unlinked_inode_not_on_deleted_list ) \
x ( rebalance_work , \
2024-02-08 18:39:42 -05:00
BIT_ULL ( BCH_RECOVERY_PASS_set_fs_needs_rebalance ) ) \
x ( subvolume_fs_parent , \
BIT_ULL ( BCH_RECOVERY_PASS_check_dirents ) , \
2024-01-21 06:00:07 -05:00
BCH_FSCK_ERR_subvol_fs_path_parent_wrong ) \
x ( btree_subvolume_children , \
BIT_ULL ( BCH_RECOVERY_PASS_check_subvols ) , \
BCH_FSCK_ERR_subvol_children_not_set )
2023-12-29 15:25:07 -05:00
# define DOWNGRADE_TABLE()
2024-01-03 21:01:37 -05:00
struct upgrade_downgrade_entry {
2023-12-29 15:25:07 -05:00
u64 recovery_passes ;
u16 version ;
u16 nr_errors ;
const u16 * errors ;
} ;
2024-01-03 21:01:37 -05:00
# 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__ };
2023-12-29 15:25:07 -05:00
DOWNGRADE_TABLE ( )
# undef x
2024-01-03 21:01:37 -05:00
static const struct upgrade_downgrade_entry downgrade_table [ ] = {
2023-12-29 15:25:07 -05:00
# define x(ver, passes, ...) { \
. recovery_passes = passes , \
. version = bcachefs_metadata_version_ # # ver , \
2024-01-03 21:01:37 -05:00
. nr_errors = ARRAY_SIZE ( downgrade_ # # ver # # _errors ) , \
. errors = downgrade_ # # ver # # _errors , \
2023-12-29 15:25:07 -05:00
} ,
DOWNGRADE_TABLE ( )
# undef x
} ;
static inline const struct bch_sb_field_downgrade_entry *
downgrade_entry_next_c ( const struct bch_sb_field_downgrade_entry * e )
{
return ( void * ) & e - > errors [ le16_to_cpu ( e - > nr_errors ) ] ;
}
# define for_each_downgrade_entry(_d, _i) \
for ( const struct bch_sb_field_downgrade_entry * _i = ( _d ) - > entries ; \
( void * ) _i < vstruct_end ( & ( _d ) - > field ) & & \
( void * ) & _i - > errors [ 0 ] < vstruct_end ( & ( _d ) - > field ) ; \
_i = downgrade_entry_next_c ( _i ) )
static int bch2_sb_downgrade_validate ( struct bch_sb * sb , struct bch_sb_field * f ,
struct printbuf * err )
{
struct bch_sb_field_downgrade * e = field_to_type ( f , downgrade ) ;
for_each_downgrade_entry ( e , i ) {
if ( BCH_VERSION_MAJOR ( le16_to_cpu ( i - > version ) ) ! =
BCH_VERSION_MAJOR ( le16_to_cpu ( sb - > version ) ) ) {
prt_printf ( err , " downgrade entry with mismatched major version (%u != %u) " ,
BCH_VERSION_MAJOR ( le16_to_cpu ( i - > version ) ) ,
BCH_VERSION_MAJOR ( le16_to_cpu ( sb - > version ) ) ) ;
return - BCH_ERR_invalid_sb_downgrade ;
}
}
return 0 ;
}
static void bch2_sb_downgrade_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
{
struct bch_sb_field_downgrade * e = field_to_type ( f , downgrade ) ;
if ( out - > nr_tabstops < = 1 )
printbuf_tabstop_push ( out , 16 ) ;
for_each_downgrade_entry ( e , i ) {
prt_str ( out , " version: " ) ;
prt_tab ( out ) ;
bch2_version_to_text ( out , le16_to_cpu ( i - > version ) ) ;
prt_newline ( out ) ;
prt_str ( out , " recovery passes: " ) ;
prt_tab ( out ) ;
prt_bitflags ( out , bch2_recovery_passes ,
bch2_recovery_passes_from_stable ( le64_to_cpu ( i - > recovery_passes [ 0 ] ) ) ) ;
prt_newline ( out ) ;
prt_str ( out , " errors: " ) ;
prt_tab ( out ) ;
bool first = true ;
for ( unsigned j = 0 ; j < le16_to_cpu ( i - > nr_errors ) ; j + + ) {
if ( ! first )
prt_char ( out , ' , ' ) ;
first = false ;
unsigned e = le16_to_cpu ( i - > errors [ j ] ) ;
prt_str ( out , e < BCH_SB_ERR_MAX ? bch2_sb_error_strs [ e ] : " (unknown) " ) ;
}
prt_newline ( out ) ;
}
}
const struct bch_sb_field_ops bch_sb_field_ops_downgrade = {
. validate = bch2_sb_downgrade_validate ,
. to_text = bch2_sb_downgrade_to_text ,
} ;
int bch2_sb_downgrade_update ( struct bch_fs * c )
{
darray_char table = { } ;
int ret = 0 ;
2024-01-03 21:01:37 -05:00
for ( const struct upgrade_downgrade_entry * src = downgrade_table ;
2023-12-29 15:25:07 -05:00
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 ) ) )
continue ;
struct bch_sb_field_downgrade_entry * dst ;
unsigned bytes = sizeof ( * dst ) + sizeof ( dst - > errors [ 0 ] ) * src - > nr_errors ;
ret = darray_make_room ( & table , bytes ) ;
if ( ret )
goto out ;
dst = ( void * ) & darray_top ( table ) ;
dst - > version = cpu_to_le16 ( src - > version ) ;
dst - > recovery_passes [ 0 ] = cpu_to_le64 ( src - > recovery_passes ) ;
dst - > recovery_passes [ 1 ] = 0 ;
dst - > nr_errors = cpu_to_le16 ( src - > nr_errors ) ;
for ( unsigned i = 0 ; i < src - > nr_errors ; i + + )
dst - > errors [ i ] = cpu_to_le16 ( src - > errors [ i ] ) ;
table . nr + = bytes ;
}
struct bch_sb_field_downgrade * d = bch2_sb_field_get ( c - > disk_sb . sb , downgrade ) ;
unsigned sb_u64s = DIV_ROUND_UP ( sizeof ( * d ) + table . nr , sizeof ( u64 ) ) ;
if ( d & & le32_to_cpu ( d - > field . u64s ) > sb_u64s )
goto out ;
d = bch2_sb_field_resize ( & c - > disk_sb , downgrade , sb_u64s ) ;
if ( ! d ) {
ret = - BCH_ERR_ENOSPC_sb_downgrade ;
goto out ;
}
memcpy ( d - > entries , table . data , table . nr ) ;
memset_u64s_tail ( d - > entries , 0 , table . nr ) ;
out :
darray_exit ( & table ) ;
return ret ;
}
void bch2_sb_set_downgrade ( struct bch_fs * c , unsigned new_minor , unsigned old_minor )
{
struct bch_sb_field_downgrade * d = bch2_sb_field_get ( c - > disk_sb . sb , downgrade ) ;
if ( ! d )
return ;
struct bch_sb_field_ext * ext = bch2_sb_field_get ( c - > disk_sb . sb , ext ) ;
for_each_downgrade_entry ( d , i ) {
unsigned minor = BCH_VERSION_MINOR ( le16_to_cpu ( i - > version ) ) ;
if ( new_minor < minor & & minor < = old_minor ) {
ext - > recovery_passes_required [ 0 ] | = i - > recovery_passes [ 0 ] ;
ext - > recovery_passes_required [ 1 ] | = i - > recovery_passes [ 1 ] ;
for ( unsigned j = 0 ; j < le16_to_cpu ( i - > nr_errors ) ; j + + ) {
unsigned e = le16_to_cpu ( i - > errors [ j ] ) ;
if ( e < BCH_SB_ERR_MAX )
__set_bit ( e , c - > sb . errors_silent ) ;
if ( e < sizeof ( ext - > errors_silent ) * 8 )
2024-03-11 21:15:26 -04:00
__set_bit_le64 ( e , ext - > errors_silent ) ;
2023-12-29 15:25:07 -05:00
}
}
}
}