2018-11-28 02:30:56 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
2019-11-10 00:01:15 +03:00
# include "bkey_on_stack.h"
2018-11-28 02:30:56 +03:00
# include "bkey_sort.h"
# include "bset.h"
# include "extents.h"
2019-12-15 00:20:33 +03:00
typedef int ( * sort_cmp_fn ) ( struct btree * ,
struct bkey_packed * ,
struct bkey_packed * ) ;
2018-11-28 02:30:56 +03:00
2019-12-15 00:20:33 +03:00
static inline bool sort_iter_end ( struct sort_iter * iter )
2018-11-28 02:30:56 +03:00
{
return ! iter - > used ;
}
static inline void __sort_iter_sift ( struct sort_iter * iter ,
unsigned from ,
sort_cmp_fn cmp )
{
unsigned i ;
for ( i = from ;
i + 1 < iter - > used & &
cmp ( iter - > b , iter - > data [ i ] . k , iter - > data [ i + 1 ] . k ) > 0 ;
i + + )
swap ( iter - > data [ i ] , iter - > data [ i + 1 ] ) ;
}
static inline void sort_iter_sift ( struct sort_iter * iter , sort_cmp_fn cmp )
{
__sort_iter_sift ( iter , 0 , cmp ) ;
}
static inline void sort_iter_sort ( struct sort_iter * iter , sort_cmp_fn cmp )
{
unsigned i = iter - > used ;
while ( i - - )
__sort_iter_sift ( iter , i , cmp ) ;
}
static inline struct bkey_packed * sort_iter_peek ( struct sort_iter * iter )
{
2019-12-15 00:20:33 +03:00
return ! sort_iter_end ( iter ) ? iter - > data - > k : NULL ;
2018-11-28 02:30:56 +03:00
}
2019-12-15 00:20:33 +03:00
static inline void __sort_iter_advance ( struct sort_iter * iter ,
unsigned idx , sort_cmp_fn cmp )
2018-11-28 02:30:56 +03:00
{
2019-12-15 00:20:33 +03:00
struct sort_iter_set * i = iter - > data + idx ;
2018-11-28 02:30:56 +03:00
2019-12-15 00:20:33 +03:00
BUG_ON ( idx > = iter - > used ) ;
2018-11-28 02:30:56 +03:00
2019-12-15 00:20:33 +03:00
i - > k = bkey_next_skip_noops ( i - > k , i - > end ) ;
BUG_ON ( i - > k > i - > end ) ;
if ( i - > k = = i - > end )
array_remove_item ( iter - > data , iter - > used , idx ) ;
2018-11-28 02:30:56 +03:00
else
2019-12-15 00:20:33 +03:00
__sort_iter_sift ( iter , idx , cmp ) ;
}
static inline void sort_iter_advance ( struct sort_iter * iter , sort_cmp_fn cmp )
{
__sort_iter_advance ( iter , 0 , cmp ) ;
2018-11-28 02:30:56 +03:00
}
static inline struct bkey_packed * sort_iter_next ( struct sort_iter * iter ,
sort_cmp_fn cmp )
{
struct bkey_packed * ret = sort_iter_peek ( iter ) ;
if ( ret )
sort_iter_advance ( iter , cmp ) ;
return ret ;
}
/*
2019-12-15 00:20:33 +03:00
* If keys compare equal , compare by pointer order :
2018-11-28 02:30:56 +03:00
*/
2019-12-15 00:20:33 +03:00
static inline int key_sort_fix_overlapping_cmp ( struct btree * b ,
struct bkey_packed * l ,
struct bkey_packed * r )
2018-11-28 02:30:56 +03:00
{
2020-11-07 20:31:20 +03:00
return bch2_bkey_cmp_packed ( b , l , r ) ? :
2019-12-15 00:20:33 +03:00
cmp_int ( ( unsigned long ) l , ( unsigned long ) r ) ;
}
2018-11-28 02:30:56 +03:00
2019-12-15 00:20:33 +03:00
static inline bool should_drop_next_key ( struct sort_iter * iter )
{
2018-11-28 02:30:56 +03:00
/*
* key_sort_cmp ( ) ensures that when keys compare equal the older key
2019-12-15 00:20:33 +03:00
* comes first ; so if l - > k compares equal to r - > k then l - > k is older
* and should be dropped .
2018-11-28 02:30:56 +03:00
*/
2019-12-15 00:20:33 +03:00
return iter - > used > = 2 & &
2020-11-07 20:31:20 +03:00
! bch2_bkey_cmp_packed ( iter - > b ,
2019-12-15 00:20:33 +03:00
iter - > data [ 0 ] . k ,
iter - > data [ 1 ] . k ) ;
2018-11-28 02:30:56 +03:00
}
2019-12-15 00:20:33 +03:00
struct btree_nr_keys
bch2_key_sort_fix_overlapping ( struct bch_fs * c , struct bset * dst ,
struct sort_iter * iter )
2018-11-28 02:30:56 +03:00
{
struct bkey_packed * out = dst - > start ;
2019-12-15 00:20:33 +03:00
struct bkey_packed * k ;
2018-11-28 02:30:56 +03:00
struct btree_nr_keys nr ;
memset ( & nr , 0 , sizeof ( nr ) ) ;
2019-12-15 00:20:33 +03:00
sort_iter_sort ( iter , key_sort_fix_overlapping_cmp ) ;
2018-11-28 02:30:56 +03:00
2019-12-15 00:20:33 +03:00
while ( ( k = sort_iter_peek ( iter ) ) ) {
if ( ! bkey_whiteout ( k ) & &
! should_drop_next_key ( iter ) ) {
2018-11-28 02:30:56 +03:00
bkey_copy ( out , k ) ;
btree_keys_account_key_add ( & nr , 0 , out ) ;
out = bkey_next ( out ) ;
}
2019-12-15 00:20:33 +03:00
sort_iter_advance ( iter , key_sort_fix_overlapping_cmp ) ;
2018-11-28 02:30:56 +03:00
}
dst - > u64s = cpu_to_le16 ( ( u64 * ) out - dst - > _data ) ;
return nr ;
}
static void extent_sort_append ( struct bch_fs * c ,
2019-06-09 23:56:29 +03:00
struct bkey_format * f ,
2018-11-28 02:30:56 +03:00
struct btree_nr_keys * nr ,
2020-03-25 00:00:48 +03:00
struct bkey_packed * * out ,
2019-06-09 23:56:29 +03:00
struct bkey_s k )
2018-11-28 02:30:56 +03:00
{
2020-03-25 00:00:48 +03:00
if ( ! bkey_whiteout ( k . k ) ) {
if ( ! bch2_bkey_pack_key ( * out , k . k , f ) )
memcpy_u64s_small ( * out , k . k , BKEY_U64s ) ;
2018-11-28 02:30:56 +03:00
2020-03-25 00:00:48 +03:00
memcpy_u64s_small ( bkeyp_val ( f , * out ) , k . v , bkey_val_u64s ( k . k ) ) ;
2018-11-28 02:30:56 +03:00
2020-03-25 00:00:48 +03:00
btree_keys_account_key_add ( nr , 0 , * out ) ;
* out = bkey_next ( * out ) ;
}
2018-11-28 02:30:56 +03:00
}
/* Sort + repack in a new format: */
2018-11-01 22:10:01 +03:00
struct btree_nr_keys
2018-11-28 02:30:56 +03:00
bch2_sort_repack ( struct bset * dst , struct btree * src ,
struct btree_node_iter * src_iter ,
struct bkey_format * out_f ,
bool filter_whiteouts )
{
struct bkey_format * in_f = & src - > format ;
struct bkey_packed * in , * out = vstruct_last ( dst ) ;
struct btree_nr_keys nr ;
memset ( & nr , 0 , sizeof ( nr ) ) ;
while ( ( in = bch2_btree_node_iter_next_all ( src_iter , src ) ) ) {
if ( filter_whiteouts & & bkey_whiteout ( in ) )
continue ;
if ( bch2_bkey_transform ( out_f , out , bkey_packed ( in )
? in_f : & bch2_bkey_format_current , in ) )
out - > format = KEY_FORMAT_LOCAL_BTREE ;
else
bch2_bkey_unpack ( src , ( void * ) out , in ) ;
btree_keys_account_key_add ( & nr , 0 , out ) ;
out = bkey_next ( out ) ;
}
dst - > u64s = cpu_to_le16 ( ( u64 * ) out - dst - > _data ) ;
return nr ;
}
2020-03-25 00:00:48 +03:00
/* Sort, repack, and call bch2_bkey_normalize() to drop stale pointers: */
2018-11-28 02:30:56 +03:00
struct btree_nr_keys
bch2_sort_repack_merge ( struct bch_fs * c ,
struct bset * dst , struct btree * src ,
struct btree_node_iter * iter ,
struct bkey_format * out_f ,
2018-11-01 22:10:01 +03:00
bool filter_whiteouts )
2018-11-28 02:30:56 +03:00
{
2020-03-25 00:00:48 +03:00
struct bkey_packed * out = vstruct_last ( dst ) , * k_packed ;
2020-01-17 00:14:56 +03:00
struct bkey_on_stack k ;
2018-11-28 02:30:56 +03:00
struct btree_nr_keys nr ;
memset ( & nr , 0 , sizeof ( nr ) ) ;
2020-01-17 00:14:56 +03:00
bkey_on_stack_init ( & k ) ;
2018-11-28 02:30:56 +03:00
2019-08-22 01:35:15 +03:00
while ( ( k_packed = bch2_btree_node_iter_next_all ( iter , src ) ) ) {
2019-06-09 23:56:29 +03:00
if ( filter_whiteouts & & bkey_whiteout ( k_packed ) )
2018-11-28 02:30:56 +03:00
continue ;
2020-01-17 00:14:56 +03:00
/*
* NOTE :
* bch2_bkey_normalize may modify the key we pass it ( dropping
* stale pointers ) and we don ' t have a write lock on the src
* node ; we have to make a copy of the entire key before calling
* normalize
*/
bkey_on_stack_realloc ( & k , c , k_packed - > u64s + BKEY_U64s ) ;
bch2_bkey_unpack ( src , k . k , k_packed ) ;
2018-11-28 02:30:56 +03:00
2019-06-09 23:56:29 +03:00
if ( filter_whiteouts & &
2020-01-17 00:14:56 +03:00
bch2_bkey_normalize ( c , bkey_i_to_s ( k . k ) ) )
2018-11-28 02:30:56 +03:00
continue ;
2020-03-25 00:00:48 +03:00
extent_sort_append ( c , out_f , & nr , & out , bkey_i_to_s ( k . k ) ) ;
2018-11-28 02:30:56 +03:00
}
2020-03-25 00:00:48 +03:00
dst - > u64s = cpu_to_le16 ( ( u64 * ) out - dst - > _data ) ;
2020-01-17 00:14:56 +03:00
bkey_on_stack_exit ( & k , c ) ;
2018-11-28 02:30:56 +03:00
return nr ;
}
static inline int sort_keys_cmp ( struct btree * b ,
struct bkey_packed * l ,
struct bkey_packed * r )
{
2020-11-07 20:31:20 +03:00
return bch2_bkey_cmp_packed ( b , l , r ) ? :
2019-11-27 01:26:04 +03:00
( int ) bkey_deleted ( r ) - ( int ) bkey_deleted ( l ) ? :
2018-11-28 02:30:56 +03:00
( int ) l - > needs_whiteout - ( int ) r - > needs_whiteout ;
}
unsigned bch2_sort_keys ( struct bkey_packed * dst ,
struct sort_iter * iter ,
bool filter_whiteouts )
{
const struct bkey_format * f = & iter - > b - > format ;
struct bkey_packed * in , * next , * out = dst ;
sort_iter_sort ( iter , sort_keys_cmp ) ;
while ( ( in = sort_iter_next ( iter , sort_keys_cmp ) ) ) {
2020-01-16 06:53:49 +03:00
bool needs_whiteout = false ;
2018-11-28 02:30:56 +03:00
if ( bkey_whiteout ( in ) & &
( filter_whiteouts | | ! in - > needs_whiteout ) )
continue ;
2020-01-16 06:53:49 +03:00
while ( ( next = sort_iter_peek ( iter ) ) & &
2020-11-07 20:31:20 +03:00
! bch2_bkey_cmp_packed ( iter - > b , in , next ) ) {
2018-11-28 02:30:56 +03:00
BUG_ON ( in - > needs_whiteout & &
next - > needs_whiteout ) ;
2020-01-16 06:53:49 +03:00
needs_whiteout | = in - > needs_whiteout ;
in = sort_iter_next ( iter , sort_keys_cmp ) ;
2018-11-28 02:30:56 +03:00
}
if ( bkey_whiteout ( in ) ) {
memcpy_u64s ( out , in , bkeyp_key_u64s ( f , in ) ) ;
set_bkeyp_val_u64s ( f , out , 0 ) ;
} else {
bkey_copy ( out , in ) ;
}
2020-01-16 06:53:49 +03:00
out - > needs_whiteout | = needs_whiteout ;
2018-11-28 02:30:56 +03:00
out = bkey_next ( out ) ;
}
return ( u64 * ) out - ( u64 * ) dst ;
}
2019-11-27 01:26:04 +03:00
/* Compat code for btree_node_old_extent_overwrite: */
/*
* If keys compare equal , compare by pointer order :
*
* Necessary for sort_fix_overlapping ( ) - if there are multiple keys that
* compare equal in different sets , we have to process them newest to oldest .
*/
static inline int extent_sort_fix_overlapping_cmp ( struct btree * b ,
struct bkey_packed * l ,
struct bkey_packed * r )
{
struct bkey ul = bkey_unpack_key ( b , l ) ;
struct bkey ur = bkey_unpack_key ( b , r ) ;
return bkey_cmp ( bkey_start_pos ( & ul ) ,
bkey_start_pos ( & ur ) ) ? :
cmp_int ( ( unsigned long ) r , ( unsigned long ) l ) ;
}
2020-03-03 01:08:19 +03:00
/*
* The algorithm in extent_sort_fix_overlapping ( ) relies on keys in the same
* bset being ordered by start offset - but 0 size whiteouts ( which are always
* KEY_TYPE_deleted ) break this ordering , so we need to skip over them :
*/
static void extent_iter_advance ( struct sort_iter * iter , unsigned idx )
{
struct sort_iter_set * i = iter - > data + idx ;
do {
i - > k = bkey_next_skip_noops ( i - > k , i - > end ) ;
} while ( i - > k ! = i - > end & & bkey_deleted ( i - > k ) ) ;
if ( i - > k = = i - > end )
array_remove_item ( iter - > data , iter - > used , idx ) ;
else
__sort_iter_sift ( iter , idx , extent_sort_fix_overlapping_cmp ) ;
}
2019-11-27 01:26:04 +03:00
struct btree_nr_keys
bch2_extent_sort_fix_overlapping ( struct bch_fs * c , struct bset * dst ,
struct sort_iter * iter )
{
struct btree * b = iter - > b ;
struct bkey_format * f = & b - > format ;
struct sort_iter_set * _l = iter - > data , * _r = iter - > data + 1 ;
2020-03-25 00:00:48 +03:00
struct bkey_packed * out = dst - > start ;
2019-11-27 01:26:04 +03:00
struct bkey l_unpacked , r_unpacked ;
struct bkey_s l , r ;
struct btree_nr_keys nr ;
struct bkey_on_stack split ;
2020-03-03 01:08:19 +03:00
unsigned i ;
2019-11-27 01:26:04 +03:00
memset ( & nr , 0 , sizeof ( nr ) ) ;
bkey_on_stack_init ( & split ) ;
sort_iter_sort ( iter , extent_sort_fix_overlapping_cmp ) ;
2020-03-03 01:08:19 +03:00
for ( i = 0 ; i < iter - > used ; ) {
if ( bkey_deleted ( iter - > data [ i ] . k ) )
__sort_iter_advance ( iter , i ,
extent_sort_fix_overlapping_cmp ) ;
else
i + + ;
}
2019-11-27 01:26:04 +03:00
while ( ! sort_iter_end ( iter ) ) {
l = __bkey_disassemble ( b , _l - > k , & l_unpacked ) ;
if ( iter - > used = = 1 ) {
2020-03-25 00:00:48 +03:00
extent_sort_append ( c , f , & nr , & out , l ) ;
2020-03-03 01:08:19 +03:00
extent_iter_advance ( iter , 0 ) ;
2019-11-27 01:26:04 +03:00
continue ;
}
r = __bkey_disassemble ( b , _r - > k , & r_unpacked ) ;
/* If current key and next key don't overlap, just append */
if ( bkey_cmp ( l . k - > p , bkey_start_pos ( r . k ) ) < = 0 ) {
2020-03-25 00:00:48 +03:00
extent_sort_append ( c , f , & nr , & out , l ) ;
2020-03-03 01:08:19 +03:00
extent_iter_advance ( iter , 0 ) ;
2019-11-27 01:26:04 +03:00
continue ;
}
/* Skip 0 size keys */
if ( ! r . k - > size ) {
2020-03-03 01:08:19 +03:00
extent_iter_advance ( iter , 1 ) ;
2019-11-27 01:26:04 +03:00
continue ;
}
/*
* overlap : keep the newer key and trim the older key so they
* don ' t overlap . comparing pointers tells us which one is
* newer , since the bsets are appended one after the other .
*/
/* can't happen because of comparison func */
BUG_ON ( _l - > k < _r - > k & &
! bkey_cmp ( bkey_start_pos ( l . k ) , bkey_start_pos ( r . k ) ) ) ;
if ( _l - > k > _r - > k ) {
/* l wins, trim r */
if ( bkey_cmp ( l . k - > p , r . k - > p ) > = 0 ) {
2020-03-03 01:08:19 +03:00
extent_iter_advance ( iter , 1 ) ;
2019-11-27 01:26:04 +03:00
} else {
bch2_cut_front_s ( l . k - > p , r ) ;
extent_save ( b , _r - > k , r . k ) ;
__sort_iter_sift ( iter , 1 ,
extent_sort_fix_overlapping_cmp ) ;
}
} else if ( bkey_cmp ( l . k - > p , r . k - > p ) > 0 ) {
/*
* r wins , but it overlaps in the middle of l - split l :
*/
bkey_on_stack_reassemble ( & split , c , l . s_c ) ;
bch2_cut_back ( bkey_start_pos ( r . k ) , split . k ) ;
bch2_cut_front_s ( r . k - > p , l ) ;
extent_save ( b , _l - > k , l . k ) ;
__sort_iter_sift ( iter , 0 ,
extent_sort_fix_overlapping_cmp ) ;
2020-03-25 00:00:48 +03:00
extent_sort_append ( c , f , & nr , & out ,
bkey_i_to_s ( split . k ) ) ;
2019-11-27 01:26:04 +03:00
} else {
bch2_cut_back_s ( bkey_start_pos ( r . k ) , l ) ;
extent_save ( b , _l - > k , l . k ) ;
}
}
2020-03-25 00:00:48 +03:00
dst - > u64s = cpu_to_le16 ( ( u64 * ) out - dst - > _data ) ;
2019-11-27 01:26:04 +03:00
bkey_on_stack_exit ( & split , c ) ;
return nr ;
}
2018-11-28 02:30:56 +03:00
static inline int sort_extents_cmp ( struct btree * b ,
struct bkey_packed * l ,
struct bkey_packed * r )
{
2020-11-07 20:31:20 +03:00
return bch2_bkey_cmp_packed ( b , l , r ) ? :
2018-11-28 02:30:56 +03:00
( int ) bkey_deleted ( l ) - ( int ) bkey_deleted ( r ) ;
}
unsigned bch2_sort_extents ( struct bkey_packed * dst ,
struct sort_iter * iter ,
bool filter_whiteouts )
{
struct bkey_packed * in , * out = dst ;
sort_iter_sort ( iter , sort_extents_cmp ) ;
while ( ( in = sort_iter_next ( iter , sort_extents_cmp ) ) ) {
if ( bkey_deleted ( in ) )
continue ;
if ( bkey_whiteout ( in ) & &
( filter_whiteouts | | ! in - > needs_whiteout ) )
continue ;
bkey_copy ( out , in ) ;
out = bkey_next ( out ) ;
}
return ( u64 * ) out - ( u64 * ) dst ;
}
static inline int sort_extent_whiteouts_cmp ( struct btree * b ,
struct bkey_packed * l ,
struct bkey_packed * r )
{
struct bkey ul = bkey_unpack_key ( b , l ) ;
struct bkey ur = bkey_unpack_key ( b , r ) ;
return bkey_cmp ( bkey_start_pos ( & ul ) , bkey_start_pos ( & ur ) ) ;
}
unsigned bch2_sort_extent_whiteouts ( struct bkey_packed * dst ,
struct sort_iter * iter )
{
const struct bkey_format * f = & iter - > b - > format ;
struct bkey_packed * in , * out = dst ;
struct bkey_i l , r ;
bool prev = false , l_packed = false ;
u64 max_packed_size = bkey_field_max ( f , BKEY_FIELD_SIZE ) ;
u64 max_packed_offset = bkey_field_max ( f , BKEY_FIELD_OFFSET ) ;
u64 new_size ;
max_packed_size = min_t ( u64 , max_packed_size , KEY_SIZE_MAX ) ;
sort_iter_sort ( iter , sort_extent_whiteouts_cmp ) ;
while ( ( in = sort_iter_next ( iter , sort_extent_whiteouts_cmp ) ) ) {
if ( bkey_deleted ( in ) )
continue ;
EBUG_ON ( bkeyp_val_u64s ( f , in ) ) ;
2018-11-01 22:10:01 +03:00
EBUG_ON ( in - > type ! = KEY_TYPE_discard ) ;
2018-11-28 02:30:56 +03:00
r . k = bkey_unpack_key ( iter - > b , in ) ;
if ( prev & &
bkey_cmp ( l . k . p , bkey_start_pos ( & r . k ) ) > = 0 ) {
if ( bkey_cmp ( l . k . p , r . k . p ) > = 0 )
continue ;
new_size = l_packed
? min ( max_packed_size , max_packed_offset -
bkey_start_offset ( & l . k ) )
: KEY_SIZE_MAX ;
new_size = min ( new_size , r . k . p . offset -
bkey_start_offset ( & l . k ) ) ;
BUG_ON ( new_size < l . k . size ) ;
bch2_key_resize ( & l . k , new_size ) ;
if ( bkey_cmp ( l . k . p , r . k . p ) > = 0 )
continue ;
bch2_cut_front ( l . k . p , & r ) ;
}
if ( prev ) {
if ( ! bch2_bkey_pack ( out , & l , f ) ) {
BUG_ON ( l_packed ) ;
bkey_copy ( out , & l ) ;
}
out = bkey_next ( out ) ;
}
l = r ;
prev = true ;
l_packed = bkey_packed ( in ) ;
}
if ( prev ) {
if ( ! bch2_bkey_pack ( out , & l , f ) ) {
BUG_ON ( l_packed ) ;
bkey_copy ( out , & l ) ;
}
out = bkey_next ( out ) ;
}
return ( u64 * ) out - ( u64 * ) dst ;
}