2019-08-16 09:59:56 -04:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
2020-12-17 15:08:58 -05:00
# include "bkey_buf.h"
2019-08-16 09:59:56 -04:00
# include "btree_update.h"
2021-05-17 00:08:06 -04:00
# include "buckets.h"
2019-08-16 09:59:56 -04:00
# include "extents.h"
2019-10-10 12:47:22 -04:00
# include "inode.h"
# include "io.h"
2019-08-16 09:59:56 -04:00
# include "reflink.h"
2021-03-16 00:28:17 -04:00
# include "subvolume.h"
2019-08-16 09:59:56 -04:00
# include <linux/sched/signal.h>
2020-10-24 19:51:34 -04:00
static inline unsigned bkey_type_to_indirect ( const struct bkey * k )
{
switch ( k - > type ) {
case KEY_TYPE_extent :
return KEY_TYPE_reflink_v ;
case KEY_TYPE_inline_data :
return KEY_TYPE_indirect_inline_data ;
default :
return 0 ;
}
}
2019-08-16 09:59:56 -04:00
/* reflink pointers */
const char * bch2_reflink_p_invalid ( const struct bch_fs * c , struct bkey_s_c k )
{
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p ( k ) ;
if ( bkey_val_bytes ( p . k ) ! = sizeof ( * p . v ) )
return " incorrect value size " ;
return NULL ;
}
void bch2_reflink_p_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p ( k ) ;
pr_buf ( out , " idx %llu " , le64_to_cpu ( p . v - > idx ) ) ;
}
2021-04-28 23:49:30 -04:00
bool bch2_reflink_p_merge ( struct bch_fs * c , struct bkey_s _l , struct bkey_s_c _r )
2019-08-16 09:59:56 -04:00
{
struct bkey_s_reflink_p l = bkey_s_to_reflink_p ( _l ) ;
2021-04-28 23:49:30 -04:00
struct bkey_s_c_reflink_p r = bkey_s_c_to_reflink_p ( _r ) ;
2019-08-16 09:59:56 -04:00
2021-04-28 23:49:30 -04:00
/*
* Disabled for now , the triggers code needs to be reworked for merging
* of reflink pointers to work :
*/
return false ;
2019-08-16 09:59:56 -04:00
2021-04-28 23:49:30 -04:00
if ( le64_to_cpu ( l . v - > idx ) + l . k - > size ! = le64_to_cpu ( r . v - > idx ) )
return false ;
2019-08-16 09:59:56 -04:00
bch2_key_resize ( l . k , l . k - > size + r . k - > size ) ;
2021-04-28 23:49:30 -04:00
return true ;
2019-08-16 09:59:56 -04:00
}
/* indirect extents */
const char * bch2_reflink_v_invalid ( const struct bch_fs * c , struct bkey_s_c k )
{
struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v ( k ) ;
if ( bkey_val_bytes ( r . k ) < sizeof ( * r . v ) )
return " incorrect value size " ;
return bch2_bkey_ptrs_invalid ( c , k ) ;
}
void bch2_reflink_v_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v ( k ) ;
pr_buf ( out , " refcount: %llu " , le64_to_cpu ( r . v - > refcount ) ) ;
bch2_bkey_ptrs_to_text ( out , c , k ) ;
}
2021-05-15 15:04:08 -04:00
bool bch2_reflink_v_merge ( struct bch_fs * c , struct bkey_s _l , struct bkey_s_c _r )
{
struct bkey_s_reflink_v l = bkey_s_to_reflink_v ( _l ) ;
struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v ( _r ) ;
return l . v - > refcount = = r . v - > refcount & & bch2_extent_merge ( c , _l , _r ) ;
}
2020-10-24 19:51:34 -04:00
/* indirect inline data */
const char * bch2_indirect_inline_data_invalid ( const struct bch_fs * c ,
struct bkey_s_c k )
{
if ( bkey_val_bytes ( k . k ) < sizeof ( struct bch_indirect_inline_data ) )
return " incorrect value size " ;
return NULL ;
}
void bch2_indirect_inline_data_to_text ( struct printbuf * out ,
struct bch_fs * c , struct bkey_s_c k )
{
struct bkey_s_c_indirect_inline_data d = bkey_s_c_to_indirect_inline_data ( k ) ;
unsigned datalen = bkey_inline_data_bytes ( k . k ) ;
pr_buf ( out , " refcount %llu datalen %u: %*phN " ,
le64_to_cpu ( d . v - > refcount ) , datalen ,
min ( datalen , 32U ) , d . v - > data ) ;
}
2019-08-16 09:59:56 -04:00
static int bch2_make_extent_indirect ( struct btree_trans * trans ,
struct btree_iter * extent_iter ,
2020-10-24 19:51:34 -04:00
struct bkey_i * orig )
2019-08-16 09:59:56 -04:00
{
struct bch_fs * c = trans - > c ;
2021-08-30 15:18:31 -04:00
struct btree_iter reflink_iter = { NULL } ;
2019-08-16 09:59:56 -04:00
struct bkey_s_c k ;
2020-10-24 19:51:34 -04:00
struct bkey_i * r_v ;
2019-08-16 09:59:56 -04:00
struct bkey_i_reflink_p * r_p ;
2020-10-24 19:51:34 -04:00
__le64 * refcount ;
2019-08-16 09:59:56 -04:00
int ret ;
2020-10-24 19:51:34 -04:00
if ( orig - > k . type = = KEY_TYPE_inline_data )
bch2_check_set_feature ( c , BCH_FEATURE_reflink_inline_data ) ;
2021-02-20 19:27:37 -05:00
for_each_btree_key ( trans , reflink_iter , BTREE_ID_reflink ,
2019-08-16 09:59:56 -04:00
POS ( 0 , c - > reflink_hint ) ,
BTREE_ITER_INTENT | BTREE_ITER_SLOTS , k , ret ) {
2021-08-30 15:18:31 -04:00
if ( reflink_iter . pos . inode ) {
bch2_btree_iter_set_pos ( & reflink_iter , POS_MIN ) ;
2019-08-16 09:59:56 -04:00
continue ;
}
2020-10-24 19:51:34 -04:00
if ( bkey_deleted ( k . k ) & & orig - > k . size < = k . k - > size )
2019-08-16 09:59:56 -04:00
break ;
}
if ( ret )
goto err ;
/* rewind iter to start of hole, if necessary: */
2021-08-30 15:18:31 -04:00
bch2_btree_iter_set_pos_to_extent_start ( & reflink_iter ) ;
2019-08-16 09:59:56 -04:00
2021-06-10 13:21:39 -04:00
r_v = bch2_trans_kmalloc ( trans , sizeof ( __le64 ) + bkey_bytes ( & orig - > k ) ) ;
2019-08-16 09:59:56 -04:00
ret = PTR_ERR_OR_ZERO ( r_v ) ;
if ( ret )
goto err ;
2020-10-24 19:51:34 -04:00
bkey_init ( & r_v - > k ) ;
r_v - > k . type = bkey_type_to_indirect ( & orig - > k ) ;
2021-08-30 15:18:31 -04:00
r_v - > k . p = reflink_iter . pos ;
2020-10-24 19:51:34 -04:00
bch2_key_resize ( & r_v - > k , orig - > k . size ) ;
r_v - > k . version = orig - > k . version ;
set_bkey_val_bytes ( & r_v - > k , sizeof ( __le64 ) + bkey_val_bytes ( & orig - > k ) ) ;
2019-08-16 09:59:56 -04:00
2021-05-23 02:31:33 -04:00
refcount = bkey_refcount ( r_v ) ;
2020-10-24 19:51:34 -04:00
* refcount = 0 ;
memcpy ( refcount + 1 , & orig - > v , bkey_val_bytes ( & orig - > k ) ) ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
ret = bch2_trans_update ( trans , & reflink_iter , r_v , 0 ) ;
2021-05-18 23:17:03 -04:00
if ( ret )
goto err ;
2019-08-16 09:59:56 -04:00
2020-10-24 19:51:34 -04:00
orig - > k . type = KEY_TYPE_reflink_p ;
r_p = bkey_i_to_reflink_p ( orig ) ;
2019-08-16 09:59:56 -04:00
set_bkey_val_bytes ( & r_p - > k , sizeof ( r_p - > v ) ) ;
r_p - > v . idx = cpu_to_le64 ( bkey_start_offset ( & r_v - > k ) ) ;
2021-05-18 23:17:03 -04:00
ret = bch2_trans_update ( trans , extent_iter , & r_p - > k_i , 0 ) ;
2019-08-16 09:59:56 -04:00
err :
2021-08-30 15:18:31 -04:00
c - > reflink_hint = reflink_iter . pos . offset ;
bch2_trans_iter_exit ( trans , & reflink_iter ) ;
2019-08-16 09:59:56 -04:00
return ret ;
}
static struct bkey_s_c get_next_src ( struct btree_iter * iter , struct bpos end )
{
2021-03-20 22:14:10 -04:00
struct bkey_s_c k ;
2019-10-04 20:40:47 -04:00
int ret ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
for_each_btree_key_continue ( * iter , 0 , k , ret ) {
2019-08-16 09:59:56 -04:00
if ( bkey_cmp ( iter - > pos , end ) > = 0 )
2021-03-20 22:14:10 -04:00
break ;
2019-08-16 09:59:56 -04:00
2020-10-24 19:51:34 -04:00
if ( bkey_extent_is_data ( k . k ) )
2021-03-20 22:14:10 -04:00
return k ;
2019-08-16 09:59:56 -04:00
}
2019-10-04 20:40:47 -04:00
2021-07-24 19:50:40 -04:00
if ( bkey_cmp ( iter - > pos , end ) > = 0 )
bch2_btree_iter_set_pos ( iter , end ) ;
return ret ? bkey_s_c_err ( ret ) : bkey_s_c_null ;
2019-08-16 09:59:56 -04:00
}
s64 bch2_remap_range ( struct bch_fs * c ,
2021-03-16 00:28:17 -04:00
subvol_inum dst_inum , u64 dst_offset ,
subvol_inum src_inum , u64 src_offset ,
2019-10-10 12:47:22 -04:00
u64 remap_sectors , u64 * journal_seq ,
u64 new_i_size , s64 * i_sectors_delta )
2019-08-16 09:59:56 -04:00
{
struct btree_trans trans ;
2021-08-30 15:18:31 -04:00
struct btree_iter dst_iter , src_iter ;
2019-08-16 09:59:56 -04:00
struct bkey_s_c src_k ;
2020-12-17 15:08:58 -05:00
struct bkey_buf new_dst , new_src ;
2021-03-16 00:28:17 -04:00
struct bpos dst_start = POS ( dst_inum . inum , dst_offset ) ;
struct bpos src_start = POS ( src_inum . inum , src_offset ) ;
2019-08-16 09:59:56 -04:00
struct bpos dst_end = dst_start , src_end = src_start ;
2021-03-20 22:14:10 -04:00
struct bpos src_want ;
u64 dst_done ;
2021-03-12 20:30:39 -05:00
u32 dst_snapshot , src_snapshot ;
2019-10-10 12:47:22 -04:00
int ret = 0 , ret2 = 0 ;
2019-08-16 09:59:56 -04:00
2019-10-19 19:03:23 -04:00
if ( ! percpu_ref_tryget ( & c - > writes ) )
return - EROFS ;
2019-12-28 20:17:06 -05:00
bch2_check_set_feature ( c , BCH_FEATURE_reflink ) ;
2019-08-16 09:59:56 -04:00
dst_end . offset + = remap_sectors ;
src_end . offset + = remap_sectors ;
2020-12-17 15:08:58 -05:00
bch2_bkey_buf_init ( & new_dst ) ;
bch2_bkey_buf_init ( & new_src ) ;
2019-08-16 09:59:56 -04:00
bch2_trans_init ( & trans , c , BTREE_ITER_MAX , 4096 ) ;
2021-08-30 15:18:31 -04:00
bch2_trans_iter_init ( & trans , & src_iter , BTREE_ID_extents , src_start ,
BTREE_ITER_INTENT ) ;
bch2_trans_iter_init ( & trans , & dst_iter , BTREE_ID_extents , dst_start ,
BTREE_ITER_INTENT ) ;
2019-08-16 09:59:56 -04:00
2021-03-20 22:14:10 -04:00
while ( ( ret = = 0 | | ret = = - EINTR ) & &
2021-08-30 15:18:31 -04:00
bkey_cmp ( dst_iter . pos , dst_end ) < 0 ) {
2021-05-17 00:08:06 -04:00
struct disk_reservation disk_res = { 0 } ;
2020-02-26 15:39:46 -05:00
bch2_trans_begin ( & trans ) ;
2019-12-20 16:35:24 -05:00
2019-08-16 09:59:56 -04:00
if ( fatal_signal_pending ( current ) ) {
ret = - EINTR ;
2021-03-19 20:29:11 -04:00
break ;
2019-08-16 09:59:56 -04:00
}
2021-03-16 00:28:17 -04:00
ret = bch2_subvolume_get_snapshot ( & trans , src_inum . subvol ,
2021-03-12 20:30:39 -05:00
& src_snapshot ) ;
2021-03-16 00:28:17 -04:00
if ( ret )
continue ;
2021-03-12 20:30:39 -05:00
bch2_btree_iter_set_snapshot ( & src_iter , src_snapshot ) ;
2021-03-16 00:28:17 -04:00
ret = bch2_subvolume_get_snapshot ( & trans , dst_inum . subvol ,
2021-03-12 20:30:39 -05:00
& dst_snapshot ) ;
2021-03-16 00:28:17 -04:00
if ( ret )
continue ;
2021-03-12 20:30:39 -05:00
bch2_btree_iter_set_snapshot ( & dst_iter , dst_snapshot ) ;
2021-08-30 15:18:31 -04:00
dst_done = dst_iter . pos . offset - dst_start . offset ;
2021-03-20 22:14:10 -04:00
src_want = POS ( src_start . inode , src_start . offset + dst_done ) ;
2021-08-30 15:18:31 -04:00
bch2_btree_iter_set_pos ( & src_iter , src_want ) ;
2021-03-20 22:14:10 -04:00
2021-08-30 15:18:31 -04:00
src_k = get_next_src ( & src_iter , src_end ) ;
2019-08-16 09:59:56 -04:00
ret = bkey_err ( src_k ) ;
if ( ret )
2021-03-19 20:29:11 -04:00
continue ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
if ( bkey_cmp ( src_want , src_iter . pos ) < 0 ) {
2021-03-12 20:30:39 -05:00
ret = bch2_fpunch_at ( & trans , & dst_iter , dst_inum ,
min ( dst_end . offset ,
dst_iter . pos . offset +
src_iter . pos . offset - src_want . offset ) ,
journal_seq , i_sectors_delta ) ;
2019-08-16 09:59:56 -04:00
continue ;
}
2020-10-24 19:51:34 -04:00
if ( src_k . k - > type ! = KEY_TYPE_reflink_p ) {
2021-08-30 15:18:31 -04:00
bch2_btree_iter_set_pos_to_extent_start ( & src_iter ) ;
2021-06-14 18:16:10 -04:00
2020-12-17 15:08:58 -05:00
bch2_bkey_buf_reassemble ( & new_src , c , src_k ) ;
2019-11-09 16:01:15 -05:00
src_k = bkey_i_to_s_c ( new_src . k ) ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
ret = bch2_make_extent_indirect ( & trans , & src_iter ,
2020-10-24 19:51:34 -04:00
new_src . k ) ;
2019-08-16 09:59:56 -04:00
if ( ret )
2021-03-19 20:29:11 -04:00
continue ;
2019-08-16 09:59:56 -04:00
BUG_ON ( src_k . k - > type ! = KEY_TYPE_reflink_p ) ;
}
if ( src_k . k - > type = = KEY_TYPE_reflink_p ) {
struct bkey_s_c_reflink_p src_p =
bkey_s_c_to_reflink_p ( src_k ) ;
struct bkey_i_reflink_p * dst_p =
2020-12-17 15:08:58 -05:00
bkey_reflink_p_init ( new_dst . k ) ;
2019-08-16 09:59:56 -04:00
u64 offset = le64_to_cpu ( src_p . v - > idx ) +
2021-03-20 22:14:10 -04:00
( src_want . offset -
2019-08-16 09:59:56 -04:00
bkey_start_offset ( src_k . k ) ) ;
dst_p - > v . idx = cpu_to_le64 ( offset ) ;
} else {
BUG ( ) ;
}
2021-08-30 15:18:31 -04:00
new_dst . k - > k . p = dst_iter . pos ;
2020-12-17 15:08:58 -05:00
bch2_key_resize ( & new_dst . k - > k ,
2021-03-20 22:14:10 -04:00
min ( src_k . k - > p . offset - src_want . offset ,
2021-08-30 15:18:31 -04:00
dst_end . offset - dst_iter . pos . offset ) ) ;
2021-03-12 20:30:39 -05:00
ret = bch2_extent_update ( & trans , dst_inum , & dst_iter ,
new_dst . k , & disk_res , journal_seq ,
2021-05-20 15:49:23 -04:00
new_i_size , i_sectors_delta ,
true ) ;
2021-05-17 00:08:06 -04:00
bch2_disk_reservation_put ( c , & disk_res ) ;
2019-08-16 09:59:56 -04:00
}
2021-08-30 15:18:31 -04:00
bch2_trans_iter_exit ( & trans , & dst_iter ) ;
bch2_trans_iter_exit ( & trans , & src_iter ) ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
BUG_ON ( ! ret & & bkey_cmp ( dst_iter . pos , dst_end ) ) ;
BUG_ON ( bkey_cmp ( dst_iter . pos , dst_end ) > 0 ) ;
2019-08-16 09:59:56 -04:00
2021-08-30 15:18:31 -04:00
dst_done = dst_iter . pos . offset - dst_start . offset ;
new_i_size = min ( dst_iter . pos . offset < < 9 , new_i_size ) ;
2019-08-16 09:59:56 -04:00
2019-10-10 12:47:22 -04:00
do {
struct bch_inode_unpacked inode_u ;
2021-08-30 15:18:31 -04:00
struct btree_iter inode_iter = { NULL } ;
2019-08-16 09:59:56 -04:00
2021-07-24 20:24:10 -04:00
bch2_trans_begin ( & trans ) ;
2021-08-30 15:18:31 -04:00
ret2 = bch2_inode_peek ( & trans , & inode_iter , & inode_u ,
2021-03-16 00:28:17 -04:00
dst_inum , BTREE_ITER_INTENT ) ;
2019-08-16 09:59:56 -04:00
2019-10-10 12:47:22 -04:00
if ( ! ret2 & &
2019-11-04 22:22:13 -05:00
inode_u . bi_size < new_i_size ) {
inode_u . bi_size = new_i_size ;
2021-08-30 15:18:31 -04:00
ret2 = bch2_inode_write ( & trans , & inode_iter , & inode_u ) ? :
2019-12-22 23:39:28 -05:00
bch2_trans_commit ( & trans , NULL , journal_seq , 0 ) ;
2019-11-04 22:22:13 -05:00
}
2021-03-19 20:29:11 -04:00
2021-08-30 15:18:31 -04:00
bch2_trans_iter_exit ( & trans , & inode_iter ) ;
2019-10-10 12:47:22 -04:00
} while ( ret2 = = - EINTR ) ;
ret = bch2_trans_exit ( & trans ) ? : ret ;
2020-12-17 15:08:58 -05:00
bch2_bkey_buf_exit ( & new_src , c ) ;
bch2_bkey_buf_exit ( & new_dst , c ) ;
2019-10-10 12:47:22 -04:00
2019-10-19 19:03:23 -04:00
percpu_ref_put ( & c - > writes ) ;
2019-10-10 12:47:22 -04:00
return dst_done ? : ret ? : ret2 ;
}