2022-03-11 00:43:52 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "journal_sb.h"
# include "darray.h"
# include <linux/sort.h>
/* BCH_SB_FIELD_journal: */
static int u64_cmp ( const void * _l , const void * _r )
{
const u64 * l = _l ;
const u64 * r = _r ;
return cmp_int ( * l , * r ) ;
}
static int bch2_sb_journal_validate ( struct bch_sb * sb ,
struct bch_sb_field * f ,
struct printbuf * err )
{
struct bch_sb_field_journal * journal = field_to_type ( f , journal ) ;
2023-09-25 06:55:37 +03:00
struct bch_member m = bch2_sb_member_get ( sb , sb - > dev_idx ) ;
2022-11-20 06:39:08 +03:00
int ret = - BCH_ERR_invalid_sb_journal ;
2022-03-11 00:43:52 +03:00
unsigned nr ;
unsigned i ;
u64 * b ;
nr = bch2_nr_journal_buckets ( journal ) ;
if ( ! nr )
return 0 ;
2022-10-20 01:31:33 +03:00
b = kmalloc_array ( nr , sizeof ( u64 ) , GFP_KERNEL ) ;
2022-03-11 00:43:52 +03:00
if ( ! b )
2023-03-14 22:35:57 +03:00
return - BCH_ERR_ENOMEM_sb_journal_validate ;
2022-03-11 00:43:52 +03:00
for ( i = 0 ; i < nr ; i + + )
b [ i ] = le64_to_cpu ( journal - > buckets [ i ] ) ;
sort ( b , nr , sizeof ( u64 ) , u64_cmp , NULL ) ;
if ( ! b [ 0 ] ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket at sector 0 " ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
2023-09-25 06:55:37 +03:00
if ( b [ 0 ] < le16_to_cpu ( m . first_bucket ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket %llu before first bucket %u " ,
2023-09-25 06:55:37 +03:00
b [ 0 ] , le16_to_cpu ( m . first_bucket ) ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
2023-09-25 06:55:37 +03:00
if ( b [ nr - 1 ] > = le64_to_cpu ( m . nbuckets ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket %llu past end of device (nbuckets %llu) " ,
2023-09-25 06:55:37 +03:00
b [ nr - 1 ] , le64_to_cpu ( m . nbuckets ) ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
for ( i = 0 ; i + 1 < nr ; i + + )
if ( b [ i ] = = b [ i + 1 ] ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " duplicate journal buckets %llu " , b [ i ] ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
ret = 0 ;
err :
kfree ( b ) ;
return ret ;
}
static void bch2_sb_journal_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
{
struct bch_sb_field_journal * journal = field_to_type ( f , journal ) ;
unsigned i , nr = bch2_nr_journal_buckets ( journal ) ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Buckets: " ) ;
2022-03-11 00:43:52 +03:00
for ( i = 0 ; i < nr ; i + + )
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %llu " , le64_to_cpu ( journal - > buckets [ i ] ) ) ;
prt_newline ( out ) ;
2022-03-11 00:43:52 +03:00
}
const struct bch_sb_field_ops bch_sb_field_ops_journal = {
. validate = bch2_sb_journal_validate ,
. to_text = bch2_sb_journal_to_text ,
} ;
struct u64_range {
u64 start ;
u64 end ;
} ;
static int u64_range_cmp ( const void * _l , const void * _r )
{
const struct u64_range * l = _l ;
const struct u64_range * r = _r ;
return cmp_int ( l - > start , r - > start ) ;
}
static int bch2_sb_journal_v2_validate ( struct bch_sb * sb ,
struct bch_sb_field * f ,
struct printbuf * err )
{
struct bch_sb_field_journal_v2 * journal = field_to_type ( f , journal_v2 ) ;
2023-09-25 06:55:37 +03:00
struct bch_member m = bch2_sb_member_get ( sb , sb - > dev_idx ) ;
2022-11-20 06:39:08 +03:00
int ret = - BCH_ERR_invalid_sb_journal ;
2022-03-11 00:43:52 +03:00
unsigned nr ;
unsigned i ;
struct u64_range * b ;
nr = bch2_sb_field_journal_v2_nr_entries ( journal ) ;
if ( ! nr )
return 0 ;
2022-10-20 01:31:33 +03:00
b = kmalloc_array ( nr , sizeof ( * b ) , GFP_KERNEL ) ;
2022-03-11 00:43:52 +03:00
if ( ! b )
2023-03-14 22:35:57 +03:00
return - BCH_ERR_ENOMEM_sb_journal_v2_validate ;
2022-03-11 00:43:52 +03:00
for ( i = 0 ; i < nr ; i + + ) {
b [ i ] . start = le64_to_cpu ( journal - > d [ i ] . start ) ;
b [ i ] . end = b [ i ] . start + le64_to_cpu ( journal - > d [ i ] . nr ) ;
}
sort ( b , nr , sizeof ( * b ) , u64_range_cmp , NULL ) ;
if ( ! b [ 0 ] . start ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket at sector 0 " ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
2023-09-25 06:55:37 +03:00
if ( b [ 0 ] . start < le16_to_cpu ( m . first_bucket ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket %llu before first bucket %u " ,
2023-09-25 06:55:37 +03:00
b [ 0 ] . start , le16_to_cpu ( m . first_bucket ) ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
2023-09-25 06:55:37 +03:00
if ( b [ nr - 1 ] . end > le64_to_cpu ( m . nbuckets ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " journal bucket %llu past end of device (nbuckets %llu) " ,
2023-09-25 06:55:37 +03:00
b [ nr - 1 ] . end - 1 , le64_to_cpu ( m . nbuckets ) ) ;
2022-03-11 00:43:52 +03:00
goto err ;
}
for ( i = 0 ; i + 1 < nr ; i + + ) {
if ( b [ i ] . end > b [ i + 1 ] . start ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " duplicate journal buckets in ranges %llu-%llu, %llu-%llu " ,
2022-03-11 00:43:52 +03:00
b [ i ] . start , b [ i ] . end , b [ i + 1 ] . start , b [ i + 1 ] . end ) ;
goto err ;
}
}
ret = 0 ;
err :
kfree ( b ) ;
return ret ;
}
static void bch2_sb_journal_v2_to_text ( struct printbuf * out , struct bch_sb * sb ,
struct bch_sb_field * f )
{
struct bch_sb_field_journal_v2 * journal = field_to_type ( f , journal_v2 ) ;
unsigned i , nr = bch2_sb_field_journal_v2_nr_entries ( journal ) ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " Buckets: " ) ;
2022-03-11 00:43:52 +03:00
for ( i = 0 ; i < nr ; i + + )
2023-02-04 05:01:40 +03:00
prt_printf ( out , " %llu-%llu " ,
2022-03-11 00:43:52 +03:00
le64_to_cpu ( journal - > d [ i ] . start ) ,
le64_to_cpu ( journal - > d [ i ] . start ) + le64_to_cpu ( journal - > d [ i ] . nr ) ) ;
2023-02-04 05:01:40 +03:00
prt_newline ( out ) ;
2022-03-11 00:43:52 +03:00
}
const struct bch_sb_field_ops bch_sb_field_ops_journal_v2 = {
. validate = bch2_sb_journal_v2_validate ,
. to_text = bch2_sb_journal_v2_to_text ,
} ;
2023-03-06 13:29:12 +03:00
int bch2_journal_buckets_to_sb ( struct bch_fs * c , struct bch_dev * ca ,
u64 * buckets , unsigned nr )
2022-03-11 00:43:52 +03:00
{
struct bch_sb_field_journal_v2 * j ;
2023-03-06 13:29:12 +03:00
unsigned i , dst = 0 , nr_compacted = 1 ;
2022-03-11 00:43:52 +03:00
if ( c )
lockdep_assert_held ( & c - > sb_lock ) ;
2023-03-06 13:29:12 +03:00
if ( ! nr ) {
2022-03-11 00:43:52 +03:00
bch2_sb_field_delete ( & ca - > disk_sb , BCH_SB_FIELD_journal ) ;
bch2_sb_field_delete ( & ca - > disk_sb , BCH_SB_FIELD_journal_v2 ) ;
return 0 ;
}
2023-03-06 13:29:12 +03:00
for ( i = 0 ; i + 1 < nr ; i + + )
if ( buckets [ i ] + 1 ! = buckets [ i + 1 ] )
nr_compacted + + ;
2022-03-11 00:43:52 +03:00
2023-09-27 00:49:34 +03:00
j = bch2_sb_field_resize ( & ca - > disk_sb , journal_v2 ,
2023-03-06 13:29:12 +03:00
( sizeof ( * j ) + sizeof ( j - > d [ 0 ] ) * nr_compacted ) / sizeof ( u64 ) ) ;
2022-03-11 00:43:52 +03:00
if ( ! j )
2022-09-19 00:10:33 +03:00
return - BCH_ERR_ENOSPC_sb_journal ;
2022-03-11 00:43:52 +03:00
bch2_sb_field_delete ( & ca - > disk_sb , BCH_SB_FIELD_journal ) ;
2023-07-07 05:47:42 +03:00
j - > d [ dst ] . start = cpu_to_le64 ( buckets [ 0 ] ) ;
j - > d [ dst ] . nr = cpu_to_le64 ( 1 ) ;
2022-03-11 00:43:52 +03:00
2023-03-06 13:29:12 +03:00
for ( i = 1 ; i < nr ; i + + ) {
if ( buckets [ i ] = = buckets [ i - 1 ] + 1 ) {
2022-03-11 00:43:52 +03:00
le64_add_cpu ( & j - > d [ dst ] . nr , 1 ) ;
} else {
dst + + ;
2023-07-07 05:47:42 +03:00
j - > d [ dst ] . start = cpu_to_le64 ( buckets [ i ] ) ;
j - > d [ dst ] . nr = cpu_to_le64 ( 1 ) ;
2022-03-11 00:43:52 +03:00
}
}
2023-03-06 13:29:12 +03:00
BUG_ON ( dst + 1 ! = nr_compacted ) ;
2022-03-11 00:43:52 +03:00
return 0 ;
}