2017-03-17 09:18:50 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "checksum.h"
# include "disk_groups.h"
2018-11-01 22:13:19 +03:00
# include "ec.h"
2017-03-17 09:18:50 +03:00
# include "error.h"
# include "journal.h"
2022-03-11 00:43:52 +03:00
# include "journal_sb.h"
2019-04-05 04:53:12 +03:00
# include "journal_seq_blacklist.h"
2024-03-24 03:07:46 +03:00
# include "recovery_passes.h"
2017-03-17 09:18:50 +03:00
# include "replicas.h"
# include "quota.h"
2023-08-05 22:54:38 +03:00
# include "sb-clean.h"
2024-01-21 07:46:35 +03:00
# include "sb-counters.h"
2023-12-29 23:25:07 +03:00
# include "sb-downgrade.h"
2023-10-25 22:51:16 +03:00
# include "sb-errors.h"
2023-08-05 22:40:21 +03:00
# include "sb-members.h"
2017-03-17 09:18:50 +03:00
# include "super-io.h"
# include "super.h"
2022-04-03 22:13:20 +03:00
# include "trace.h"
2017-03-17 09:18:50 +03:00
# include "vstructs.h"
# include <linux/backing-dev.h>
# include <linux/sort.h>
static const struct blk_holder_ops bch2_sb_handle_bdev_ops = {
} ;
2023-07-10 20:42:26 +03:00
struct bch2_metadata_version {
2023-06-28 05:09:35 +03:00
u16 version ;
const char * name ;
} ;
2023-07-10 20:42:26 +03:00
static const struct bch2_metadata_version bch2_metadata_versions [ ] = {
2024-01-04 05:01:37 +03:00
# define x(n, v) { \
2023-07-10 20:42:26 +03:00
. version = v , \
. name = # n , \
} ,
2023-06-29 02:53:05 +03:00
BCH_METADATA_VERSIONS ( )
# undef x
} ;
void bch2_version_to_text ( struct printbuf * out , unsigned v )
{
2023-06-28 05:09:35 +03:00
const char * str = " (unknown version) " ;
for ( unsigned i = 0 ; i < ARRAY_SIZE ( bch2_metadata_versions ) ; i + + )
if ( bch2_metadata_versions [ i ] . version = = v ) {
str = bch2_metadata_versions [ i ] . name ;
break ;
}
prt_printf ( out , " %u.%u: %s " , BCH_VERSION_MAJOR ( v ) , BCH_VERSION_MINOR ( v ) , str ) ;
}
unsigned bch2_latest_compatible_version ( unsigned v )
{
if ( ! BCH_VERSION_MAJOR ( v ) )
return v ;
for ( unsigned i = 0 ; i < ARRAY_SIZE ( bch2_metadata_versions ) ; i + + )
if ( bch2_metadata_versions [ i ] . version > v & &
BCH_VERSION_MAJOR ( bch2_metadata_versions [ i ] . version ) = =
BCH_VERSION_MAJOR ( v ) )
v = bch2_metadata_versions [ i ] . version ;
2023-06-29 02:53:05 +03:00
2023-06-28 05:09:35 +03:00
return v ;
2023-06-29 02:53:05 +03:00
}
2017-03-17 09:18:50 +03:00
const char * const bch2_sb_fields [ ] = {
# define x(name, nr) #name,
BCH_SB_FIELDS ( )
# undef x
NULL
} ;
2022-01-04 07:38:50 +03:00
static int bch2_sb_field_validate ( struct bch_sb * , struct bch_sb_field * ,
2024-05-09 01:49:14 +03:00
enum bch_validate_flags , struct printbuf * ) ;
2017-03-17 09:18:50 +03:00
2023-09-27 00:49:34 +03:00
struct bch_sb_field * bch2_sb_field_get_id ( struct bch_sb * sb ,
2017-03-17 09:18:50 +03:00
enum bch_sb_field_type type )
{
/* XXX: need locking around superblock to access optional fields */
vstruct_for_each ( sb , f )
if ( le32_to_cpu ( f - > type ) = = type )
return f ;
return NULL ;
}
static struct bch_sb_field * __bch2_sb_field_resize ( struct bch_sb_handle * sb ,
struct bch_sb_field * f ,
unsigned u64s )
{
unsigned old_u64s = f ? le32_to_cpu ( f - > u64s ) : 0 ;
unsigned sb_u64s = le32_to_cpu ( sb - > sb - > u64s ) + u64s - old_u64s ;
2021-04-06 21:00:56 +03:00
BUG_ON ( __vstruct_bytes ( struct bch_sb , sb_u64s ) > sb - > buffer_size ) ;
2017-03-17 09:18:50 +03:00
2019-12-19 01:34:36 +03:00
if ( ! f & & ! u64s ) {
/* nothing to do: */
} else if ( ! f ) {
2017-03-17 09:18:50 +03:00
f = vstruct_last ( sb - > sb ) ;
memset ( f , 0 , sizeof ( u64 ) * u64s ) ;
f - > u64s = cpu_to_le32 ( u64s ) ;
f - > type = 0 ;
} else {
void * src , * dst ;
src = vstruct_end ( f ) ;
2018-10-30 21:32:47 +03:00
if ( u64s ) {
f - > u64s = cpu_to_le32 ( u64s ) ;
dst = vstruct_end ( f ) ;
} else {
dst = f ;
}
2017-03-17 09:18:50 +03:00
memmove ( dst , src , vstruct_end ( sb - > sb ) - src ) ;
if ( dst > src )
memset ( src , 0 , dst - src ) ;
}
sb - > sb - > u64s = cpu_to_le32 ( sb_u64s ) ;
2018-10-30 21:32:47 +03:00
return u64s ? f : NULL ;
}
void bch2_sb_field_delete ( struct bch_sb_handle * sb ,
enum bch_sb_field_type type )
{
2023-09-27 00:49:34 +03:00
struct bch_sb_field * f = bch2_sb_field_get_id ( sb - > sb , type ) ;
2018-10-30 21:32:47 +03:00
if ( f )
__bch2_sb_field_resize ( sb , f , 0 ) ;
2017-03-17 09:18:50 +03:00
}
/* Superblock realloc/free: */
void bch2_free_super ( struct bch_sb_handle * sb )
{
2022-10-20 01:31:33 +03:00
kfree ( sb - > bio ) ;
2024-01-23 16:26:35 +03:00
if ( ! IS_ERR_OR_NULL ( sb - > s_bdev_file ) )
2024-03-26 15:47:22 +03:00
bdev_fput ( sb - > s_bdev_file ) ;
2017-03-17 09:18:50 +03:00
kfree ( sb - > holder ) ;
2023-11-16 20:13:43 +03:00
kfree ( sb - > sb_name ) ;
2017-03-17 09:18:50 +03:00
2021-04-06 21:00:56 +03:00
kfree ( sb - > sb ) ;
2017-03-17 09:18:50 +03:00
memset ( sb , 0 , sizeof ( * sb ) ) ;
}
int bch2_sb_realloc ( struct bch_sb_handle * sb , unsigned u64s )
{
size_t new_bytes = __vstruct_bytes ( struct bch_sb , u64s ) ;
2021-04-06 21:00:56 +03:00
size_t new_buffer_size ;
2017-03-17 09:18:50 +03:00
struct bch_sb * new_sb ;
struct bio * bio ;
2021-04-06 21:00:56 +03:00
if ( sb - > bdev )
new_bytes = max_t ( size_t , new_bytes , bdev_logical_block_size ( sb - > bdev ) ) ;
new_buffer_size = roundup_pow_of_two ( new_bytes ) ;
if ( sb - > sb & & sb - > buffer_size > = new_buffer_size )
2017-03-17 09:18:50 +03:00
return 0 ;
2023-09-20 08:32:20 +03:00
if ( sb - > sb & & sb - > have_layout ) {
2017-03-17 09:18:50 +03:00
u64 max_bytes = 512 < < sb - > sb - > layout . sb_max_size_bits ;
if ( new_bytes > max_bytes ) {
2024-01-05 19:58:50 +03:00
struct printbuf buf = PRINTBUF ;
prt_bdevname ( & buf , sb - > bdev ) ;
prt_printf ( & buf , " : superblock too big: want %zu but have %llu " , new_bytes , max_bytes ) ;
pr_err ( " %s " , buf . buf ) ;
printbuf_exit ( & buf ) ;
2022-09-19 00:10:33 +03:00
return - BCH_ERR_ENOSPC_sb ;
2017-03-17 09:18:50 +03:00
}
}
2021-04-06 21:00:56 +03:00
if ( sb - > buffer_size > = new_buffer_size & & sb - > sb )
2017-03-17 09:18:50 +03:00
return 0 ;
if ( dynamic_fault ( " bcachefs:add:super_realloc " ) )
2023-03-14 22:35:57 +03:00
return - BCH_ERR_ENOMEM_sb_realloc_injected ;
2017-03-17 09:18:50 +03:00
2023-08-08 03:44:56 +03:00
new_sb = krealloc ( sb - > sb , new_buffer_size , GFP_NOFS | __GFP_ZERO ) ;
if ( ! new_sb )
return - BCH_ERR_ENOMEM_sb_buf_realloc ;
sb - > sb = new_sb ;
2017-03-17 09:18:50 +03:00
if ( sb - > have_bio ) {
2023-08-08 03:44:56 +03:00
unsigned nr_bvecs = buf_pages ( sb - > sb , new_buffer_size ) ;
2017-03-17 09:18:50 +03:00
bio = bio_kmalloc ( nr_bvecs , GFP_KERNEL ) ;
if ( ! bio )
2023-03-14 22:35:57 +03:00
return - BCH_ERR_ENOMEM_sb_bio_realloc ;
2017-03-17 09:18:50 +03:00
bio_init ( bio , NULL , bio - > bi_inline_vecs , nr_bvecs , 0 ) ;
2022-10-20 01:31:33 +03:00
kfree ( sb - > bio ) ;
2017-03-17 09:18:50 +03:00
sb - > bio = bio ;
}
2021-04-06 21:00:56 +03:00
sb - > buffer_size = new_buffer_size ;
2017-03-17 09:18:50 +03:00
return 0 ;
}
2023-09-27 00:49:34 +03:00
struct bch_sb_field * bch2_sb_field_resize_id ( struct bch_sb_handle * sb ,
2017-03-17 09:18:50 +03:00
enum bch_sb_field_type type ,
unsigned u64s )
{
2023-09-27 00:49:34 +03:00
struct bch_sb_field * f = bch2_sb_field_get_id ( sb - > sb , type ) ;
2017-03-17 09:18:50 +03:00
ssize_t old_u64s = f ? le32_to_cpu ( f - > u64s ) : 0 ;
ssize_t d = - old_u64s + u64s ;
if ( bch2_sb_realloc ( sb , le32_to_cpu ( sb - > sb - > u64s ) + d ) )
return NULL ;
if ( sb - > fs_sb ) {
struct bch_fs * c = container_of ( sb , struct bch_fs , disk_sb ) ;
lockdep_assert_held ( & c - > sb_lock ) ;
/* XXX: we're not checking that offline device have enough space */
2023-12-17 07:47:29 +03:00
for_each_online_member ( c , ca ) {
2023-09-13 01:41:22 +03:00
struct bch_sb_handle * dev_sb = & ca - > disk_sb ;
2017-03-17 09:18:50 +03:00
2023-09-13 01:41:22 +03:00
if ( bch2_sb_realloc ( dev_sb , le32_to_cpu ( dev_sb - > sb - > u64s ) + d ) ) {
2024-05-04 00:13:21 +03:00
percpu_ref_put ( & ca - > io_ref ) ;
2017-03-17 09:18:50 +03:00
return NULL ;
}
}
}
2023-09-27 00:49:34 +03:00
f = bch2_sb_field_get_id ( sb - > sb , type ) ;
2017-03-17 09:18:50 +03:00
f = __bch2_sb_field_resize ( sb , f , u64s ) ;
2018-10-30 21:32:47 +03:00
if ( f )
f - > type = cpu_to_le32 ( type ) ;
2017-03-17 09:18:50 +03:00
return f ;
}
2023-12-29 23:15:14 +03:00
struct bch_sb_field * bch2_sb_field_get_minsize_id ( struct bch_sb_handle * sb ,
enum bch_sb_field_type type ,
unsigned u64s )
{
struct bch_sb_field * f = bch2_sb_field_get_id ( sb - > sb , type ) ;
if ( ! f | | le32_to_cpu ( f - > u64s ) < u64s )
f = bch2_sb_field_resize_id ( sb , type , u64s ) ;
return f ;
}
2017-03-17 09:18:50 +03:00
/* Superblock validate: */
2022-01-04 07:38:50 +03:00
static int validate_sb_layout ( struct bch_sb_layout * layout , struct printbuf * out )
2017-03-17 09:18:50 +03:00
{
u64 offset , prev_offset , max_sectors ;
unsigned i ;
2023-08-02 03:06:45 +03:00
BUILD_BUG_ON ( sizeof ( struct bch_sb_layout ) ! = 512 ) ;
2017-03-17 09:18:50 +03:00
if ( ! uuid_equal ( & layout - > magic , & BCACHE_MAGIC ) & &
2022-01-04 07:38:50 +03:00
! uuid_equal ( & layout - > magic , & BCHFS_MAGIC ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Not a bcachefs superblock layout " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_layout ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( layout - > layout_type ! = 0 ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock layout type %u " ,
2022-01-04 07:38:50 +03:00
layout - > layout_type ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_layout_type ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( ! layout - > nr_superblocks ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock layout: no superblocks " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_layout_nr_superblocks ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( layout - > nr_superblocks > ARRAY_SIZE ( layout - > sb_offset ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock layout: too many superblocks " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_layout_nr_superblocks ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
max_sectors = 1 < < layout - > sb_max_size_bits ;
prev_offset = le64_to_cpu ( layout - > sb_offset [ 0 ] ) ;
for ( i = 1 ; i < layout - > nr_superblocks ; i + + ) {
offset = le64_to_cpu ( layout - > sb_offset [ i ] ) ;
2022-01-04 07:38:50 +03:00
if ( offset < prev_offset + max_sectors ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock layout: superblocks overlap \n "
2022-01-04 07:38:50 +03:00
" (sb %u ends at %llu next starts at %llu " ,
i - 1 , prev_offset + max_sectors , offset ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_layout_superblocks_overlap ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
prev_offset = offset ;
}
2022-01-04 07:38:50 +03:00
return 0 ;
2017-03-17 09:18:50 +03:00
}
2023-06-29 03:27:07 +03:00
static int bch2_sb_compatible ( struct bch_sb * sb , struct printbuf * out )
2017-03-17 09:18:50 +03:00
{
2023-06-29 03:27:07 +03:00
u16 version = le16_to_cpu ( sb - > version ) ;
u16 version_min = le16_to_cpu ( sb - > version_min ) ;
if ( ! bch2_version_compatible ( version ) ) {
prt_str ( out , " Unsupported superblock version " ) ;
bch2_version_to_text ( out , version ) ;
prt_str ( out , " (min " ) ;
bch2_version_to_text ( out , bcachefs_metadata_version_min ) ;
prt_str ( out , " , max " ) ;
bch2_version_to_text ( out , bcachefs_metadata_version_current ) ;
prt_str ( out , " ) " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_version ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2023-06-29 03:27:07 +03:00
if ( ! bch2_version_compatible ( version_min ) ) {
prt_str ( out , " Unsupported superblock version_min " ) ;
bch2_version_to_text ( out , version_min ) ;
prt_str ( out , " (min " ) ;
bch2_version_to_text ( out , bcachefs_metadata_version_min ) ;
prt_str ( out , " , max " ) ;
bch2_version_to_text ( out , bcachefs_metadata_version_current ) ;
prt_str ( out , " ) " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_version ;
2022-01-04 07:38:50 +03:00
}
if ( version_min > version ) {
2023-06-29 03:27:07 +03:00
prt_str ( out , " Bad minimum version " ) ;
bch2_version_to_text ( out , version_min ) ;
prt_str ( out , " , greater than version field " ) ;
bch2_version_to_text ( out , version ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_version ;
2022-01-04 07:38:50 +03:00
}
2018-11-01 22:10:01 +03:00
2023-06-29 03:27:07 +03:00
return 0 ;
}
2024-05-09 01:49:14 +03:00
static int bch2_sb_validate ( struct bch_sb_handle * disk_sb ,
enum bch_validate_flags flags , struct printbuf * out )
2023-06-29 03:27:07 +03:00
{
struct bch_sb * sb = disk_sb - > sb ;
2023-09-25 07:06:32 +03:00
struct bch_sb_field_members_v1 * mi ;
2023-06-29 03:27:07 +03:00
enum bch_opt_id opt_id ;
u16 block_size ;
int ret ;
ret = bch2_sb_compatible ( sb , out ) ;
if ( ret )
return ret ;
2018-11-13 02:30:55 +03:00
if ( sb - > features [ 1 ] | |
2022-01-04 07:38:50 +03:00
( le64_to_cpu ( sb - > features [ 0 ] ) & ( ~ 0ULL < < BCH_FEATURE_NR ) ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Filesystem has incompatible features " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_features ;
2022-01-04 07:38:50 +03:00
}
2018-11-13 02:30:55 +03:00
2017-03-17 09:18:50 +03:00
block_size = le16_to_cpu ( sb - > block_size ) ;
2022-01-04 07:38:50 +03:00
if ( block_size > PAGE_SECTORS ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Block size too big (got %u, max %u) " ,
2022-01-04 07:38:50 +03:00
block_size , PAGE_SECTORS ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_block_size ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( bch2_is_zero ( sb - > user_uuid . b , sizeof ( sb - > user_uuid ) ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Bad user UUID (got zeroes) " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_uuid ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( bch2_is_zero ( sb - > uuid . b , sizeof ( sb - > uuid ) ) ) {
2023-09-12 11:25:27 +03:00
prt_printf ( out , " Bad internal UUID (got zeroes) " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_uuid ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
if ( ! sb - > nr_devices | |
2022-01-04 07:38:50 +03:00
sb - > nr_devices > BCH_SB_MEMBERS_MAX ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Bad number of member devices %u (max %u) " ,
2022-01-04 07:38:50 +03:00
sb - > nr_devices , BCH_SB_MEMBERS_MAX ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_too_many_members ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( sb - > dev_idx > = sb - > nr_devices ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Bad dev_idx (got %u, nr_devices %u) " ,
2022-01-04 07:38:50 +03:00
sb - > dev_idx , sb - > nr_devices ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_dev_idx ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
if ( ! sb - > time_precision | |
2022-01-04 07:38:50 +03:00
le32_to_cpu ( sb - > time_precision ) > NSEC_PER_SEC ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid time precision: %u (min 1, max %lu) " ,
2022-01-04 07:38:50 +03:00
le32_to_cpu ( sb - > time_precision ) , NSEC_PER_SEC ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_time_precision ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2024-05-09 01:49:14 +03:00
if ( ! flags ) {
2022-03-21 10:03:03 +03:00
/*
* Been seeing a bug where these are getting inexplicably
2023-06-29 03:27:07 +03:00
* zeroed , so we ' re now validating them , but we have to be
2022-03-21 10:03:03 +03:00
* careful not to preven people ' s filesystems from mounting :
*/
if ( ! BCH_SB_JOURNAL_FLUSH_DELAY ( sb ) )
SET_BCH_SB_JOURNAL_FLUSH_DELAY ( sb , 1000 ) ;
if ( ! BCH_SB_JOURNAL_RECLAIM_DELAY ( sb ) )
SET_BCH_SB_JOURNAL_RECLAIM_DELAY ( sb , 1000 ) ;
2023-07-16 04:03:26 +03:00
if ( ! BCH_SB_VERSION_UPGRADE_COMPLETE ( sb ) )
SET_BCH_SB_VERSION_UPGRADE_COMPLETE ( sb , le16_to_cpu ( sb - > version ) ) ;
2022-03-21 10:03:03 +03:00
}
2022-03-21 07:15:38 +03:00
for ( opt_id = 0 ; opt_id < bch2_opts_nr ; opt_id + + ) {
const struct bch_option * opt = bch2_opt_table + opt_id ;
if ( opt - > get_sb ! = BCH2_NO_SB_OPT ) {
u64 v = bch2_opt_from_sb ( sb , opt_id ) ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid option " ) ;
2022-03-21 07:15:38 +03:00
ret = bch2_opt_validate ( opt , v , out ) ;
if ( ret )
return ret ;
printbuf_reset ( out ) ;
}
}
2017-03-17 09:18:50 +03:00
/* validate layout */
2022-01-04 07:38:50 +03:00
ret = validate_sb_layout ( & sb - > layout , out ) ;
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
vstruct_for_each ( sb , f ) {
2022-01-04 07:38:50 +03:00
if ( ! f - > u64s ) {
2022-11-20 06:39:08 +03:00
prt_printf ( out , " Invalid superblock: optional field with size 0 (type %u) " ,
2022-01-04 07:38:50 +03:00
le32_to_cpu ( f - > type ) ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_field_size ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( vstruct_next ( f ) > vstruct_last ( sb ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock: optional field extends past end of superblock (type %u) " ,
2022-01-04 07:38:50 +03:00
le32_to_cpu ( f - > type ) ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_field_size ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
}
/* members must be validated first: */
2023-09-27 00:49:34 +03:00
mi = bch2_sb_field_get ( sb , members_v1 ) ;
2022-01-04 07:38:50 +03:00
if ( ! mi ) {
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Invalid superblock: member info area missing " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_members_missing ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2024-05-09 01:49:14 +03:00
ret = bch2_sb_field_validate ( sb , & mi - > field , flags , out ) ;
2022-01-04 07:38:50 +03:00
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
vstruct_for_each ( sb , f ) {
2023-09-25 07:06:32 +03:00
if ( le32_to_cpu ( f - > type ) = = BCH_SB_FIELD_members_v1 )
2017-03-17 09:18:50 +03:00
continue ;
2024-05-09 01:49:14 +03:00
ret = bch2_sb_field_validate ( sb , f , flags , out ) ;
2022-01-04 07:38:50 +03:00
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
}
2024-05-09 01:49:14 +03:00
if ( ( flags & BCH_VALIDATE_write ) & &
2024-03-09 00:10:08 +03:00
bch2_sb_member_get ( sb , sb - > dev_idx ) . seq ! = sb - > seq ) {
prt_printf ( out , " Invalid superblock: member seq %llu != sb seq %llu " ,
le64_to_cpu ( bch2_sb_member_get ( sb , sb - > dev_idx ) . seq ) ,
le64_to_cpu ( sb - > seq ) ) ;
return - BCH_ERR_invalid_sb_members_missing ;
}
2022-01-04 07:38:50 +03:00
return 0 ;
2017-03-17 09:18:50 +03:00
}
/* device open: */
2023-12-29 23:15:14 +03:00
static unsigned long le_ulong_to_cpu ( unsigned long v )
{
return sizeof ( unsigned long ) = = 8
? le64_to_cpu ( v )
: le32_to_cpu ( v ) ;
}
static void le_bitvector_to_cpu ( unsigned long * dst , unsigned long * src , unsigned nr )
{
BUG_ON ( nr & ( BITS_PER_TYPE ( long ) - 1 ) ) ;
for ( unsigned i = 0 ; i < BITS_TO_LONGS ( nr ) ; i + + )
dst [ i ] = le_ulong_to_cpu ( src [ i ] ) ;
}
2017-03-17 09:18:50 +03:00
static void bch2_sb_update ( struct bch_fs * c )
{
struct bch_sb * src = c - > disk_sb . sb ;
lockdep_assert_held ( & c - > sb_lock ) ;
c - > sb . uuid = src - > uuid ;
c - > sb . user_uuid = src - > user_uuid ;
2018-11-01 22:10:01 +03:00
c - > sb . version = le16_to_cpu ( src - > version ) ;
2021-03-21 23:03:23 +03:00
c - > sb . version_min = le16_to_cpu ( src - > version_min ) ;
2023-07-16 04:03:26 +03:00
c - > sb . version_upgrade_complete = BCH_SB_VERSION_UPGRADE_COMPLETE ( src ) ;
2017-03-17 09:18:50 +03:00
c - > sb . nr_devices = src - > nr_devices ;
c - > sb . clean = BCH_SB_CLEAN ( src ) ;
c - > sb . encryption_type = BCH_SB_ENCRYPTION_TYPE ( src ) ;
2021-04-29 05:51:42 +03:00
c - > sb . nsec_per_time_unit = le32_to_cpu ( src - > time_precision ) ;
c - > sb . time_units_per_sec = NSEC_PER_SEC / c - > sb . nsec_per_time_unit ;
/* XXX this is wrong, we need a 96 or 128 bit integer type */
c - > sb . time_base_lo = div_u64 ( le64_to_cpu ( src - > time_base_lo ) ,
c - > sb . nsec_per_time_unit ) ;
2017-03-17 09:18:50 +03:00
c - > sb . time_base_hi = le32_to_cpu ( src - > time_base_hi ) ;
2021-04-29 05:51:42 +03:00
2017-03-17 09:18:50 +03:00
c - > sb . features = le64_to_cpu ( src - > features [ 0 ] ) ;
2019-02-06 19:56:51 +03:00
c - > sb . compat = le64_to_cpu ( src - > compat [ 0 ] ) ;
2017-03-17 09:18:50 +03:00
2023-12-29 23:15:14 +03:00
memset ( c - > sb . errors_silent , 0 , sizeof ( c - > sb . errors_silent ) ) ;
struct bch_sb_field_ext * ext = bch2_sb_field_get ( src , ext ) ;
2024-03-16 06:03:42 +03:00
if ( ext ) {
2023-12-29 23:15:14 +03:00
le_bitvector_to_cpu ( c - > sb . errors_silent , ( void * ) ext - > errors_silent ,
sizeof ( c - > sb . errors_silent ) * 8 ) ;
2024-03-16 06:03:42 +03:00
c - > sb . btrees_lost_data = le64_to_cpu ( ext - > btrees_lost_data ) ;
}
2023-12-29 23:15:14 +03:00
2023-12-17 07:47:29 +03:00
for_each_member_device ( c , ca ) {
2023-12-29 23:15:14 +03:00
struct bch_member m = bch2_sb_member_get ( src , ca - > dev_idx ) ;
2023-09-25 06:55:37 +03:00
ca - > mi = bch2_mi_to_cpu ( & m ) ;
}
2017-03-17 09:18:50 +03:00
}
2023-02-13 06:08:39 +03:00
static int __copy_super ( struct bch_sb_handle * dst_handle , struct bch_sb * src )
2017-03-17 09:18:50 +03:00
{
struct bch_sb_field * src_f , * dst_f ;
struct bch_sb * dst = dst_handle - > sb ;
2018-10-30 21:32:47 +03:00
unsigned i ;
2017-03-17 09:18:50 +03:00
dst - > version = src - > version ;
2018-11-01 22:10:01 +03:00
dst - > version_min = src - > version_min ;
2017-03-17 09:18:50 +03:00
dst - > seq = src - > seq ;
dst - > uuid = src - > uuid ;
dst - > user_uuid = src - > user_uuid ;
memcpy ( dst - > label , src - > label , sizeof ( dst - > label ) ) ;
dst - > block_size = src - > block_size ;
dst - > nr_devices = src - > nr_devices ;
dst - > time_base_lo = src - > time_base_lo ;
dst - > time_base_hi = src - > time_base_hi ;
dst - > time_precision = src - > time_precision ;
2023-06-28 04:02:27 +03:00
dst - > write_time = src - > write_time ;
2017-03-17 09:18:50 +03:00
memcpy ( dst - > flags , src - > flags , sizeof ( dst - > flags ) ) ;
memcpy ( dst - > features , src - > features , sizeof ( dst - > features ) ) ;
memcpy ( dst - > compat , src - > compat , sizeof ( dst - > compat ) ) ;
2018-10-30 21:32:47 +03:00
for ( i = 0 ; i < BCH_SB_FIELD_NR ; i + + ) {
2023-02-13 06:08:39 +03:00
int d ;
2022-03-11 00:43:52 +03:00
if ( ( 1U < < i ) & BCH_SINGLE_DEVICE_SB_FIELDS )
2017-03-17 09:18:50 +03:00
continue ;
2023-09-27 00:49:34 +03:00
src_f = bch2_sb_field_get_id ( src , i ) ;
dst_f = bch2_sb_field_get_id ( dst , i ) ;
2023-02-13 06:08:39 +03:00
d = ( src_f ? le32_to_cpu ( src_f - > u64s ) : 0 ) -
( dst_f ? le32_to_cpu ( dst_f - > u64s ) : 0 ) ;
if ( d > 0 ) {
2023-08-07 19:04:05 +03:00
int ret = bch2_sb_realloc ( dst_handle ,
le32_to_cpu ( dst_handle - > sb - > u64s ) + d ) ;
2023-02-13 06:08:39 +03:00
if ( ret )
return ret ;
dst = dst_handle - > sb ;
2023-09-27 00:49:34 +03:00
dst_f = bch2_sb_field_get_id ( dst , i ) ;
2023-02-13 06:08:39 +03:00
}
2017-03-17 09:18:50 +03:00
dst_f = __bch2_sb_field_resize ( dst_handle , dst_f ,
2018-10-30 21:32:47 +03:00
src_f ? le32_to_cpu ( src_f - > u64s ) : 0 ) ;
2017-03-17 09:18:50 +03:00
2018-10-30 21:32:47 +03:00
if ( src_f )
memcpy ( dst_f , src_f , vstruct_bytes ( src_f ) ) ;
2017-03-17 09:18:50 +03:00
}
2023-02-13 06:08:39 +03:00
return 0 ;
2017-03-17 09:18:50 +03:00
}
int bch2_sb_to_fs ( struct bch_fs * c , struct bch_sb * src )
{
int ret ;
lockdep_assert_held ( & c - > sb_lock ) ;
2023-02-13 06:08:39 +03:00
ret = bch2_sb_realloc ( & c - > disk_sb , 0 ) ? :
__copy_super ( & c - > disk_sb , src ) ? :
bch2_sb_replicas_to_cpu_replicas ( c ) ? :
bch2_sb_disk_groups_to_cpu ( c ) ;
2017-03-17 09:18:50 +03:00
if ( ret )
return ret ;
bch2_sb_update ( c ) ;
return 0 ;
}
int bch2_sb_from_fs ( struct bch_fs * c , struct bch_dev * ca )
{
2023-02-13 06:08:39 +03:00
return __copy_super ( & ca - > disk_sb , c - > disk_sb . sb ) ;
2017-03-17 09:18:50 +03:00
}
/* read superblock: */
2022-01-04 07:38:50 +03:00
static int read_one_super ( struct bch_sb_handle * sb , u64 offset , struct printbuf * err )
2017-03-17 09:18:50 +03:00
{
size_t bytes ;
2022-01-04 07:38:50 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
reread :
bio_reset ( sb - > bio , sb - > bdev , REQ_OP_READ | REQ_SYNC | REQ_META ) ;
sb - > bio - > bi_iter . bi_sector = offset ;
2021-04-06 21:00:56 +03:00
bch2_bio_map ( sb - > bio , sb - > sb , sb - > buffer_size ) ;
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
ret = submit_bio_wait ( sb - > bio ) ;
if ( ret ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " IO error: %i " , ret ) ;
2022-01-04 07:38:50 +03:00
return ret ;
}
2017-03-17 09:18:50 +03:00
if ( ! uuid_equal ( & sb - > sb - > magic , & BCACHE_MAGIC ) & &
2022-01-04 07:38:50 +03:00
! uuid_equal ( & sb - > sb - > magic , & BCHFS_MAGIC ) ) {
2024-01-05 21:03:01 +03:00
prt_str ( err , " Not a bcachefs superblock (got magic " ) ;
pr_uuid ( err , sb - > sb - > magic . b ) ;
prt_str ( err , " ) " ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_magic ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2023-06-29 03:27:07 +03:00
ret = bch2_sb_compatible ( sb - > sb , err ) ;
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
bytes = vstruct_bytes ( sb - > sb ) ;
2024-05-06 16:10:29 +03:00
if ( bytes > 512ULL < < min ( BCH_SB_LAYOUT_SIZE_BITS_MAX , sb - > sb - > layout . sb_max_size_bits ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " Invalid superblock: too big (got %zu bytes, layout max %lu) " ,
2022-01-04 07:38:50 +03:00
bytes , 512UL < < sb - > sb - > layout . sb_max_size_bits ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_too_big ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2021-04-06 21:00:56 +03:00
if ( bytes > sb - > buffer_size ) {
2023-03-14 22:35:57 +03:00
ret = bch2_sb_realloc ( sb , le32_to_cpu ( sb - > sb - > u64s ) ) ;
if ( ret )
return ret ;
2017-03-17 09:18:50 +03:00
goto reread ;
}
2024-01-05 19:59:03 +03:00
enum bch_csum_type csum_type = BCH_SB_CSUM_TYPE ( sb - > sb ) ;
if ( csum_type > = BCH_CSUM_NR ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " unknown checksum type %llu " , BCH_SB_CSUM_TYPE ( sb - > sb ) ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_csum_type ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
/* XXX: verify MACs */
2024-01-05 19:59:03 +03:00
struct bch_csum csum = csum_vstruct ( NULL , csum_type , null_nonce ( ) , sb - > sb ) ;
2022-01-04 07:38:50 +03:00
if ( bch2_crc_cmp ( csum , sb - > sb - > csum ) ) {
2024-01-05 19:59:03 +03:00
bch2_csum_err_msg ( err , csum_type , sb - > sb - > csum , csum ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_sb_csum ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2019-03-22 06:13:46 +03:00
sb - > seq = le64_to_cpu ( sb - > sb - > seq ) ;
2022-01-04 07:38:50 +03:00
return 0 ;
2017-03-17 09:18:50 +03:00
}
2023-11-19 23:53:36 +03:00
static int __bch2_read_super ( const char * path , struct bch_opts * opts ,
struct bch_sb_handle * sb , bool ignore_notbchfs_msg )
2017-03-17 09:18:50 +03:00
{
u64 offset = opt_get ( * opts , sb ) ;
struct bch_sb_layout layout ;
2022-02-25 21:18:19 +03:00
struct printbuf err = PRINTBUF ;
2023-11-19 23:53:36 +03:00
struct printbuf err2 = PRINTBUF ;
2017-03-17 09:18:50 +03:00
__le64 * i ;
int ret ;
2023-07-11 03:30:04 +03:00
# ifndef __KERNEL__
retry :
# endif
2017-03-17 09:18:50 +03:00
memset ( sb , 0 , sizeof ( * sb ) ) ;
sb - > mode = BLK_OPEN_READ ;
sb - > have_bio = true ;
sb - > holder = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! sb - > holder )
return - ENOMEM ;
2023-11-16 20:13:43 +03:00
sb - > sb_name = kstrdup ( path , GFP_KERNEL ) ;
2024-04-12 09:36:38 +03:00
if ( ! sb - > sb_name ) {
ret = - ENOMEM ;
prt_printf ( & err , " error allocating memory for sb_name " ) ;
goto err ;
}
2023-11-16 20:13:43 +03:00
2023-07-11 03:30:04 +03:00
# ifndef __KERNEL__
if ( opt_get ( * opts , direct_io ) = = false )
2023-09-24 02:07:16 +03:00
sb - > mode | = BLK_OPEN_BUFFERED ;
2023-07-11 03:30:04 +03:00
# endif
2017-03-17 09:18:50 +03:00
if ( ! opt_get ( * opts , noexcl ) )
sb - > mode | = BLK_OPEN_EXCL ;
if ( ! opt_get ( * opts , nochanges ) )
sb - > mode | = BLK_OPEN_WRITE ;
2024-01-23 16:26:35 +03:00
sb - > s_bdev_file = bdev_file_open_by_path ( path , sb - > mode , sb - > holder , & bch2_sb_handle_bdev_ops ) ;
if ( IS_ERR ( sb - > s_bdev_file ) & &
PTR_ERR ( sb - > s_bdev_file ) = = - EACCES & &
2017-03-17 09:18:50 +03:00
opt_get ( * opts , read_only ) ) {
sb - > mode & = ~ BLK_OPEN_WRITE ;
2024-01-23 16:26:35 +03:00
sb - > s_bdev_file = bdev_file_open_by_path ( path , sb - > mode , sb - > holder , & bch2_sb_handle_bdev_ops ) ;
if ( ! IS_ERR ( sb - > s_bdev_file ) )
2017-03-17 09:18:50 +03:00
opt_set ( * opts , nochanges , true ) ;
}
2024-01-23 16:26:35 +03:00
if ( IS_ERR ( sb - > s_bdev_file ) ) {
ret = PTR_ERR ( sb - > s_bdev_file ) ;
2024-02-13 01:15:29 +03:00
prt_printf ( & err , " error opening %s: %s " , path , bch2_err_str ( ret ) ) ;
2024-02-09 16:41:31 +03:00
goto err ;
2017-03-17 09:18:50 +03:00
}
2024-01-23 16:26:35 +03:00
sb - > bdev = file_bdev ( sb - > s_bdev_file ) ;
2017-03-17 09:18:50 +03:00
ret = bch2_sb_realloc ( sb , 0 ) ;
2022-01-04 07:38:50 +03:00
if ( ret ) {
2023-02-04 05:01:40 +03:00
prt_printf ( & err , " error allocating memory for superblock " ) ;
2017-03-17 09:18:50 +03:00
goto err ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
if ( bch2_fs_init_fault ( " read_super " ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( & err , " dynamic fault " ) ;
2022-01-04 07:38:50 +03:00
ret = - EFAULT ;
2017-03-17 09:18:50 +03:00
goto err ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
ret = read_one_super ( sb , offset , & err ) ;
if ( ! ret )
2017-03-17 09:18:50 +03:00
goto got_super ;
if ( opt_defined ( * opts , sb ) )
goto err ;
2023-11-19 23:53:36 +03:00
prt_printf ( & err2 , " bcachefs (%s): error reading default superblock: %s \n " ,
2022-02-25 21:18:19 +03:00
path , err . buf ) ;
2023-11-19 23:53:36 +03:00
if ( ret = = - BCH_ERR_invalid_sb_magic & & ignore_notbchfs_msg )
2024-02-13 01:15:29 +03:00
bch2_print_opts ( opts , KERN_INFO " %s " , err2 . buf ) ;
2023-11-19 23:53:36 +03:00
else
2024-02-13 01:15:29 +03:00
bch2_print_opts ( opts , KERN_ERR " %s " , err2 . buf ) ;
2023-11-19 23:53:36 +03:00
printbuf_exit ( & err2 ) ;
2022-02-25 21:18:19 +03:00
printbuf_reset ( & err ) ;
2017-03-17 09:18:50 +03:00
/*
* Error reading primary superblock - read location of backup
* superblocks :
*/
bio_reset ( sb - > bio , sb - > bdev , REQ_OP_READ | REQ_SYNC | REQ_META ) ;
sb - > bio - > bi_iter . bi_sector = BCH_SB_LAYOUT_SECTOR ;
/*
* use sb buffer to read layout , since sb buffer is page aligned but
* layout won ' t be :
*/
2019-07-04 02:27:42 +03:00
bch2_bio_map ( sb - > bio , sb - > sb , sizeof ( struct bch_sb_layout ) ) ;
2017-03-17 09:18:50 +03:00
2022-01-04 07:38:50 +03:00
ret = submit_bio_wait ( sb - > bio ) ;
if ( ret ) {
2023-02-04 05:01:40 +03:00
prt_printf ( & err , " IO error: %i " , ret ) ;
2017-03-17 09:18:50 +03:00
goto err ;
2022-01-04 07:38:50 +03:00
}
2017-03-17 09:18:50 +03:00
memcpy ( & layout , sb - > sb , sizeof ( layout ) ) ;
2022-01-04 07:38:50 +03:00
ret = validate_sb_layout ( & layout , & err ) ;
if ( ret )
2017-03-17 09:18:50 +03:00
goto err ;
for ( i = layout . sb_offset ;
i < layout . sb_offset + layout . nr_superblocks ; i + + ) {
offset = le64_to_cpu ( * i ) ;
if ( offset = = opt_get ( * opts , sb ) )
continue ;
2022-01-04 07:38:50 +03:00
ret = read_one_super ( sb , offset , & err ) ;
if ( ! ret )
2017-03-17 09:18:50 +03:00
goto got_super ;
}
goto err ;
got_super :
if ( le16_to_cpu ( sb - > sb - > block_size ) < < 9 <
2023-07-11 03:30:04 +03:00
bdev_logical_block_size ( sb - > bdev ) & &
opt_get ( * opts , direct_io ) ) {
# ifndef __KERNEL__
opt_set ( * opts , direct_io , false ) ;
bch2_free_super ( sb ) ;
goto retry ;
# endif
2023-02-04 05:01:40 +03:00
prt_printf ( & err , " block size (%u) smaller than device block size (%u) " ,
2021-12-14 22:24:41 +03:00
le16_to_cpu ( sb - > sb - > block_size ) < < 9 ,
bdev_logical_block_size ( sb - > bdev ) ) ;
2022-11-20 06:39:08 +03:00
ret = - BCH_ERR_block_size_too_small ;
2022-01-04 07:38:50 +03:00
goto err ;
2021-12-14 22:24:41 +03:00
}
2017-03-17 09:18:50 +03:00
sb - > have_layout = true ;
2022-01-04 07:38:50 +03:00
2024-05-09 01:49:14 +03:00
ret = bch2_sb_validate ( sb , 0 , & err ) ;
2022-01-04 07:38:50 +03:00
if ( ret ) {
2024-02-13 01:15:29 +03:00
bch2_print_opts ( opts , KERN_ERR " bcachefs (%s): error validating superblock: %s \n " ,
path , err . buf ) ;
2022-01-04 07:38:50 +03:00
goto err_no_print ;
}
2017-03-17 09:18:50 +03:00
out :
2022-02-25 21:18:19 +03:00
printbuf_exit ( & err ) ;
2017-03-17 09:18:50 +03:00
return ret ;
err :
2024-02-13 01:15:29 +03:00
bch2_print_opts ( opts , KERN_ERR " bcachefs (%s): error reading superblock: %s \n " ,
path , err . buf ) ;
2021-12-14 22:24:41 +03:00
err_no_print :
bch2_free_super ( sb ) ;
2017-03-17 09:18:50 +03:00
goto out ;
}
2023-11-19 23:53:36 +03:00
int bch2_read_super ( const char * path , struct bch_opts * opts ,
struct bch_sb_handle * sb )
{
return __bch2_read_super ( path , opts , sb , false ) ;
}
/* provide a silenced version for mount.bcachefs */
int bch2_read_super_silent ( const char * path , struct bch_opts * opts ,
struct bch_sb_handle * sb )
{
return __bch2_read_super ( path , opts , sb , true ) ;
}
2017-03-17 09:18:50 +03:00
/* write superblock: */
static void write_super_endio ( struct bio * bio )
{
struct bch_dev * ca = bio - > bi_private ;
/* XXX: return errors directly */
2023-10-25 23:29:37 +03:00
if ( bch2_dev_io_err_on ( bio - > bi_status , ca ,
bio_data_dir ( bio )
? BCH_MEMBER_ERROR_write
: BCH_MEMBER_ERROR_read ,
" superblock %s error: %s " ,
bio_data_dir ( bio ) ? " write " : " read " ,
2020-07-21 20:34:22 +03:00
bch2_blk_status_to_str ( bio - > bi_status ) ) )
2017-03-17 09:18:50 +03:00
ca - > sb_write_error = 1 ;
closure_put ( & ca - > fs - > sb_write ) ;
percpu_ref_put ( & ca - > io_ref ) ;
}
2019-03-22 06:13:46 +03:00
static void read_back_super ( struct bch_fs * c , struct bch_dev * ca )
{
struct bch_sb * sb = ca - > disk_sb . sb ;
struct bio * bio = ca - > disk_sb . bio ;
bio_reset ( bio , ca - > disk_sb . bdev , REQ_OP_READ | REQ_SYNC | REQ_META ) ;
bio - > bi_iter . bi_sector = le64_to_cpu ( sb - > layout . sb_offset [ 0 ] ) ;
bio - > bi_end_io = write_super_endio ;
bio - > bi_private = ca ;
2019-07-04 02:27:42 +03:00
bch2_bio_map ( bio , ca - > sb_read_scratch , PAGE_SIZE ) ;
2019-03-22 06:13:46 +03:00
2020-07-10 01:28:11 +03:00
this_cpu_add ( ca - > io_done - > sectors [ READ ] [ BCH_DATA_sb ] ,
2019-03-22 06:13:46 +03:00
bio_sectors ( bio ) ) ;
percpu_ref_get ( & ca - > io_ref ) ;
closure_bio_submit ( bio , & c - > sb_write ) ;
}
2017-03-17 09:18:50 +03:00
static void write_one_super ( struct bch_fs * c , struct bch_dev * ca , unsigned idx )
{
struct bch_sb * sb = ca - > disk_sb . sb ;
struct bio * bio = ca - > disk_sb . bio ;
sb - > offset = sb - > layout . sb_offset [ idx ] ;
2021-06-13 23:01:08 +03:00
SET_BCH_SB_CSUM_TYPE ( sb , bch2_csum_opt_to_type ( c - > opts . metadata_checksum , false ) ) ;
2017-03-17 09:18:50 +03:00
sb - > csum = csum_vstruct ( c , BCH_SB_CSUM_TYPE ( sb ) ,
null_nonce ( ) , sb ) ;
bio_reset ( bio , ca - > disk_sb . bdev , REQ_OP_WRITE | REQ_SYNC | REQ_META ) ;
bio - > bi_iter . bi_sector = le64_to_cpu ( sb - > offset ) ;
bio - > bi_end_io = write_super_endio ;
bio - > bi_private = ca ;
2019-07-04 02:27:42 +03:00
bch2_bio_map ( bio , sb ,
roundup ( ( size_t ) vstruct_bytes ( sb ) ,
bdev_logical_block_size ( ca - > disk_sb . bdev ) ) ) ;
2017-03-17 09:18:50 +03:00
2020-07-10 01:28:11 +03:00
this_cpu_add ( ca - > io_done - > sectors [ WRITE ] [ BCH_DATA_sb ] ,
2017-03-17 09:18:50 +03:00
bio_sectors ( bio ) ) ;
percpu_ref_get ( & ca - > io_ref ) ;
closure_bio_submit ( bio , & c - > sb_write ) ;
}
2019-03-22 06:13:46 +03:00
int bch2_write_super ( struct bch_fs * c )
2017-03-17 09:18:50 +03:00
{
struct closure * cl = & c - > sb_write ;
2022-02-25 21:18:19 +03:00
struct printbuf err = PRINTBUF ;
2023-12-17 07:47:29 +03:00
unsigned sb = 0 , nr_wrote ;
2017-03-17 09:18:50 +03:00
struct bch_devs_mask sb_written ;
bool wrote , can_mount_without_written , can_mount_with_written ;
2021-04-10 02:04:57 +03:00
unsigned degraded_flags = BCH_FORCE_IF_DEGRADED ;
2024-05-07 03:49:24 +03:00
DARRAY ( struct bch_dev * ) online_devices = { } ;
2019-03-22 06:13:46 +03:00
int ret = 0 ;
2017-03-17 09:18:50 +03:00
2022-08-27 19:48:36 +03:00
trace_and_count ( c , write_super , c , _RET_IP_ ) ;
2022-04-03 22:13:20 +03:00
2021-04-10 02:04:57 +03:00
if ( c - > opts . very_degraded )
degraded_flags | = BCH_FORCE_IF_LOST ;
2017-03-17 09:18:50 +03:00
lockdep_assert_held ( & c - > sb_lock ) ;
closure_init_stack ( cl ) ;
memset ( & sb_written , 0 , sizeof ( sb_written ) ) ;
2024-05-07 03:49:24 +03:00
for_each_online_member ( c , ca ) {
ret = darray_push ( & online_devices , ca ) ;
if ( bch2_fs_fatal_err_on ( ret , c , " %s: error allocating online devices " , __func__ ) ) {
percpu_ref_put ( & ca - > io_ref ) ;
goto out ;
}
percpu_ref_get ( & ca - > io_ref ) ;
}
2023-06-28 05:09:35 +03:00
/* Make sure we're using the new magic numbers: */
c - > disk_sb . sb - > magic = BCHFS_MAGIC ;
c - > disk_sb . sb - > layout . magic = BCHFS_MAGIC ;
2022-12-03 03:46:49 +03:00
2017-03-17 09:18:50 +03:00
le64_add_cpu ( & c - > disk_sb . sb - > seq , 1 ) ;
2023-06-28 04:02:27 +03:00
struct bch_sb_field_members_v2 * mi = bch2_sb_field_get ( c - > disk_sb . sb , members_v2 ) ;
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca )
__bch2_members_v2_get_mut ( mi , ( * ca ) - > dev_idx ) - > seq = c - > disk_sb . sb - > seq ;
2023-06-28 04:02:27 +03:00
c - > disk_sb . sb - > write_time = cpu_to_le64 ( ktime_get_real_seconds ( ) ) ;
2023-11-27 01:05:02 +03:00
if ( test_bit ( BCH_FS_error , & c - > flags ) )
2019-03-28 16:34:55 +03:00
SET_BCH_SB_HAS_ERRORS ( c - > disk_sb . sb , 1 ) ;
2023-11-27 01:05:02 +03:00
if ( test_bit ( BCH_FS_topology_error , & c - > flags ) )
2021-04-24 23:32:35 +03:00
SET_BCH_SB_HAS_TOPOLOGY_ERRORS ( c - > disk_sb . sb , 1 ) ;
2019-03-28 16:34:55 +03:00
2021-03-05 03:06:26 +03:00
SET_BCH_SB_BIG_ENDIAN ( c - > disk_sb . sb , CPU_BIG_ENDIAN ) ;
2022-03-15 11:36:33 +03:00
bch2_sb_counters_from_cpu ( c ) ;
2023-10-25 22:51:16 +03:00
bch2_sb_members_from_cpu ( c ) ;
2023-10-25 23:29:37 +03:00
bch2_sb_members_cpy_v2_v1 ( & c - > disk_sb ) ;
2023-10-25 22:51:16 +03:00
bch2_sb_errors_from_cpu ( c ) ;
2023-12-29 23:25:07 +03:00
bch2_sb_downgrade_update ( c ) ;
2022-03-15 11:36:33 +03:00
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca )
bch2_sb_from_fs ( c , ( * ca ) ) ;
2017-03-17 09:18:50 +03:00
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca ) {
2022-02-25 21:18:19 +03:00
printbuf_reset ( & err ) ;
2022-01-04 07:38:50 +03:00
2024-05-09 01:49:14 +03:00
ret = bch2_sb_validate ( & ( * ca ) - > disk_sb , BCH_VALIDATE_write , & err ) ;
2022-01-04 07:38:50 +03:00
if ( ret ) {
2022-02-25 21:18:19 +03:00
bch2_fs_inconsistent ( c , " sb invalid before write: %s " , err . buf ) ;
2017-03-17 09:18:50 +03:00
goto out ;
}
}
2019-03-28 16:34:55 +03:00
if ( c - > opts . nochanges )
2017-03-17 09:18:50 +03:00
goto out ;
2022-04-03 00:24:25 +03:00
/*
* Defer writing the superblock until filesystem initialization is
* complete - don ' t write out a partly initialized superblock :
*/
if ( ! BCH_SB_INITIALIZED ( c - > disk_sb . sb ) )
goto out ;
2023-12-23 05:58:43 +03:00
if ( le16_to_cpu ( c - > disk_sb . sb - > version ) > bcachefs_metadata_version_current ) {
struct printbuf buf = PRINTBUF ;
prt_printf ( & buf , " attempting to write superblock that wasn't version downgraded ( " ) ;
bch2_version_to_text ( & buf , le16_to_cpu ( c - > disk_sb . sb - > version ) ) ;
prt_str ( & buf , " > " ) ;
bch2_version_to_text ( & buf , bcachefs_metadata_version_current ) ;
prt_str ( & buf , " ) " ) ;
2024-03-18 04:51:19 +03:00
bch2_fs_fatal_error ( c , " : %s " , buf . buf ) ;
2023-12-23 05:58:43 +03:00
printbuf_exit ( & buf ) ;
return - BCH_ERR_sb_not_downgraded ;
}
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca ) {
__set_bit ( ( * ca ) - > dev_idx , sb_written . d ) ;
( * ca ) - > sb_write_error = 0 ;
2017-03-17 09:18:50 +03:00
}
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca )
read_back_super ( c , * ca ) ;
2019-03-22 06:13:46 +03:00
closure_sync ( cl ) ;
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , cap ) {
struct bch_dev * ca = * cap ;
2022-01-02 03:04:33 +03:00
if ( ca - > sb_write_error )
continue ;
if ( le64_to_cpu ( ca - > sb_read_scratch - > seq ) < ca - > disk_sb . seq ) {
2024-05-03 21:17:54 +03:00
struct printbuf buf = PRINTBUF ;
prt_char ( & buf , ' ' ) ;
prt_bdevname ( & buf , ca - > disk_sb . bdev ) ;
prt_printf ( & buf ,
2024-03-18 04:51:19 +03:00
" : Superblock write was silently dropped! (seq %llu expected %llu) " ,
2022-01-02 03:04:33 +03:00
le64_to_cpu ( ca - > sb_read_scratch - > seq ) ,
ca - > disk_sb . seq ) ;
2024-05-03 21:17:54 +03:00
bch2_fs_fatal_error ( c , " %s " , buf . buf ) ;
printbuf_exit ( & buf ) ;
2022-12-12 04:37:11 +03:00
ret = - BCH_ERR_erofs_sb_err ;
2022-01-02 03:04:33 +03:00
}
if ( le64_to_cpu ( ca - > sb_read_scratch - > seq ) > ca - > disk_sb . seq ) {
2024-05-03 21:17:54 +03:00
struct printbuf buf = PRINTBUF ;
prt_char ( & buf , ' ' ) ;
prt_bdevname ( & buf , ca - > disk_sb . bdev ) ;
prt_printf ( & buf ,
2024-03-18 04:51:19 +03:00
" : Superblock modified by another process (seq %llu expected %llu) " ,
2022-01-02 03:04:33 +03:00
le64_to_cpu ( ca - > sb_read_scratch - > seq ) ,
ca - > disk_sb . seq ) ;
2024-05-03 21:17:54 +03:00
bch2_fs_fatal_error ( c , " %s " , buf . buf ) ;
printbuf_exit ( & buf ) ;
2022-12-12 04:37:11 +03:00
ret = - BCH_ERR_erofs_sb_err ;
2019-03-22 06:13:46 +03:00
}
}
2024-05-03 21:17:54 +03:00
if ( ret )
goto out ;
2017-03-17 09:18:50 +03:00
do {
wrote = false ;
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , cap ) {
struct bch_dev * ca = * cap ;
2019-03-22 06:13:46 +03:00
if ( ! ca - > sb_write_error & &
sb < ca - > disk_sb . sb - > layout . nr_superblocks ) {
2017-03-17 09:18:50 +03:00
write_one_super ( c , ca , sb ) ;
wrote = true ;
}
2024-05-07 03:49:24 +03:00
}
2017-03-17 09:18:50 +03:00
closure_sync ( cl ) ;
sb + + ;
} while ( wrote ) ;
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , cap ) {
struct bch_dev * ca = * cap ;
2017-03-17 09:18:50 +03:00
if ( ca - > sb_write_error )
__clear_bit ( ca - > dev_idx , sb_written . d ) ;
2019-03-22 06:13:46 +03:00
else
ca - > disk_sb . seq = le64_to_cpu ( ca - > disk_sb . sb - > seq ) ;
}
2017-03-17 09:18:50 +03:00
nr_wrote = dev_mask_nr ( & sb_written ) ;
can_mount_with_written =
2021-04-10 02:04:57 +03:00
bch2_have_enough_devs ( c , sb_written , degraded_flags , false ) ;
2017-03-17 09:18:50 +03:00
2023-12-17 07:47:29 +03:00
for ( unsigned i = 0 ; i < ARRAY_SIZE ( sb_written . d ) ; i + + )
2017-03-17 09:18:50 +03:00
sb_written . d [ i ] = ~ sb_written . d [ i ] ;
can_mount_without_written =
2021-04-10 02:04:57 +03:00
bch2_have_enough_devs ( c , sb_written , degraded_flags , false ) ;
2017-03-17 09:18:50 +03:00
/*
* If we would be able to mount _without_ the devices we successfully
* wrote superblocks to , we weren ' t able to write to enough devices :
*
* Exception : if we can mount without the successes because we haven ' t
* written anything ( new filesystem ) , we continue if we ' d be able to
* mount with the devices we did successfully write to :
*/
2019-03-22 06:13:46 +03:00
if ( bch2_fs_fatal_err_on ( ! nr_wrote | |
2021-02-07 07:17:26 +03:00
! can_mount_with_written | |
2019-03-22 06:13:46 +03:00
( can_mount_without_written & &
! can_mount_with_written ) , c ,
2024-03-18 04:51:19 +03:00
" : Unable to write superblock to sufficient devices (from %ps) " ,
2021-11-04 00:23:49 +03:00
( void * ) _RET_IP_ ) )
2019-03-22 06:13:46 +03:00
ret = - 1 ;
2017-03-17 09:18:50 +03:00
out :
/* Make new options visible after they're persistent: */
bch2_sb_update ( c ) ;
2024-05-07 03:49:24 +03:00
darray_for_each ( online_devices , ca )
percpu_ref_put ( & ( * ca ) - > io_ref ) ;
darray_exit ( & online_devices ) ;
2022-02-25 21:18:19 +03:00
printbuf_exit ( & err ) ;
2019-03-22 06:13:46 +03:00
return ret ;
2017-03-17 09:18:50 +03:00
}
2019-11-29 21:47:42 +03:00
void __bch2_check_set_feature ( struct bch_fs * c , unsigned feat )
{
mutex_lock ( & c - > sb_lock ) ;
if ( ! ( c - > sb . features & ( 1ULL < < feat ) ) ) {
c - > disk_sb . sb - > features [ 0 ] | = cpu_to_le64 ( 1ULL < < feat ) ;
bch2_write_super ( c ) ;
}
mutex_unlock ( & c - > sb_lock ) ;
}
2023-07-10 19:23:01 +03:00
/* Downgrade if superblock is at a higher version than currently supported: */
2023-12-29 23:25:07 +03:00
bool bch2_check_version_downgrade ( struct bch_fs * c )
2017-03-17 09:18:50 +03:00
{
2023-12-29 23:25:07 +03:00
bool ret = bcachefs_metadata_version_current < c - > sb . version ;
2023-07-10 19:23:01 +03:00
lockdep_assert_held ( & c - > sb_lock ) ;
2023-06-29 02:59:56 +03:00
2023-06-28 05:09:35 +03:00
/*
* Downgrade , if superblock is at a higher version than currently
* supported :
2024-01-06 03:04:42 +03:00
*
* c - > sb will be checked before we write the superblock , so update it as
* well :
2023-06-28 05:09:35 +03:00
*/
2024-01-06 03:04:42 +03:00
if ( BCH_SB_VERSION_UPGRADE_COMPLETE ( c - > disk_sb . sb ) > bcachefs_metadata_version_current ) {
2023-06-29 02:59:56 +03:00
SET_BCH_SB_VERSION_UPGRADE_COMPLETE ( c - > disk_sb . sb , bcachefs_metadata_version_current ) ;
2024-01-06 03:04:42 +03:00
c - > sb . version_upgrade_complete = bcachefs_metadata_version_current ;
}
if ( c - > sb . version > bcachefs_metadata_version_current ) {
2023-06-29 02:59:56 +03:00
c - > disk_sb . sb - > version = cpu_to_le16 ( bcachefs_metadata_version_current ) ;
2024-01-06 03:04:42 +03:00
c - > sb . version = bcachefs_metadata_version_current ;
}
if ( c - > sb . version_min > bcachefs_metadata_version_current ) {
2023-06-28 05:09:35 +03:00
c - > disk_sb . sb - > version_min = cpu_to_le16 ( bcachefs_metadata_version_current ) ;
2024-01-06 03:04:42 +03:00
c - > sb . version_min = bcachefs_metadata_version_current ;
}
2023-06-28 05:09:35 +03:00
c - > disk_sb . sb - > compat [ 0 ] & = cpu_to_le64 ( ( 1ULL < < BCH_COMPAT_NR ) - 1 ) ;
2023-12-29 23:25:07 +03:00
return ret ;
2023-07-10 19:23:01 +03:00
}
void bch2_sb_upgrade ( struct bch_fs * c , unsigned new_version )
{
lockdep_assert_held ( & c - > sb_lock ) ;
2023-06-29 02:59:56 +03:00
2023-12-29 23:25:07 +03:00
if ( BCH_VERSION_MAJOR ( new_version ) >
BCH_VERSION_MAJOR ( le16_to_cpu ( c - > disk_sb . sb - > version ) ) )
bch2_sb_field_resize ( & c - > disk_sb , downgrade , 0 ) ;
2023-07-10 19:23:01 +03:00
c - > disk_sb . sb - > version = cpu_to_le16 ( new_version ) ;
c - > disk_sb . sb - > features [ 0 ] | = cpu_to_le64 ( BCH_SB_FEATURES_ALL ) ;
}
2023-12-29 23:15:14 +03:00
static int bch2_sb_ext_validate ( struct bch_sb * sb , struct bch_sb_field * f ,
2024-05-09 01:49:14 +03:00
enum bch_validate_flags flags , struct printbuf * err )
2023-12-29 23:15:14 +03:00
{
if ( vstruct_bytes ( f ) < 88 ) {
prt_printf ( err , " field too small (%zu < %u) " , vstruct_bytes ( f ) , 88 ) ;
return - BCH_ERR_invalid_sb_ext ;
}
return 0 ;
}
static void bch2_sb_ext_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
{
struct bch_sb_field_ext * e = field_to_type ( f , ext ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Recovery passes required: \t " ) ;
2023-12-29 23:15:14 +03:00
prt_bitflags ( out , bch2_recovery_passes ,
bch2_recovery_passes_from_stable ( le64_to_cpu ( e - > recovery_passes_required [ 0 ] ) ) ) ;
prt_newline ( out ) ;
unsigned long * errors_silent = kmalloc ( sizeof ( e - > errors_silent ) , GFP_KERNEL ) ;
if ( errors_silent ) {
le_bitvector_to_cpu ( errors_silent , ( void * ) e - > errors_silent , sizeof ( e - > errors_silent ) * 8 ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Errors to silently fix: \t " ) ;
2023-12-29 23:15:14 +03:00
prt_bitflags_vector ( out , bch2_sb_error_strs , errors_silent , sizeof ( e - > errors_silent ) * 8 ) ;
prt_newline ( out ) ;
kfree ( errors_silent ) ;
}
2024-03-16 06:03:42 +03:00
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Btrees with missing data: \t " ) ;
2024-03-16 06:03:42 +03:00
prt_bitflags ( out , __bch2_btree_ids , le64_to_cpu ( e - > btrees_lost_data ) ) ;
prt_newline ( out ) ;
2023-12-29 23:15:14 +03:00
}
static const struct bch_sb_field_ops bch_sb_field_ops_ext = {
. validate = bch2_sb_ext_validate ,
. to_text = bch2_sb_ext_to_text ,
} ;
2017-03-17 09:18:50 +03:00
static const struct bch_sb_field_ops * bch2_sb_field_ops [ ] = {
# define x(f, nr) \
[ BCH_SB_FIELD_ # # f ] = & bch_sb_field_ops_ # # f ,
BCH_SB_FIELDS ( )
# undef x
} ;
2023-07-10 22:56:05 +03:00
static const struct bch_sb_field_ops bch2_sb_field_null_ops ;
2023-07-07 03:11:36 +03:00
static const struct bch_sb_field_ops * bch2_sb_field_type_ops ( unsigned type )
{
return likely ( type < ARRAY_SIZE ( bch2_sb_field_ops ) )
? bch2_sb_field_ops [ type ]
: & bch2_sb_field_null_ops ;
}
2022-01-04 07:38:50 +03:00
static int bch2_sb_field_validate ( struct bch_sb * sb , struct bch_sb_field * f ,
2024-05-09 01:49:14 +03:00
enum bch_validate_flags flags , struct printbuf * err )
2017-03-17 09:18:50 +03:00
{
unsigned type = le32_to_cpu ( f - > type ) ;
2022-02-27 19:57:42 +03:00
struct printbuf field_err = PRINTBUF ;
2023-07-07 03:11:36 +03:00
const struct bch_sb_field_ops * ops = bch2_sb_field_type_ops ( type ) ;
2022-01-04 07:38:50 +03:00
int ret ;
2017-03-17 09:18:50 +03:00
2024-05-09 01:49:14 +03:00
ret = ops - > validate ? ops - > validate ( sb , f , flags , & field_err ) : 0 ;
2022-01-04 07:38:50 +03:00
if ( ret ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " Invalid superblock section %s: %s " ,
2023-07-07 03:11:36 +03:00
bch2_sb_fields [ type ] , field_err . buf ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( err ) ;
2022-02-27 19:57:42 +03:00
bch2_sb_field_to_text ( err , sb , f ) ;
2022-01-04 07:38:50 +03:00
}
2022-02-27 19:57:42 +03:00
printbuf_exit ( & field_err ) ;
2022-01-04 07:38:50 +03:00
return ret ;
2017-03-17 09:18:50 +03:00
}
2024-01-05 20:37:47 +03:00
void __bch2_sb_field_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
2017-03-17 09:18:50 +03:00
{
unsigned type = le32_to_cpu ( f - > type ) ;
2023-07-07 03:11:36 +03:00
const struct bch_sb_field_ops * ops = bch2_sb_field_type_ops ( type ) ;
2017-03-17 09:18:50 +03:00
2023-02-04 05:01:40 +03:00
if ( ! out - > nr_tabstops )
printbuf_tabstop_push ( out , 32 ) ;
2022-03-05 20:01:16 +03:00
2024-01-05 20:37:47 +03:00
if ( ops - > to_text )
ops - > to_text ( out , sb , f ) ;
}
void bch2_sb_field_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
{
unsigned type = le32_to_cpu ( f - > type ) ;
2023-07-07 03:11:36 +03:00
if ( type < BCH_SB_FIELD_NR )
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %s " , bch2_sb_fields [ type ] ) ;
2018-11-09 09:24:07 +03:00
else
2023-02-04 05:01:40 +03:00
prt_printf ( out , " (unknown field %u) " , type ) ;
2018-11-09 09:24:07 +03:00
2023-02-04 05:01:40 +03:00
prt_printf ( out , " (size %zu): " , vstruct_bytes ( f ) ) ;
prt_newline ( out ) ;
2017-03-17 09:18:50 +03:00
2024-01-05 20:37:47 +03:00
__bch2_sb_field_to_text ( out , sb , f ) ;
2022-02-20 13:00:45 +03:00
}
void bch2_sb_layout_to_text ( struct printbuf * out , struct bch_sb_layout * l )
{
unsigned i ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Type: %u " , l - > layout_type ) ;
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
2023-02-04 05:01:40 +03:00
prt_str ( out , " Superblock max size: " ) ;
prt_units_u64 ( out , 512 < < l - > sb_max_size_bits ) ;
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Nr superblocks: %u " , l - > nr_superblocks ) ;
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
2023-02-04 05:01:40 +03:00
prt_str ( out , " Offsets: " ) ;
2022-02-20 13:00:45 +03:00
for ( i = 0 ; i < l - > nr_superblocks ; i + + ) {
if ( i )
2023-02-04 05:01:40 +03:00
prt_str ( out , " , " ) ;
prt_printf ( out , " %llu " , le64_to_cpu ( l - > sb_offset [ i ] ) ) ;
2022-02-20 13:00:45 +03:00
}
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
}
void bch2_sb_to_text ( struct printbuf * out , struct bch_sb * sb ,
bool print_layout , unsigned fields )
{
u64 fields_have = 0 ;
unsigned nr_devices = 0 ;
2023-02-04 05:01:40 +03:00
if ( ! out - > nr_tabstops )
2022-09-17 01:39:01 +03:00
printbuf_tabstop_push ( out , 44 ) ;
2022-03-05 20:01:16 +03:00
2023-09-25 06:55:37 +03:00
for ( int i = 0 ; i < sb - > nr_devices ; i + + )
2024-04-12 06:31:55 +03:00
nr_devices + = bch2_member_exists ( sb , i ) ;
2022-02-20 13:00:45 +03:00
2024-04-10 23:08:24 +03:00
prt_printf ( out , " External UUID: \t " ) ;
2022-02-20 13:00:45 +03:00
pr_uuid ( out , sb - > user_uuid . b ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Internal UUID: \t " ) ;
2022-02-20 13:00:45 +03:00
pr_uuid ( out , sb - > uuid . b ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Magic number: \t " ) ;
2024-01-05 21:03:01 +03:00
pr_uuid ( out , sb - > magic . b ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Device index: \t %u \n " , sb - > dev_idx ) ;
2023-02-04 05:01:40 +03:00
2024-04-10 23:08:24 +03:00
prt_str ( out , " Label: \t " ) ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %.*s " , ( int ) sizeof ( sb - > label ) , sb - > label ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_str ( out , " Version: \t " ) ;
2023-06-29 02:53:05 +03:00
bch2_version_to_text ( out , le16_to_cpu ( sb - > version ) ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_str ( out , " Version upgrade complete: \t " ) ;
2023-06-29 02:59:56 +03:00
bch2_version_to_text ( out , BCH_SB_VERSION_UPGRADE_COMPLETE ( sb ) ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Oldest version on disk: \t " ) ;
2023-06-29 02:53:05 +03:00
bch2_version_to_text ( out , le16_to_cpu ( sb - > version_min ) ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Created: \t " ) ;
2022-02-20 13:00:45 +03:00
if ( sb - > time_base_lo )
2023-11-01 06:43:47 +03:00
bch2_prt_datetime ( out , div_u64 ( le64_to_cpu ( sb - > time_base_lo ) , NSEC_PER_SEC ) ) ;
2022-02-20 13:00:45 +03:00
else
2023-02-04 05:01:40 +03:00
prt_printf ( out , " (not set) " ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Sequence number: \t " ) ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %llu " , le64_to_cpu ( sb - > seq ) ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Time of last write: \t " ) ;
2023-06-28 04:02:27 +03:00
bch2_prt_datetime ( out , le64_to_cpu ( sb - > write_time ) ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Superblock size: \t " ) ;
2024-01-16 01:57:44 +03:00
prt_units_u64 ( out , vstruct_bytes ( sb ) ) ;
prt_str ( out , " / " ) ;
prt_units_u64 ( out , 512ULL < < sb - > layout . sb_max_size_bits ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Clean: \t %llu \n " , BCH_SB_CLEAN ( sb ) ) ;
prt_printf ( out , " Devices: \t %u \n " , nr_devices ) ;
2023-02-04 05:01:40 +03:00
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Sections: \t " ) ;
2022-03-05 20:01:16 +03:00
vstruct_for_each ( sb , f )
fields_have | = 1 < < le32_to_cpu ( f - > type ) ;
2023-02-04 05:01:40 +03:00
prt_bitflags ( out , bch2_sb_fields , fields_have ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Features: \t " ) ;
2023-02-04 05:01:40 +03:00
prt_bitflags ( out , bch2_sb_features , le64_to_cpu ( sb - > features [ 0 ] ) ) ;
prt_newline ( out ) ;
2024-04-10 23:08:24 +03:00
prt_printf ( out , " Compat features: \t " ) ;
2023-02-04 05:01:40 +03:00
prt_bitflags ( out , bch2_sb_compat , le64_to_cpu ( sb - > compat [ 0 ] ) ) ;
prt_newline ( out ) ;
prt_newline ( out ) ;
prt_printf ( out , " Options: " ) ;
prt_newline ( out ) ;
printbuf_indent_add ( out , 2 ) ;
2022-03-05 20:01:16 +03:00
{
enum bch_opt_id id ;
2022-02-20 13:00:45 +03:00
2022-03-05 20:01:16 +03:00
for ( id = 0 ; id < bch2_opts_nr ; id + + ) {
const struct bch_option * opt = bch2_opt_table + id ;
2022-02-20 13:00:45 +03:00
2022-03-05 20:01:16 +03:00
if ( opt - > get_sb ! = BCH2_NO_SB_OPT ) {
u64 v = bch2_opt_from_sb ( sb , id ) ;
2022-02-20 13:00:45 +03:00
2024-04-10 23:08:24 +03:00
prt_printf ( out , " %s: \t " , opt - > attr . name ) ;
2022-03-05 20:01:16 +03:00
bch2_opt_to_text ( out , NULL , sb , opt , v ,
OPT_HUMAN_READABLE | OPT_SHOW_FULL_LIST ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2022-03-05 20:01:16 +03:00
}
}
}
2022-02-20 13:00:45 +03:00
2023-02-04 05:01:40 +03:00
printbuf_indent_sub ( out , 2 ) ;
2022-02-20 13:00:45 +03:00
if ( print_layout ) {
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
prt_printf ( out , " layout: " ) ;
prt_newline ( out ) ;
printbuf_indent_add ( out , 2 ) ;
2022-02-20 13:00:45 +03:00
bch2_sb_layout_to_text ( out , & sb - > layout ) ;
2023-02-04 05:01:40 +03:00
printbuf_indent_sub ( out , 2 ) ;
2022-02-20 13:00:45 +03:00
}
vstruct_for_each ( sb , f )
if ( fields & ( 1 < < le32_to_cpu ( f - > type ) ) ) {
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2022-02-20 13:00:45 +03:00
bch2_sb_field_to_text ( out , sb , f ) ;
}
2017-03-17 09:18:50 +03:00
}