2017-03-17 09:18:50 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Code for moving data off a device .
*/
# include "bcachefs.h"
2020-12-17 23:08:58 +03:00
# include "bkey_buf.h"
2017-03-17 09:18:50 +03:00
# include "btree_update.h"
2019-01-21 23:32:13 +03:00
# include "btree_update_interior.h"
2017-03-17 09:18:50 +03:00
# include "buckets.h"
# include "extents.h"
# include "io.h"
# include "journal.h"
# include "keylist.h"
# include "migrate.h"
# include "move.h"
# include "replicas.h"
# include "super-io.h"
2018-11-01 22:10:01 +03:00
static int drop_dev_ptrs ( struct bch_fs * c , struct bkey_s k ,
2017-03-17 09:18:50 +03:00
unsigned dev_idx , int flags , bool metadata )
{
unsigned replicas = metadata ? c - > opts . metadata_replicas : c - > opts . data_replicas ;
unsigned lost = metadata ? BCH_FORCE_IF_METADATA_LOST : BCH_FORCE_IF_DATA_LOST ;
unsigned degraded = metadata ? BCH_FORCE_IF_METADATA_DEGRADED : BCH_FORCE_IF_DATA_DEGRADED ;
unsigned nr_good ;
2018-11-01 22:10:01 +03:00
bch2_bkey_drop_device ( k , dev_idx ) ;
2017-03-17 09:18:50 +03:00
2018-11-01 22:10:01 +03:00
nr_good = bch2_bkey_durability ( c , k . s_c ) ;
2017-03-17 09:18:50 +03:00
if ( ( ! nr_good & & ! ( flags & lost ) ) | |
( nr_good < replicas & & ! ( flags & degraded ) ) )
return - EINVAL ;
return 0 ;
}
2019-08-16 16:59:56 +03:00
static int __bch2_dev_usrdata_drop ( struct bch_fs * c , unsigned dev_idx , int flags ,
enum btree_id btree_id )
2017-03-17 09:18:50 +03:00
{
2019-03-14 03:49:16 +03:00
struct btree_trans trans ;
struct btree_iter * iter ;
2017-03-17 09:18:50 +03:00
struct bkey_s_c k ;
2020-12-17 23:08:58 +03:00
struct bkey_buf sk ;
2017-03-17 09:18:50 +03:00
int ret = 0 ;
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_init ( & sk ) ;
2019-05-15 17:54:43 +03:00
bch2_trans_init ( & trans , c , BTREE_ITER_MAX , 0 ) ;
2019-03-14 03:49:16 +03:00
2019-08-16 16:59:56 +03:00
iter = bch2_trans_get_iter ( & trans , btree_id , POS_MIN ,
BTREE_ITER_PREFETCH ) ;
2019-03-14 03:49:16 +03:00
while ( ( k = bch2_btree_iter_peek ( iter ) ) . k & &
2019-03-28 05:03:30 +03:00
! ( ret = bkey_err ( k ) ) ) {
2019-07-25 20:52:14 +03:00
if ( ! bch2_bkey_has_device ( k , dev_idx ) ) {
2019-03-14 03:49:16 +03:00
bch2_btree_iter_next ( iter ) ;
2017-03-17 09:18:50 +03:00
continue ;
}
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_reassemble ( & sk , c , k ) ;
2017-03-17 09:18:50 +03:00
2019-11-10 00:01:15 +03:00
ret = drop_dev_ptrs ( c , bkey_i_to_s ( sk . k ) ,
2018-11-01 22:10:01 +03:00
dev_idx , flags , false ) ;
2017-03-17 09:18:50 +03:00
if ( ret )
break ;
/*
* If the new extent no longer has any pointers , bch2_extent_normalize ( )
* will do the appropriate thing with it ( turning it into a
2018-11-01 22:10:01 +03:00
* KEY_TYPE_error key , or just a discard if it was a cached extent )
2017-03-17 09:18:50 +03:00
*/
2019-11-10 00:01:15 +03:00
bch2_extent_normalize ( c , bkey_i_to_s ( sk . k ) ) ;
2017-03-17 09:18:50 +03:00
2019-11-10 00:01:15 +03:00
bch2_btree_iter_set_pos ( iter , bkey_start_pos ( & sk . k - > k ) ) ;
2019-03-14 03:49:16 +03:00
2020-01-01 00:17:42 +03:00
bch2_trans_update ( & trans , iter , sk . k , 0 ) ;
2017-03-17 09:18:50 +03:00
2019-03-14 03:49:16 +03:00
ret = bch2_trans_commit ( & trans , NULL , NULL ,
BTREE_INSERT_NOFAIL ) ;
2017-03-17 09:18:50 +03:00
/*
* don ' t want to leave ret = = - EINTR , since if we raced and
* something else overwrote the key we could spuriously return
* - EINTR below :
*/
if ( ret = = - EINTR )
ret = 0 ;
if ( ret )
break ;
}
2019-05-01 00:15:39 +03:00
ret = bch2_trans_exit ( & trans ) ? : ret ;
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_exit ( & sk , c ) ;
2019-03-17 23:49:59 +03:00
2019-05-01 00:15:39 +03:00
BUG_ON ( ret = = - EINTR ) ;
2017-03-17 09:18:50 +03:00
return ret ;
}
2019-08-16 16:59:56 +03:00
static int bch2_dev_usrdata_drop ( struct bch_fs * c , unsigned dev_idx , int flags )
{
2021-02-21 03:27:37 +03:00
return __bch2_dev_usrdata_drop ( c , dev_idx , flags , BTREE_ID_extents ) ? :
__bch2_dev_usrdata_drop ( c , dev_idx , flags , BTREE_ID_reflink ) ;
2019-08-16 16:59:56 +03:00
}
2017-03-17 09:18:50 +03:00
static int bch2_dev_metadata_drop ( struct bch_fs * c , unsigned dev_idx , int flags )
{
2019-03-25 22:10:15 +03:00
struct btree_trans trans ;
struct btree_iter * iter ;
2017-03-17 09:18:50 +03:00
struct closure cl ;
struct btree * b ;
2020-12-17 23:08:58 +03:00
struct bkey_buf k ;
2017-03-17 09:18:50 +03:00
unsigned id ;
int ret ;
/* don't handle this yet: */
if ( flags & BCH_FORCE_IF_METADATA_LOST )
return - EINVAL ;
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_init ( & k ) ;
2019-05-15 17:54:43 +03:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2017-03-17 09:18:50 +03:00
closure_init_stack ( & cl ) ;
for ( id = 0 ; id < BTREE_ID_NR ; id + + ) {
2019-03-25 22:10:15 +03:00
for_each_btree_node ( & trans , iter , id , POS_MIN ,
BTREE_ITER_PREFETCH , b ) {
2017-03-17 09:18:50 +03:00
retry :
2018-11-01 22:10:01 +03:00
if ( ! bch2_bkey_has_device ( bkey_i_to_s_c ( & b - > key ) ,
2020-01-04 06:38:14 +03:00
dev_idx ) )
continue ;
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_copy ( & k , c , & b - > key ) ;
2020-01-04 06:38:14 +03:00
2020-12-17 23:08:58 +03:00
ret = drop_dev_ptrs ( c , bkey_i_to_s ( k . k ) ,
2020-01-04 06:38:14 +03:00
dev_idx , flags , true ) ;
if ( ret ) {
bch_err ( c , " Cannot drop device without losing data " ) ;
goto err ;
}
2020-12-17 23:08:58 +03:00
ret = bch2_btree_node_update_key ( c , iter , b , k . k ) ;
2020-01-04 06:38:14 +03:00
if ( ret = = - EINTR ) {
b = bch2_btree_iter_peek_node ( iter ) ;
goto retry ;
}
if ( ret ) {
bch_err ( c , " Error updating btree node key: %i " , ret ) ;
goto err ;
2017-03-17 09:18:50 +03:00
}
}
2019-03-25 22:10:15 +03:00
bch2_trans_iter_free ( & trans , iter ) ;
2017-03-17 09:18:50 +03:00
}
2019-01-21 23:32:13 +03:00
/* flush relevant btree updates */
2020-05-25 21:57:06 +03:00
closure_wait_event ( & c - > btree_interior_update_wait ,
! bch2_btree_interior_updates_nr_pending ( c ) ) ;
2019-01-21 23:32:13 +03:00
2017-03-17 09:18:50 +03:00
ret = 0 ;
2019-03-25 22:10:15 +03:00
err :
2019-05-01 00:15:39 +03:00
ret = bch2_trans_exit ( & trans ) ? : ret ;
2020-12-17 23:08:58 +03:00
bch2_bkey_buf_exit ( & k , c ) ;
2019-03-25 22:10:15 +03:00
2019-05-01 00:15:39 +03:00
BUG_ON ( ret = = - EINTR ) ;
2017-03-17 09:18:50 +03:00
return ret ;
}
int bch2_dev_data_drop ( struct bch_fs * c , unsigned dev_idx , int flags )
{
return bch2_dev_usrdata_drop ( c , dev_idx , flags ) ? :
2020-01-04 06:38:14 +03:00
bch2_dev_metadata_drop ( c , dev_idx , flags ) ;
2017-03-17 09:18:50 +03:00
}