2021-12-05 08:31:54 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
2022-02-17 11:11:39 +03:00
# include "alloc_background.h"
2021-12-05 08:31:54 +03:00
# include "btree_iter.h"
# include "btree_update.h"
# include "error.h"
# include "lru.h"
2022-02-17 11:11:39 +03:00
# include "recovery.h"
2021-12-05 08:31:54 +03:00
2022-04-04 00:50:01 +03:00
int bch2_lru_invalid ( const struct bch_fs * c , struct bkey_s_c k ,
2022-04-04 04:50:25 +03:00
int rw , struct printbuf * err )
2021-12-05 08:31:54 +03:00
{
const struct bch_lru * lru = bkey_s_c_to_lru ( k ) . v ;
2022-04-04 00:50:01 +03:00
if ( bkey_val_bytes ( k . k ) < sizeof ( * lru ) ) {
pr_buf ( err , " incorrect value size (%zu < %zu) " ,
bkey_val_bytes ( k . k ) , sizeof ( * lru ) ) ;
return - EINVAL ;
}
2021-12-05 08:31:54 +03:00
2022-04-04 00:50:01 +03:00
return 0 ;
2021-12-05 08:31:54 +03:00
}
void bch2_lru_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
const struct bch_lru * lru = bkey_s_c_to_lru ( k ) . v ;
pr_buf ( out , " idx %llu " , le64_to_cpu ( lru - > idx ) ) ;
}
2022-04-12 03:57:01 +03:00
int bch2_lru_delete ( struct btree_trans * trans , u64 id , u64 idx , u64 time ,
struct bkey_s_c orig_k )
2021-12-05 08:31:54 +03:00
{
struct btree_iter iter ;
struct bkey_s_c k ;
u64 existing_idx ;
2022-04-12 03:57:01 +03:00
struct printbuf buf = PRINTBUF ;
2021-12-05 08:31:54 +03:00
int ret = 0 ;
if ( ! time )
return 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_lru ,
POS ( id , time ) ,
BTREE_ITER_INTENT |
BTREE_ITER_WITH_UPDATES ) ;
k = bch2_btree_iter_peek_slot ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
if ( k . k - > type ! = KEY_TYPE_lru ) {
2022-04-12 03:57:01 +03:00
bch2_bkey_val_to_text ( & buf , trans - > c , orig_k ) ;
2022-04-11 01:12:04 +03:00
bch2_trans_inconsistent ( trans ,
2022-04-12 03:57:01 +03:00
" pointer to nonexistent lru %llu:%llu \n %s " ,
id , time , buf . buf ) ;
2021-12-05 08:31:54 +03:00
ret = - EIO ;
goto err ;
}
existing_idx = le64_to_cpu ( bkey_s_c_to_lru ( k ) . v - > idx ) ;
if ( existing_idx ! = idx ) {
2022-04-12 03:57:01 +03:00
bch2_bkey_val_to_text ( & buf , trans - > c , orig_k ) ;
2022-04-11 01:12:04 +03:00
bch2_trans_inconsistent ( trans ,
2022-04-12 03:57:01 +03:00
" lru %llu:%llu with wrong backpointer: got %llu, should be %llu \n %s " ,
id , time , existing_idx , idx , buf . buf ) ;
2021-12-05 08:31:54 +03:00
ret = - EIO ;
goto err ;
}
ret = bch2_btree_delete_at ( trans , & iter , 0 ) ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
2022-04-12 03:57:01 +03:00
printbuf_exit ( & buf ) ;
2021-12-05 08:31:54 +03:00
return ret ;
}
2022-04-11 02:59:26 +03:00
int bch2_lru_set ( struct btree_trans * trans , u64 lru_id , u64 idx , u64 * time )
2021-12-05 08:31:54 +03:00
{
struct btree_iter iter ;
struct bkey_s_c k ;
struct bkey_i_lru * lru ;
int ret = 0 ;
if ( ! * time )
return 0 ;
for_each_btree_key_norestart ( trans , iter , BTREE_ID_lru ,
POS ( lru_id , * time ) ,
BTREE_ITER_SLOTS |
BTREE_ITER_INTENT |
BTREE_ITER_WITH_UPDATES , k , ret )
if ( bkey_deleted ( k . k ) )
break ;
if ( ret )
goto err ;
BUG_ON ( iter . pos . inode ! = lru_id ) ;
* time = iter . pos . offset ;
lru = bch2_trans_kmalloc ( trans , sizeof ( * lru ) ) ;
ret = PTR_ERR_OR_ZERO ( lru ) ;
if ( ret )
goto err ;
bkey_lru_init ( & lru - > k_i ) ;
lru - > k . p = iter . pos ;
lru - > v . idx = cpu_to_le64 ( idx ) ;
ret = bch2_trans_update ( trans , & iter , & lru - > k_i , 0 ) ;
if ( ret )
goto err ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
int bch2_lru_change ( struct btree_trans * trans , u64 id , u64 idx ,
2022-04-12 03:57:01 +03:00
u64 old_time , u64 * new_time ,
struct bkey_s_c k )
2021-12-05 08:31:54 +03:00
{
if ( old_time = = * new_time )
return 0 ;
2022-04-12 03:57:01 +03:00
return bch2_lru_delete ( trans , id , idx , old_time , k ) ? :
2022-04-11 02:59:26 +03:00
bch2_lru_set ( trans , id , idx , new_time ) ;
2021-12-05 08:31:54 +03:00
}
2022-02-17 11:11:39 +03:00
static int bch2_check_lru_key ( struct btree_trans * trans ,
2022-05-14 13:58:51 +03:00
struct btree_iter * lru_iter )
2022-02-17 11:11:39 +03:00
{
struct bch_fs * c = trans - > c ;
struct btree_iter iter ;
struct bkey_s_c lru_k , k ;
struct bch_alloc_v4 a ;
struct printbuf buf1 = PRINTBUF ;
struct printbuf buf2 = PRINTBUF ;
2022-04-09 22:15:36 +03:00
struct bpos alloc_pos ;
2022-02-17 11:11:39 +03:00
int ret ;
lru_k = bch2_btree_iter_peek ( lru_iter ) ;
if ( ! lru_k . k )
return 0 ;
ret = bkey_err ( lru_k ) ;
if ( ret )
return ret ;
2022-04-09 22:15:36 +03:00
alloc_pos = POS ( lru_k . k - > p . inode ,
le64_to_cpu ( bkey_s_c_to_lru ( lru_k ) . v - > idx ) ) ;
2022-02-17 11:11:39 +03:00
2022-04-09 22:15:36 +03:00
if ( fsck_err_on ( ! bch2_dev_bucket_exists ( c , alloc_pos ) , c ,
" lru key points to nonexistent device:bucket %llu:%llu " ,
alloc_pos . inode , alloc_pos . offset ) )
return bch2_btree_delete_at ( trans , lru_iter , 0 ) ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_alloc , alloc_pos , 0 ) ;
2022-02-17 11:11:39 +03:00
k = bch2_btree_iter_peek_slot ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
bch2_alloc_to_v4 ( k , & a ) ;
2022-04-01 08:29:59 +03:00
if ( fsck_err_on ( a . data_type ! = BCH_DATA_cached | |
2022-02-17 11:11:39 +03:00
a . io_time [ READ ] ! = lru_k . k - > p . offset , c ,
" incorrect lru entry %s \n "
" for %s " ,
( bch2_bkey_val_to_text ( & buf1 , c , lru_k ) , buf1 . buf ) ,
( bch2_bkey_val_to_text ( & buf2 , c , k ) , buf2 . buf ) ) ) {
struct bkey_i * update =
bch2_trans_kmalloc ( trans , sizeof ( * update ) ) ;
ret = PTR_ERR_OR_ZERO ( update ) ;
if ( ret )
goto err ;
bkey_init ( & update - > k ) ;
update - > k . p = lru_iter - > pos ;
ret = bch2_trans_update ( trans , lru_iter , update , 0 ) ;
if ( ret )
goto err ;
}
err :
fsck_err :
bch2_trans_iter_exit ( trans , & iter ) ;
printbuf_exit ( & buf2 ) ;
printbuf_exit ( & buf1 ) ;
return ret ;
}
2022-05-14 13:58:51 +03:00
int bch2_check_lrus ( struct bch_fs * c )
2022-02-17 11:11:39 +03:00
{
struct btree_trans trans ;
struct btree_iter iter ;
struct bkey_s_c k ;
int ret = 0 ;
bch2_trans_init ( & trans , c , 0 , 0 ) ;
for_each_btree_key ( & trans , iter , BTREE_ID_lru , POS_MIN ,
BTREE_ITER_PREFETCH , k , ret ) {
2022-04-21 20:13:57 +03:00
ret = __bch2_trans_do ( & trans , NULL , NULL ,
BTREE_INSERT_NOFAIL |
BTREE_INSERT_LAZY_RW ,
2022-05-14 13:58:51 +03:00
bch2_check_lru_key ( & trans , & iter ) ) ;
2022-02-17 11:11:39 +03:00
if ( ret )
break ;
}
bch2_trans_iter_exit ( & trans , & iter ) ;
bch2_trans_exit ( & trans ) ;
return ret ;
}