2017-03-17 09:18:50 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "bkey_methods.h"
# include "btree_types.h"
2018-10-06 07:46:55 +03:00
# include "alloc_background.h"
2017-03-17 09:18:50 +03:00
# include "dirent.h"
2018-11-01 22:13:19 +03:00
# include "ec.h"
2017-03-17 09:18:50 +03:00
# include "error.h"
# include "extents.h"
# include "inode.h"
# include "quota.h"
# include "xattr.h"
2018-11-01 22:10:01 +03:00
const char * const bch_bkey_types [ ] = {
# define x(name, nr) #name,
BCH_BKEY_TYPES ( )
# undef x
NULL
2017-03-17 09:18:50 +03:00
} ;
2018-11-01 22:10:01 +03:00
static const char * deleted_key_invalid ( const struct bch_fs * c ,
struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
2018-11-01 22:10:01 +03:00
return NULL ;
}
2018-12-10 00:20:52 +03:00
# define bch2_bkey_ops_deleted (struct bkey_ops) { \
. key_invalid = deleted_key_invalid , \
}
2018-11-01 22:10:01 +03:00
2018-12-10 00:20:52 +03:00
# define bch2_bkey_ops_discard (struct bkey_ops) { \
. key_invalid = deleted_key_invalid , \
}
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
static const char * empty_val_key_invalid ( const struct bch_fs * c , struct bkey_s_c k )
{
if ( bkey_val_bytes ( k . k ) )
return " value size should be zero " ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
return NULL ;
}
2017-03-17 09:18:50 +03:00
2018-12-10 00:20:52 +03:00
# define bch2_bkey_ops_error (struct bkey_ops) { \
. key_invalid = empty_val_key_invalid , \
}
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
static const char * key_type_cookie_invalid ( const struct bch_fs * c ,
struct bkey_s_c k )
{
if ( bkey_val_bytes ( k . k ) ! = sizeof ( struct bch_cookie ) )
return " incorrect value size " ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
return NULL ;
2017-03-17 09:18:50 +03:00
}
2018-12-10 00:20:52 +03:00
# define bch2_bkey_ops_cookie (struct bkey_ops) { \
. key_invalid = key_type_cookie_invalid , \
}
2018-11-01 22:10:01 +03:00
2018-12-10 00:20:52 +03:00
# define bch2_bkey_ops_whiteout (struct bkey_ops) { \
. key_invalid = empty_val_key_invalid , \
}
2018-11-01 22:10:01 +03:00
static const struct bkey_ops bch2_bkey_ops [ ] = {
# define x(name, nr) [KEY_TYPE_##name] = bch2_bkey_ops_##name,
BCH_BKEY_TYPES ( )
# undef x
} ;
const char * bch2_bkey_val_invalid ( struct bch_fs * c , struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
2018-11-01 22:10:01 +03:00
if ( k . k - > type > = KEY_TYPE_MAX )
return " invalid type " ;
return bch2_bkey_ops [ k . k - > type ] . key_invalid ( c , k ) ;
}
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
const char * __bch2_bkey_invalid ( struct bch_fs * c , struct bkey_s_c k ,
enum btree_node_type type )
{
2017-03-17 09:18:50 +03:00
if ( k . k - > u64s < BKEY_U64s )
return " u64s too small " ;
2018-11-01 22:10:01 +03:00
if ( btree_node_type_is_extents ( type ) ) {
2017-03-17 09:18:50 +03:00
if ( ( k . k - > size = = 0 ) ! = bkey_deleted ( k . k ) )
return " bad size field " ;
2018-11-01 22:10:01 +03:00
} else {
if ( k . k - > size )
return " nonzero size field " ;
2017-03-17 09:18:50 +03:00
}
if ( k . k - > p . snapshot )
return " nonzero snapshot " ;
if ( type ! = BKEY_TYPE_BTREE & &
! bkey_cmp ( k . k - > p , POS_MAX ) )
return " POS_MAX key " ;
return NULL ;
}
2018-11-01 22:10:01 +03:00
const char * bch2_bkey_invalid ( struct bch_fs * c , struct bkey_s_c k ,
enum btree_node_type type )
2017-03-17 09:18:50 +03:00
{
2018-11-01 22:10:01 +03:00
return __bch2_bkey_invalid ( c , k , type ) ? :
bch2_bkey_val_invalid ( c , k ) ;
2017-03-17 09:18:50 +03:00
}
const char * bch2_bkey_in_btree_node ( struct btree * b , struct bkey_s_c k )
{
if ( bkey_cmp ( bkey_start_pos ( k . k ) , b - > data - > min_key ) < 0 )
return " key before start of btree node " ;
if ( bkey_cmp ( k . k - > p , b - > data - > max_key ) > 0 )
return " key past end of btree node " ;
return NULL ;
}
void bch2_bkey_debugcheck ( struct bch_fs * c , struct btree * b , struct bkey_s_c k )
{
2018-11-01 22:10:01 +03:00
const struct bkey_ops * ops = & bch2_bkey_ops [ k . k - > type ] ;
2017-03-17 09:18:50 +03:00
const char * invalid ;
BUG_ON ( ! k . k - > u64s ) ;
2018-11-01 22:10:01 +03:00
invalid = bch2_bkey_invalid ( c , k , btree_node_type ( b ) ) ? :
2017-03-17 09:18:50 +03:00
bch2_bkey_in_btree_node ( b , k ) ;
if ( invalid ) {
char buf [ 160 ] ;
2018-11-01 22:10:01 +03:00
bch2_bkey_val_to_text ( & PBUF ( buf ) , c , k ) ;
2017-03-17 09:18:50 +03:00
bch2_fs_bug ( c , " invalid bkey %s: %s " , buf , invalid ) ;
return ;
}
2018-11-01 22:10:01 +03:00
if ( ops - > key_debugcheck )
2017-03-17 09:18:50 +03:00
ops - > key_debugcheck ( c , b , k ) ;
}
2018-11-09 09:24:07 +03:00
void bch2_bpos_to_text ( struct printbuf * out , struct bpos pos )
2018-07-23 16:13:07 +03:00
{
if ( ! bkey_cmp ( pos , POS_MIN ) )
2018-11-09 09:24:07 +03:00
pr_buf ( out , " POS_MIN " ) ;
2018-07-23 16:13:07 +03:00
else if ( ! bkey_cmp ( pos , POS_MAX ) )
2018-11-09 09:24:07 +03:00
pr_buf ( out , " POS_MAX " ) ;
2018-07-23 16:13:07 +03:00
else
2018-11-09 09:24:07 +03:00
pr_buf ( out , " %llu:%llu " , pos . inode , pos . offset ) ;
2018-07-23 16:13:07 +03:00
}
2018-11-09 09:24:07 +03:00
void bch2_bkey_to_text ( struct printbuf * out , const struct bkey * k )
2017-03-17 09:18:50 +03:00
{
2018-11-09 09:24:07 +03:00
pr_buf ( out , " u64s %u type %u " , k - > u64s , k - > type ) ;
2017-03-17 09:18:50 +03:00
2018-11-09 09:24:07 +03:00
bch2_bpos_to_text ( out , k - > p ) ;
2017-03-17 09:18:50 +03:00
2018-11-09 09:24:07 +03:00
pr_buf ( out , " snap %u len %u ver %llu " ,
k - > p . snapshot , k - > size , k - > version . lo ) ;
2017-03-17 09:18:50 +03:00
}
2018-11-09 09:24:07 +03:00
void bch2_val_to_text ( struct printbuf * out , struct bch_fs * c ,
2018-11-01 22:10:01 +03:00
struct bkey_s_c k )
{
const struct bkey_ops * ops = & bch2_bkey_ops [ k . k - > type ] ;
if ( likely ( ops - > val_to_text ) )
ops - > val_to_text ( out , c , k ) ;
else
pr_buf ( out , " %s " , bch_bkey_types [ k . k - > type ] ) ;
2017-03-17 09:18:50 +03:00
}
2018-11-09 09:24:07 +03:00
void bch2_bkey_val_to_text ( struct printbuf * out , struct bch_fs * c ,
2018-11-01 22:10:01 +03:00
struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
2018-11-09 09:24:07 +03:00
bch2_bkey_to_text ( out , k . k ) ;
pr_buf ( out , " : " ) ;
2018-11-01 22:10:01 +03:00
bch2_val_to_text ( out , c , k ) ;
2017-03-17 09:18:50 +03:00
}
2018-11-01 22:10:01 +03:00
void bch2_bkey_swab ( const struct bkey_format * f ,
struct bkey_packed * k )
2017-03-17 09:18:50 +03:00
{
2018-11-01 22:10:01 +03:00
const struct bkey_ops * ops = & bch2_bkey_ops [ k - > type ] ;
2017-03-17 09:18:50 +03:00
bch2_bkey_swab_key ( f , k ) ;
if ( ops - > swab )
ops - > swab ( f , k ) ;
}
2018-11-01 22:10:01 +03:00
bool bch2_bkey_normalize ( struct bch_fs * c , struct bkey_s k )
{
const struct bkey_ops * ops = & bch2_bkey_ops [ k . k - > type ] ;
return ops - > key_normalize
? ops - > key_normalize ( c , k )
: false ;
}
enum merge_result bch2_bkey_merge ( struct bch_fs * c ,
struct bkey_i * l , struct bkey_i * r )
{
const struct bkey_ops * ops = & bch2_bkey_ops [ l - > k . type ] ;
if ( ! key_merging_disabled ( c ) & &
ops - > key_merge & &
l - > k . type = = r - > k . type & &
! bversion_cmp ( l - > k . version , r - > k . version ) & &
! bkey_cmp ( l - > k . p , bkey_start_pos ( & r - > k ) ) )
return ops - > key_merge ( c , l , r ) ;
return BCH_MERGE_NOMERGE ;
}
static const struct old_bkey_type {
u8 btree_node_type ;
u8 old ;
u8 new ;
} bkey_renumber_table [ ] = {
{ BKEY_TYPE_BTREE , 128 , KEY_TYPE_btree_ptr } ,
{ BKEY_TYPE_EXTENTS , 128 , KEY_TYPE_extent } ,
{ BKEY_TYPE_EXTENTS , 129 , KEY_TYPE_extent } ,
{ BKEY_TYPE_EXTENTS , 130 , KEY_TYPE_reservation } ,
{ BKEY_TYPE_INODES , 128 , KEY_TYPE_inode } ,
{ BKEY_TYPE_INODES , 130 , KEY_TYPE_inode_generation } ,
{ BKEY_TYPE_DIRENTS , 128 , KEY_TYPE_dirent } ,
{ BKEY_TYPE_DIRENTS , 129 , KEY_TYPE_whiteout } ,
{ BKEY_TYPE_XATTRS , 128 , KEY_TYPE_xattr } ,
{ BKEY_TYPE_XATTRS , 129 , KEY_TYPE_whiteout } ,
{ BKEY_TYPE_ALLOC , 128 , KEY_TYPE_alloc } ,
{ BKEY_TYPE_QUOTAS , 128 , KEY_TYPE_quota } ,
} ;
void bch2_bkey_renumber ( enum btree_node_type btree_node_type ,
struct bkey_packed * k ,
int write )
{
const struct old_bkey_type * i ;
for ( i = bkey_renumber_table ;
i < bkey_renumber_table + ARRAY_SIZE ( bkey_renumber_table ) ;
i + + )
if ( btree_node_type = = i - > btree_node_type & &
k - > type = = ( write ? i - > new : i - > old ) ) {
k - > type = write ? i - > old : i - > new ;
break ;
}
}