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"
2023-02-07 02:51:42 +03:00
# include "btree_write_buffer.h"
2021-12-05 08:31:54 +03:00
# 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-12-06 00:49:13 +03:00
/* KEY_TYPE_lru is obsolete: */
2022-04-04 00:50:01 +03:00
int bch2_lru_invalid ( const struct bch_fs * c , struct bkey_s_c k ,
2023-07-07 04:16:10 +03:00
enum bkey_invalid_flags flags ,
struct printbuf * err )
2021-12-05 08:31:54 +03:00
{
2022-12-06 00:49:13 +03:00
if ( ! lru_pos_time ( k . k - > p ) ) {
2023-01-04 08:00:55 +03:00
prt_printf ( err , " lru entry at time=0 " ) ;
return - BCH_ERR_invalid_bkey ;
}
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 ;
2023-02-04 05:01:40 +03:00
prt_printf ( out , " idx %llu " , le64_to_cpu ( lru - > idx ) ) ;
2021-12-05 08:31:54 +03:00
}
2023-01-04 07:54:10 +03:00
void bch2_lru_pos_to_text ( struct printbuf * out , struct bpos lru )
{
prt_printf ( out , " %llu:%llu -> %llu:%llu " ,
lru_pos_id ( lru ) ,
lru_pos_time ( lru ) ,
u64_to_bucket ( lru . offset ) . inode ,
u64_to_bucket ( lru . offset ) . offset ) ;
}
2022-12-06 00:49:13 +03:00
static int __bch2_lru_set ( struct btree_trans * trans , u16 lru_id ,
2023-07-17 07:56:07 +03:00
u64 dev_bucket , u64 time , bool set )
2021-12-05 08:31:54 +03:00
{
2023-07-17 07:56:07 +03:00
return time
? bch2_btree_bit_mod ( trans , BTREE_ID_lru ,
lru_pos ( lru_id , dev_bucket , time ) , set )
: 0 ;
2021-12-05 08:31:54 +03:00
}
2022-12-06 00:49:13 +03:00
int bch2_lru_del ( struct btree_trans * trans , u16 lru_id , u64 dev_bucket , u64 time )
2021-12-05 08:31:54 +03:00
{
2022-12-06 00:49:13 +03:00
return __bch2_lru_set ( trans , lru_id , dev_bucket , time , KEY_TYPE_deleted ) ;
}
2021-12-05 08:31:54 +03:00
2022-12-06 00:49:13 +03:00
int bch2_lru_set ( struct btree_trans * trans , u16 lru_id , u64 dev_bucket , u64 time )
{
return __bch2_lru_set ( trans , lru_id , dev_bucket , time , KEY_TYPE_set ) ;
2021-12-05 08:31:54 +03:00
}
2022-12-06 00:49:13 +03:00
int bch2_lru_change ( struct btree_trans * trans ,
u16 lru_id , u64 dev_bucket ,
u64 old_time , u64 new_time )
2021-12-05 08:31:54 +03:00
{
2022-12-06 00:49:13 +03:00
if ( old_time = = new_time )
2021-12-05 08:31:54 +03:00
return 0 ;
2022-12-06 00:49:13 +03:00
return bch2_lru_del ( trans , lru_id , dev_bucket , old_time ) ? :
bch2_lru_set ( trans , lru_id , dev_bucket , new_time ) ;
2021-12-05 08:31:54 +03:00
}
2022-02-17 11:11:39 +03:00
2022-12-05 18:24:19 +03:00
static const char * const bch2_lru_types [ ] = {
# define x(n) #n,
BCH_LRU_TYPES ( )
# undef x
NULL
} ;
2022-02-17 11:11:39 +03:00
static int bch2_check_lru_key ( struct btree_trans * trans ,
2022-07-17 07:44:19 +03:00
struct btree_iter * lru_iter ,
2023-02-07 02:51:42 +03:00
struct bkey_s_c lru_k ,
struct bpos * last_flushed_pos )
2022-02-17 11:11:39 +03:00
{
struct bch_fs * c = trans - > c ;
struct btree_iter iter ;
2022-07-17 07:44:19 +03:00
struct bkey_s_c k ;
2023-01-31 04:58:43 +03:00
struct bch_alloc_v4 a_convert ;
const struct bch_alloc_v4 * a ;
2022-02-17 11:11:39 +03:00
struct printbuf buf1 = PRINTBUF ;
struct printbuf buf2 = PRINTBUF ;
2022-12-05 18:24:19 +03:00
enum bch_lru_type type = lru_type ( lru_k ) ;
2022-12-06 00:49:13 +03:00
struct bpos alloc_pos = u64_to_bucket ( lru_k . k - > p . offset ) ;
2022-12-05 18:24:19 +03:00
u64 idx ;
2022-02-17 11:11:39 +03:00
int ret ;
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 ) ;
2023-04-30 02:33:09 +03:00
k = bch2_bkey_get_iter ( trans , & iter , BTREE_ID_alloc , alloc_pos , 0 ) ;
2022-02-17 11:11:39 +03:00
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
2023-01-31 04:58:43 +03:00
a = bch2_alloc_to_v4 ( k , & a_convert ) ;
2022-02-17 11:11:39 +03:00
2022-12-05 18:24:19 +03:00
switch ( type ) {
case BCH_LRU_read :
idx = alloc_lru_idx_read ( * a ) ;
break ;
case BCH_LRU_fragmentation :
idx = a - > fragmentation_lru ;
break ;
}
2023-02-07 02:51:42 +03:00
if ( lru_k . k - > type ! = KEY_TYPE_set | |
2022-12-05 18:24:19 +03:00
lru_pos_time ( lru_k . k - > p ) ! = idx ) {
2023-02-07 02:51:42 +03:00
if ( ! bpos_eq ( * last_flushed_pos , lru_k . k - > p ) ) {
* last_flushed_pos = lru_k . k - > p ;
ret = bch2_btree_write_buffer_flush_sync ( trans ) ? :
- BCH_ERR_transaction_restart_write_buffer_flush ;
goto out ;
}
2023-03-19 21:29:51 +03:00
if ( c - > opts . reconstruct_alloc | |
fsck_err ( c , " incorrect lru entry: lru %s time %llu \n "
2022-12-05 18:24:19 +03:00
" %s \n "
" for %s " ,
bch2_lru_types [ type ] ,
lru_pos_time ( lru_k . k - > p ) ,
( bch2_bkey_val_to_text ( & buf1 , c , lru_k ) , buf1 . buf ) ,
( bch2_bkey_val_to_text ( & buf2 , c , k ) , buf2 . buf ) ) )
2023-02-07 02:51:42 +03:00
ret = bch2_btree_delete_at ( trans , lru_iter , 0 ) ;
2022-02-17 11:11:39 +03:00
}
2023-02-07 02:51:42 +03:00
out :
2022-02-17 11:11:39 +03:00
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_iter iter ;
struct bkey_s_c k ;
2023-02-07 02:51:42 +03:00
struct bpos last_flushed_pos = POS_MIN ;
2022-02-17 11:11:39 +03:00
int ret = 0 ;
2023-06-20 20:49:25 +03:00
ret = bch2_trans_run ( c ,
for_each_btree_key_commit ( & trans , iter ,
BTREE_ID_lru , POS_MIN , BTREE_ITER_PREFETCH , k ,
NULL , NULL , BTREE_INSERT_NOFAIL | BTREE_INSERT_LAZY_RW ,
bch2_check_lru_key ( & trans , & iter , k , & last_flushed_pos ) ) ) ;
if ( ret )
bch_err_fn ( c , ret ) ;
2022-02-17 11:11:39 +03:00
return ret ;
}