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 ,
2022-12-21 03:58:16 +03:00
unsigned flags , 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 ) ) {
2023-02-04 05:01:40 +03:00
prt_printf ( err , " incorrect value size (%zu < %zu) " ,
2022-04-04 00:50:01 +03:00
bkey_val_bytes ( k . k ) , sizeof ( * lru ) ) ;
2022-11-20 06:39:08 +03:00
return - BCH_ERR_invalid_bkey ;
2022-04-04 00:50:01 +03:00
}
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 ,
u64 dev_bucket , u64 time , unsigned key_type )
2021-12-05 08:31:54 +03:00
{
2022-12-06 00:49:13 +03:00
struct bkey_i * k ;
2021-12-05 08:31:54 +03:00
int ret = 0 ;
if ( ! time )
return 0 ;
2022-12-06 00:49:13 +03:00
k = bch2_trans_kmalloc_nomemzero ( trans , sizeof ( * k ) ) ;
ret = PTR_ERR_OR_ZERO ( k ) ;
if ( unlikely ( ret ) )
return ret ;
2021-12-05 08:31:54 +03:00
2022-12-06 00:49:13 +03:00
bkey_init ( & k - > k ) ;
k - > k . type = key_type ;
k - > k . p = lru_pos ( lru_id , dev_bucket , time ) ;
2021-12-05 08:31:54 +03:00
2022-12-06 00:49:13 +03:00
EBUG_ON ( lru_pos_id ( k - > k . p ) ! = lru_id ) ;
EBUG_ON ( lru_pos_time ( k - > k . p ) ! = time ) ;
EBUG_ON ( k - > k . p . offset ! = dev_bucket ) ;
2021-12-05 08:31:54 +03:00
2023-02-07 02:51:42 +03:00
return bch2_trans_update_buffered ( trans , BTREE_ID_lru , k ) ;
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
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-06 00:49:13 +03:00
struct bpos alloc_pos = u64_to_bucket ( lru_k . k - > p . offset ) ;
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 ) ;
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 ;
2023-01-31 04:58:43 +03:00
a = bch2_alloc_to_v4 ( k , & a_convert ) ;
2022-02-17 11:11:39 +03:00
2023-02-07 02:51:42 +03:00
if ( lru_k . k - > type ! = KEY_TYPE_set | |
a - > data_type ! = BCH_DATA_cached | |
a - > io_time [ READ ] ! = lru_pos_time ( lru_k . k - > p ) ) { }
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 ;
}
if ( fsck_err_on ( lru_k . k - > type ! = KEY_TYPE_set | |
a - > data_type ! = BCH_DATA_cached | |
a - > io_time [ READ ] ! = lru_pos_time ( lru_k . k - > p ) , c ,
" incorrect lru entry (time %llu) %s \n "
" for %s " ,
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 ) ) ) {
ret = bch2_btree_delete_at ( trans , lru_iter , 0 ) ;
if ( ret )
goto err ;
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_trans trans ;
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 ;
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2022-07-17 07:44:19 +03:00
ret = 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 ,
2023-02-07 02:51:42 +03:00
bch2_check_lru_key ( & trans , & iter , k , & last_flushed_pos ) ) ;
2022-02-17 11:11:39 +03:00
bch2_trans_exit ( & trans ) ;
return ret ;
}