2023-08-28 01:27:41 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "bkey_buf.h"
# include "btree_update.h"
# include "error.h"
2023-09-10 23:42:30 +03:00
# include "io_misc.h"
2023-08-28 01:27:41 +03:00
# include "logged_ops.h"
# include "super.h"
struct bch_logged_op_fn {
u8 type ;
int ( * resume ) ( struct btree_trans * , struct bkey_i * ) ;
} ;
static const struct bch_logged_op_fn logged_op_fns [ ] = {
# define x(n) { \
. type = KEY_TYPE_logged_op_ # # n , \
. resume = bch2_resume_logged_op_ # # n , \
} ,
BCH_LOGGED_OPS ( )
# undef x
} ;
static const struct bch_logged_op_fn * logged_op_fn ( enum bch_bkey_type type )
{
for ( unsigned i = 0 ; i < ARRAY_SIZE ( logged_op_fns ) ; i + + )
if ( logged_op_fns [ i ] . type = = type )
return logged_op_fns + i ;
return NULL ;
}
static int resume_logged_op ( struct btree_trans * trans , struct btree_iter * iter ,
struct bkey_s_c k )
{
struct bch_fs * c = trans - > c ;
const struct bch_logged_op_fn * fn = logged_op_fn ( k . k - > type ) ;
struct bkey_buf sk ;
u32 restart_count = trans - > restart_count ;
if ( ! fn )
return 0 ;
bch2_bkey_buf_init ( & sk ) ;
bch2_bkey_buf_reassemble ( & sk , c , k ) ;
2024-04-01 05:34:45 +03:00
fn - > resume ( trans , sk . k ) ;
2023-08-28 01:27:41 +03:00
bch2_bkey_buf_exit ( & sk , c ) ;
2024-04-01 05:34:45 +03:00
return trans_was_restarted ( trans , restart_count ) ;
2023-08-28 01:27:41 +03:00
}
int bch2_resume_logged_ops ( struct bch_fs * c )
{
2023-12-17 06:30:09 +03:00
int ret = bch2_trans_run ( c ,
2023-12-08 07:33:11 +03:00
for_each_btree_key ( trans , iter ,
BTREE_ID_logged_ops , POS_MIN ,
BTREE_ITER_PREFETCH , k ,
2023-09-13 00:16:02 +03:00
resume_logged_op ( trans , & iter , k ) ) ) ;
2023-12-17 06:43:41 +03:00
bch_err_fn ( c , ret ) ;
2023-08-28 01:27:41 +03:00
return ret ;
}
static int __bch2_logged_op_start ( struct btree_trans * trans , struct bkey_i * k )
{
struct btree_iter iter ;
int ret ;
ret = bch2_bkey_get_empty_slot ( trans , & iter , BTREE_ID_logged_ops , POS_MAX ) ;
if ( ret )
return ret ;
k - > k . p = iter . pos ;
ret = bch2_trans_update ( trans , & iter , k , 0 ) ;
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
int bch2_logged_op_start ( struct btree_trans * trans , struct bkey_i * k )
{
2023-11-12 00:31:50 +03:00
return commit_do ( trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
2023-08-28 01:27:41 +03:00
__bch2_logged_op_start ( trans , k ) ) ;
}
void bch2_logged_op_finish ( struct btree_trans * trans , struct bkey_i * k )
{
2023-11-12 00:31:50 +03:00
int ret = commit_do ( trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
2023-08-28 01:27:41 +03:00
bch2_btree_delete ( trans , BTREE_ID_logged_ops , k - > k . p , 0 ) ) ;
/*
* This needs to be a fatal error because we ' ve left an unfinished
* operation in the logged ops btree .
*
* We should only ever see an error here if the filesystem has already
* been shut down , but make sure of that here :
*/
if ( ret ) {
struct bch_fs * c = trans - > c ;
struct printbuf buf = PRINTBUF ;
bch2_bkey_val_to_text ( & buf , c , bkey_i_to_s_c ( k ) ) ;
2024-03-18 04:51:19 +03:00
bch2_fs_fatal_error ( c , " deleting logged operation %s: %s " ,
buf . buf , bch2_err_str ( ret ) ) ;
2023-08-28 01:27:41 +03:00
printbuf_exit ( & buf ) ;
}
}