2017-03-16 22:18:50 -08:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "bkey_methods.h"
# include "btree_types.h"
2018-10-06 00:46:55 -04:00
# include "alloc_background.h"
2017-03-16 22:18:50 -08:00
# include "dirent.h"
2018-11-01 15:13:19 -04:00
# include "ec.h"
2017-03-16 22:18:50 -08:00
# include "error.h"
# include "extents.h"
# include "inode.h"
# include "quota.h"
2019-08-16 09:59:56 -04:00
# include "reflink.h"
2017-03-16 22:18:50 -08:00
# include "xattr.h"
2019-07-16 12:23:04 -04:00
const char * const bch2_bkey_types [ ] = {
2018-11-01 15:10:01 -04:00
# define x(name, nr) #name,
BCH_BKEY_TYPES ( )
# undef x
NULL
2017-03-16 22:18:50 -08:00
} ;
2018-11-01 15:10:01 -04:00
static const char * deleted_key_invalid ( const struct bch_fs * c ,
struct bkey_s_c k )
2017-03-16 22:18:50 -08:00
{
2018-11-01 15:10:01 -04:00
return NULL ;
}
2018-12-09 13:20:52 -08:00
# define bch2_bkey_ops_deleted (struct bkey_ops) { \
. key_invalid = deleted_key_invalid , \
}
2018-11-01 15:10:01 -04:00
2018-12-09 13:20:52 -08:00
# define bch2_bkey_ops_discard (struct bkey_ops) { \
. key_invalid = deleted_key_invalid , \
}
2017-03-16 22:18:50 -08:00
2018-11-01 15:10:01 -04: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-16 22:18:50 -08:00
2018-11-01 15:10:01 -04:00
return NULL ;
}
2017-03-16 22:18:50 -08:00
2018-12-09 13:20:52 -08:00
# define bch2_bkey_ops_error (struct bkey_ops) { \
. key_invalid = empty_val_key_invalid , \
}
2017-03-16 22:18:50 -08:00
2018-11-01 15:10:01 -04: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-16 22:18:50 -08:00
2018-11-01 15:10:01 -04:00
return NULL ;
2017-03-16 22:18:50 -08:00
}
2018-12-09 13:20:52 -08:00
# define bch2_bkey_ops_cookie (struct bkey_ops) { \
. key_invalid = key_type_cookie_invalid , \
}
2018-11-01 15:10:01 -04:00
2018-12-09 13:20:52 -08:00
# define bch2_bkey_ops_whiteout (struct bkey_ops) { \
. key_invalid = empty_val_key_invalid , \
}
2018-11-01 15:10:01 -04:00
2019-11-09 16:43:16 -05:00
static const char * key_type_inline_data_invalid ( const struct bch_fs * c ,
struct bkey_s_c k )
{
return NULL ;
}
static void key_type_inline_data_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
pr_buf ( out , " (%zu bytes) " , bkey_val_bytes ( k . k ) ) ;
}
2019-11-26 17:09:32 -05:00
# define bch2_bkey_ops_inline_data (struct bkey_ops) { \
. key_invalid = key_type_inline_data_invalid , \
. val_to_text = key_type_inline_data_to_text , \
}
2019-11-09 16:43:16 -05:00
2018-11-01 15:10:01 -04: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-16 22:18:50 -08:00
{
2018-11-01 15:10:01 -04:00
if ( k . k - > type > = KEY_TYPE_MAX )
return " invalid type " ;
return bch2_bkey_ops [ k . k - > type ] . key_invalid ( c , k ) ;
}
2017-03-16 22:18:50 -08:00
2018-11-01 15:10:01 -04:00
const char * __bch2_bkey_invalid ( struct bch_fs * c , struct bkey_s_c k ,
enum btree_node_type type )
{
2017-03-16 22:18:50 -08:00
if ( k . k - > u64s < BKEY_U64s )
return " u64s too small " ;
2019-11-09 16:43:16 -05:00
if ( type = = BKEY_TYPE_BTREE & &
bkey_val_u64s ( k . k ) > BKEY_BTREE_PTR_VAL_U64s_MAX )
2019-06-09 20:32:54 -04:00
return " value too big " ;
2018-11-01 15:10:01 -04:00
if ( btree_node_type_is_extents ( type ) ) {
2017-03-16 22:18:50 -08:00
if ( ( k . k - > size = = 0 ) ! = bkey_deleted ( k . k ) )
return " bad size field " ;
2019-06-29 18:03:40 -04:00
if ( k . k - > size > k . k - > p . offset )
return " size greater than offset " ;
2018-11-01 15:10:01 -04:00
} else {
if ( k . k - > size )
return " nonzero size field " ;
2017-03-16 22:18:50 -08: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 15:10:01 -04:00
const char * bch2_bkey_invalid ( struct bch_fs * c , struct bkey_s_c k ,
enum btree_node_type type )
2017-03-16 22:18:50 -08:00
{
2018-11-01 15:10:01 -04:00
return __bch2_bkey_invalid ( c , k , type ) ? :
bch2_bkey_val_invalid ( c , k ) ;
2017-03-16 22:18:50 -08:00
}
const char * bch2_bkey_in_btree_node ( struct btree * b , struct bkey_s_c k )
{
2020-03-15 23:29:43 -04:00
if ( bkey_cmp ( k . k - > p , b - > data - > min_key ) < 0 )
2017-03-16 22:18:50 -08:00
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 15:10:01 -04:00
const struct bkey_ops * ops = & bch2_bkey_ops [ k . k - > type ] ;
2017-03-16 22:18:50 -08:00
const char * invalid ;
BUG_ON ( ! k . k - > u64s ) ;
2018-11-01 15:10:01 -04:00
invalid = bch2_bkey_invalid ( c , k , btree_node_type ( b ) ) ? :
2017-03-16 22:18:50 -08:00
bch2_bkey_in_btree_node ( b , k ) ;
if ( invalid ) {
char buf [ 160 ] ;
2018-11-01 15:10:01 -04:00
bch2_bkey_val_to_text ( & PBUF ( buf ) , c , k ) ;
2020-01-04 16:09:52 -05:00
bch2_fs_inconsistent ( c , " invalid bkey %s: %s " , buf , invalid ) ;
2017-03-16 22:18:50 -08:00
return ;
}
2018-11-01 15:10:01 -04:00
if ( ops - > key_debugcheck )
2019-09-14 10:47:14 -04:00
ops - > key_debugcheck ( c , k ) ;
2017-03-16 22:18:50 -08:00
}
2018-11-09 01:24:07 -05:00
void bch2_bpos_to_text ( struct printbuf * out , struct bpos pos )
2018-07-23 09:13:07 -04:00
{
if ( ! bkey_cmp ( pos , POS_MIN ) )
2018-11-09 01:24:07 -05:00
pr_buf ( out , " POS_MIN " ) ;
2018-07-23 09:13:07 -04:00
else if ( ! bkey_cmp ( pos , POS_MAX ) )
2018-11-09 01:24:07 -05:00
pr_buf ( out , " POS_MAX " ) ;
2018-07-23 09:13:07 -04:00
else
2018-11-09 01:24:07 -05:00
pr_buf ( out , " %llu:%llu " , pos . inode , pos . offset ) ;
2018-07-23 09:13:07 -04:00
}
2018-11-09 01:24:07 -05:00
void bch2_bkey_to_text ( struct printbuf * out , const struct bkey * k )
2017-03-16 22:18:50 -08:00
{
2019-07-16 12:23:04 -04:00
pr_buf ( out , " u64s %u type %s " , k - > u64s ,
bch2_bkey_types [ k - > type ] ) ;
2017-03-16 22:18:50 -08:00
2018-11-09 01:24:07 -05:00
bch2_bpos_to_text ( out , k - > p ) ;
2017-03-16 22:18:50 -08:00
2018-11-09 01:24:07 -05:00
pr_buf ( out , " snap %u len %u ver %llu " ,
k - > p . snapshot , k - > size , k - > version . lo ) ;
2017-03-16 22:18:50 -08:00
}
2018-11-09 01:24:07 -05:00
void bch2_val_to_text ( struct printbuf * out , struct bch_fs * c ,
2018-11-01 15:10:01 -04: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 ) ;
2017-03-16 22:18:50 -08:00
}
2018-11-09 01:24:07 -05:00
void bch2_bkey_val_to_text ( struct printbuf * out , struct bch_fs * c ,
2018-11-01 15:10:01 -04:00
struct bkey_s_c k )
2017-03-16 22:18:50 -08:00
{
2018-11-09 01:24:07 -05:00
bch2_bkey_to_text ( out , k . k ) ;
pr_buf ( out , " : " ) ;
2018-11-01 15:10:01 -04:00
bch2_val_to_text ( out , c , k ) ;
2017-03-16 22:18:50 -08:00
}
2020-02-06 20:15:15 -05:00
void bch2_bkey_swab_val ( struct bkey_s k )
2017-03-16 22:18:50 -08:00
{
2020-02-06 20:15:15 -05:00
const struct bkey_ops * ops = & bch2_bkey_ops [ k . k - > type ] ;
2017-03-16 22:18:50 -08:00
if ( ops - > swab )
2020-02-06 20:15:15 -05:00
ops - > swab ( k ) ;
2017-03-16 22:18:50 -08:00
}
2018-11-01 15:10:01 -04: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 ,
2019-06-09 16:56:16 -04:00
struct bkey_s l , struct bkey_s r )
2018-11-01 15:10:01 -04:00
{
2019-06-09 16:56:16 -04:00
const struct bkey_ops * ops = & bch2_bkey_ops [ l . k - > type ] ;
2019-05-12 22:23:30 -04:00
enum merge_result ret ;
2018-11-01 15:10:01 -04:00
2019-05-12 22:23:30 -04:00
if ( key_merging_disabled ( c ) | |
! ops - > key_merge | |
2019-06-09 16:56:16 -04:00
l . k - > type ! = r . k - > type | |
bversion_cmp ( l . k - > version , r . k - > version ) | |
bkey_cmp ( l . k - > p , bkey_start_pos ( r . k ) ) )
2019-05-12 22:23:30 -04:00
return BCH_MERGE_NOMERGE ;
2018-11-01 15:10:01 -04:00
2019-05-12 22:23:30 -04:00
ret = ops - > key_merge ( c , l , r ) ;
if ( ret ! = BCH_MERGE_NOMERGE )
2019-06-09 16:56:16 -04:00
l . k - > needs_whiteout | = r . k - > needs_whiteout ;
2019-05-12 22:23:30 -04:00
return ret ;
2018-11-01 15:10:01 -04:00
}
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 ;
}
}
2020-01-07 13:29:32 -05:00
void __bch2_bkey_compat ( unsigned level , enum btree_id btree_id ,
unsigned version , unsigned big_endian ,
int write ,
struct bkey_format * f ,
struct bkey_packed * k )
{
const struct bkey_ops * ops ;
struct bkey uk ;
struct bkey_s u ;
2020-04-24 14:08:18 -04:00
int i ;
/*
* Do these operations in reverse order in the write path :
*/
for ( i = 0 ; i < 4 ; i + + )
switch ( ! write ? i : 3 - i ) {
case 0 :
if ( big_endian ! = CPU_BIG_ENDIAN )
bch2_bkey_swab_key ( f , k ) ;
break ;
case 1 :
if ( version < bcachefs_metadata_version_bkey_renumber )
bch2_bkey_renumber ( __btree_node_type ( level , btree_id ) , k , write ) ;
break ;
case 2 :
if ( version < bcachefs_metadata_version_inode_btree_change & &
btree_id = = BTREE_ID_INODES ) {
if ( ! bkey_packed ( k ) ) {
struct bkey_i * u = packed_to_bkey ( k ) ;
swap ( u - > k . p . inode , u - > k . p . offset ) ;
} else if ( f - > bits_per_field [ BKEY_FIELD_INODE ] & &
f - > bits_per_field [ BKEY_FIELD_OFFSET ] ) {
struct bkey_format tmp = * f , * in = f , * out = & tmp ;
swap ( tmp . bits_per_field [ BKEY_FIELD_INODE ] ,
tmp . bits_per_field [ BKEY_FIELD_OFFSET ] ) ;
swap ( tmp . field_offset [ BKEY_FIELD_INODE ] ,
tmp . field_offset [ BKEY_FIELD_OFFSET ] ) ;
if ( ! write )
swap ( in , out ) ;
uk = __bch2_bkey_unpack_key ( in , k ) ;
swap ( uk . p . inode , uk . p . offset ) ;
BUG_ON ( ! bch2_bkey_pack_key ( k , & uk , out ) ) ;
}
}
break ;
case 3 :
2020-01-07 13:29:32 -05:00
if ( ! bkey_packed ( k ) ) {
2020-04-24 14:08:18 -04:00
u = bkey_i_to_s ( packed_to_bkey ( k ) ) ;
} else {
uk = __bch2_bkey_unpack_key ( f , k ) ;
u . k = & uk ;
u . v = bkeyp_val ( f , k ) ;
2020-01-07 13:29:32 -05:00
}
2020-04-24 14:08:18 -04:00
if ( big_endian ! = CPU_BIG_ENDIAN )
bch2_bkey_swab_val ( u ) ;
2020-01-07 13:29:32 -05:00
2020-04-24 14:08:18 -04:00
ops = & bch2_bkey_ops [ k - > type ] ;
2020-01-07 13:29:32 -05:00
2020-04-24 14:08:18 -04:00
if ( ops - > compat )
ops - > compat ( btree_id , version , big_endian , write , u ) ;
break ;
default :
BUG ( ) ;
}
2020-01-07 13:29:32 -05:00
}