2021-03-16 00:42:25 -04:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "btree_key_cache.h"
# include "btree_update.h"
2022-07-18 19:42:58 -04:00
# include "errcode.h"
2021-03-16 00:42:25 -04:00
# include "error.h"
2021-10-11 12:03:19 -04:00
# include "fs.h"
2021-03-16 00:42:25 -04:00
# include "subvolume.h"
/* Snapshot tree: */
void bch2_snapshot_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot ( k ) ;
2022-07-12 09:11:52 -04:00
prt_printf ( out , " is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u " ,
2021-03-16 00:42:25 -04:00
BCH_SNAPSHOT_SUBVOL ( s . v ) ,
BCH_SNAPSHOT_DELETED ( s . v ) ,
le32_to_cpu ( s . v - > parent ) ,
le32_to_cpu ( s . v - > children [ 0 ] ) ,
le32_to_cpu ( s . v - > children [ 1 ] ) ,
le32_to_cpu ( s . v - > subvol ) ) ;
}
2022-04-03 17:50:01 -04:00
int bch2_snapshot_invalid ( const struct bch_fs * c , struct bkey_s_c k ,
2022-12-20 19:58:16 -05:00
unsigned flags , struct printbuf * err )
2021-03-16 00:42:25 -04:00
{
struct bkey_s_c_snapshot s ;
u32 i , id ;
2022-11-24 03:12:22 -05:00
if ( bkey_gt ( k . k - > p , POS ( 0 , U32_MAX ) ) | |
bkey_lt ( k . k - > p , POS ( 0 , 1 ) ) ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " bad pos " ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
2022-04-03 17:50:01 -04:00
if ( bkey_val_bytes ( k . k ) ! = sizeof ( struct bch_snapshot ) ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " bad val size (%zu != %zu) " ,
2022-04-03 17:50:01 -04:00
bkey_val_bytes ( k . k ) , sizeof ( struct bch_snapshot ) ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
s = bkey_s_c_to_snapshot ( k ) ;
id = le32_to_cpu ( s . v - > parent ) ;
2022-04-03 17:50:01 -04:00
if ( id & & id < = k . k - > p . offset ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " bad parent node (%u <= %llu) " ,
2022-04-03 17:50:01 -04:00
id , k . k - > p . offset ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
2022-04-03 17:50:01 -04:00
if ( le32_to_cpu ( s . v - > children [ 0 ] ) < le32_to_cpu ( s . v - > children [ 1 ] ) ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " children not normalized " ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
if ( s . v - > children [ 0 ] & &
2022-04-03 17:50:01 -04:00
s . v - > children [ 0 ] = = s . v - > children [ 1 ] ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " duplicate child nodes " ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
for ( i = 0 ; i < 2 ; i + + ) {
id = le32_to_cpu ( s . v - > children [ i ] ) ;
2022-04-03 17:50:01 -04:00
if ( id > = k . k - > p . offset ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " bad child node (%u >= %llu) " ,
2022-04-03 17:50:01 -04:00
id , k . k - > p . offset ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
}
2022-04-03 17:50:01 -04:00
return 0 ;
2021-03-16 00:42:25 -04:00
}
2021-10-29 18:43:18 -04:00
int bch2_mark_snapshot ( struct btree_trans * trans ,
2023-03-01 22:14:31 -05:00
enum btree_id btree , unsigned level ,
2021-03-16 00:42:25 -04:00
struct bkey_s_c old , struct bkey_s_c new ,
2021-10-29 18:43:18 -04:00
unsigned flags )
2021-03-16 00:42:25 -04:00
{
2021-10-29 18:43:18 -04:00
struct bch_fs * c = trans - > c ;
2021-03-16 00:42:25 -04:00
struct snapshot_t * t ;
t = genradix_ptr_alloc ( & c - > snapshots ,
U32_MAX - new . k - > p . offset ,
GFP_KERNEL ) ;
if ( ! t )
2023-03-14 15:35:57 -04:00
return - BCH_ERR_ENOMEM_mark_snapshot ;
2021-03-16 00:42:25 -04:00
if ( new . k - > type = = KEY_TYPE_snapshot ) {
struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot ( new ) ;
t - > parent = le32_to_cpu ( s . v - > parent ) ;
t - > children [ 0 ] = le32_to_cpu ( s . v - > children [ 0 ] ) ;
t - > children [ 1 ] = le32_to_cpu ( s . v - > children [ 1 ] ) ;
t - > subvol = BCH_SNAPSHOT_SUBVOL ( s . v ) ? le32_to_cpu ( s . v - > subvol ) : 0 ;
} else {
t - > parent = 0 ;
t - > children [ 0 ] = 0 ;
t - > children [ 1 ] = 0 ;
t - > subvol = 0 ;
}
return 0 ;
}
static int snapshot_lookup ( struct btree_trans * trans , u32 id ,
struct bch_snapshot * s )
{
struct btree_iter iter ;
struct bkey_s_c k ;
int ret ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_snapshots , POS ( 0 , id ) ,
BTREE_ITER_WITH_UPDATES ) ;
k = bch2_btree_iter_peek_slot ( & iter ) ;
ret = bkey_err ( k ) ? : k . k - > type = = KEY_TYPE_snapshot ? 0 : - ENOENT ;
if ( ! ret )
* s = * bkey_s_c_to_snapshot ( k ) . v ;
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
static int snapshot_live ( struct btree_trans * trans , u32 id )
{
struct bch_snapshot v ;
int ret ;
if ( ! id )
return 0 ;
2022-07-15 20:51:09 -04:00
ret = snapshot_lookup ( trans , id , & v ) ;
2021-03-16 00:42:25 -04:00
if ( ret = = - ENOENT )
bch_err ( trans - > c , " snapshot node %u not found " , id ) ;
if ( ret )
return ret ;
return ! BCH_SNAPSHOT_DELETED ( & v ) ;
}
2022-07-15 20:51:09 -04:00
static int bch2_snapshot_set_equiv ( struct btree_trans * trans , struct bkey_s_c k )
2021-03-16 00:42:25 -04:00
{
struct bch_fs * c = trans - > c ;
2022-07-14 05:44:10 -04:00
unsigned i , nr_live = 0 , live_idx = 0 ;
2022-07-15 20:51:09 -04:00
struct bkey_s_c_snapshot snap ;
u32 id = k . k - > p . offset , child [ 2 ] ;
if ( k . k - > type ! = KEY_TYPE_snapshot )
return 0 ;
snap = bkey_s_c_to_snapshot ( k ) ;
child [ 0 ] = le32_to_cpu ( snap . v - > children [ 0 ] ) ;
child [ 1 ] = le32_to_cpu ( snap . v - > children [ 1 ] ) ;
2022-07-14 05:44:10 -04:00
for ( i = 0 ; i < 2 ; i + + ) {
int ret = snapshot_live ( trans , child [ i ] ) ;
2022-10-22 15:59:53 -04:00
2022-07-14 05:44:10 -04:00
if ( ret < 0 )
return ret ;
if ( ret )
live_idx = i ;
nr_live + = ret ;
}
snapshot_t ( c , id ) - > equiv = nr_live = = 1
? snapshot_t ( c , child [ live_idx ] ) - > equiv
: id ;
return 0 ;
}
2021-03-16 00:42:25 -04:00
/* fsck: */
2022-07-14 05:44:10 -04:00
static int check_snapshot ( struct btree_trans * trans ,
2022-07-15 20:51:09 -04:00
struct btree_iter * iter ,
struct bkey_s_c k )
2021-03-16 00:42:25 -04:00
{
2022-07-14 05:44:10 -04:00
struct bch_fs * c = trans - > c ;
struct bkey_s_c_snapshot s ;
2021-03-16 00:42:25 -04:00
struct bch_subvolume subvol ;
struct bch_snapshot v ;
2022-07-14 05:44:10 -04:00
struct printbuf buf = PRINTBUF ;
bool should_have_subvol ;
2021-03-16 00:42:25 -04:00
u32 i , id ;
2022-07-14 05:44:10 -04:00
int ret = 0 ;
2021-03-16 00:42:25 -04:00
2022-07-14 05:44:10 -04:00
if ( k . k - > type ! = KEY_TYPE_snapshot )
return 0 ;
2021-03-16 00:42:25 -04:00
2022-07-14 05:44:10 -04:00
s = bkey_s_c_to_snapshot ( k ) ;
2021-03-16 00:42:25 -04:00
id = le32_to_cpu ( s . v - > parent ) ;
if ( id ) {
2022-07-15 20:51:09 -04:00
ret = snapshot_lookup ( trans , id , & v ) ;
2021-03-16 00:42:25 -04:00
if ( ret = = - ENOENT )
2022-07-14 05:44:10 -04:00
bch_err ( c , " snapshot with nonexistent parent: \n %s " ,
( bch2_bkey_val_to_text ( & buf , c , s . s_c ) , buf . buf ) ) ;
2021-03-16 00:42:25 -04:00
if ( ret )
2022-07-14 05:44:10 -04:00
goto err ;
2021-03-16 00:42:25 -04:00
if ( le32_to_cpu ( v . children [ 0 ] ) ! = s . k - > p . offset & &
le32_to_cpu ( v . children [ 1 ] ) ! = s . k - > p . offset ) {
2022-07-14 05:44:10 -04:00
bch_err ( c , " snapshot parent %u missing pointer to child %llu " ,
2021-03-16 00:42:25 -04:00
id , s . k - > p . offset ) ;
2022-07-14 05:44:10 -04:00
ret = - EINVAL ;
goto err ;
2021-03-16 00:42:25 -04:00
}
}
for ( i = 0 ; i < 2 & & s . v - > children [ i ] ; i + + ) {
id = le32_to_cpu ( s . v - > children [ i ] ) ;
2022-07-15 20:51:09 -04:00
ret = snapshot_lookup ( trans , id , & v ) ;
2021-03-16 00:42:25 -04:00
if ( ret = = - ENOENT )
2022-07-14 05:44:10 -04:00
bch_err ( c , " snapshot node %llu has nonexistent child %u " ,
2021-03-16 00:42:25 -04:00
s . k - > p . offset , id ) ;
if ( ret )
2022-07-14 05:44:10 -04:00
goto err ;
2021-03-16 00:42:25 -04:00
if ( le32_to_cpu ( v . parent ) ! = s . k - > p . offset ) {
2022-07-14 05:44:10 -04:00
bch_err ( c , " snapshot child %u has wrong parent (got %u should be %llu) " ,
2021-03-16 00:42:25 -04:00
id , le32_to_cpu ( v . parent ) , s . k - > p . offset ) ;
2022-07-14 05:44:10 -04:00
ret = - EINVAL ;
goto err ;
2021-03-16 00:42:25 -04:00
}
}
2022-07-14 05:44:10 -04:00
should_have_subvol = BCH_SNAPSHOT_SUBVOL ( s . v ) & &
! BCH_SNAPSHOT_DELETED ( s . v ) ;
if ( should_have_subvol ) {
id = le32_to_cpu ( s . v - > subvol ) ;
2022-07-15 20:51:09 -04:00
ret = bch2_subvolume_get ( trans , id , 0 , false , & subvol ) ;
2022-07-14 05:44:10 -04:00
if ( ret = = - ENOENT )
bch_err ( c , " snapshot points to nonexistent subvolume: \n %s " ,
( bch2_bkey_val_to_text ( & buf , c , s . s_c ) , buf . buf ) ) ;
if ( ret )
goto err ;
if ( BCH_SNAPSHOT_SUBVOL ( s . v ) ! = ( le32_to_cpu ( subvol . snapshot ) = = s . k - > p . offset ) ) {
bch_err ( c , " snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL " ,
s . k - > p . offset ) ;
ret = - EINVAL ;
goto err ;
}
} else {
if ( fsck_err_on ( s . v - > subvol , c , " snapshot should not point to subvol: \n %s " ,
( bch2_bkey_val_to_text ( & buf , c , s . s_c ) , buf . buf ) ) ) {
struct bkey_i_snapshot * u = bch2_trans_kmalloc ( trans , sizeof ( * u ) ) ;
ret = PTR_ERR_OR_ZERO ( u ) ;
if ( ret )
goto err ;
bkey_reassemble ( & u - > k_i , s . s_c ) ;
u - > v . subvol = 0 ;
ret = bch2_trans_update ( trans , iter , & u - > k_i , 0 ) ;
if ( ret )
goto err ;
}
}
if ( BCH_SNAPSHOT_DELETED ( s . v ) )
set_bit ( BCH_FS_HAVE_DELETED_SNAPSHOTS , & c - > flags ) ;
err :
fsck_err :
printbuf_exit ( & buf ) ;
return ret ;
2021-03-16 00:42:25 -04:00
}
2022-07-14 01:10:24 -04:00
int bch2_fs_check_snapshots ( struct bch_fs * c )
2021-03-16 00:42:25 -04:00
{
struct btree_trans trans ;
struct btree_iter iter ;
2022-07-15 20:51:09 -04:00
struct bkey_s_c k ;
2021-03-16 00:42:25 -04:00
int ret ;
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2022-08-15 14:01:56 -04:00
ret = for_each_btree_key_commit ( & trans , iter ,
BTREE_ID_snapshots , POS_MIN ,
2022-07-15 20:51:09 -04:00
BTREE_ITER_PREFETCH , k ,
NULL , NULL , BTREE_INSERT_LAZY_RW | BTREE_INSERT_NOFAIL ,
check_snapshot ( & trans , & iter , k ) ) ;
2021-03-16 00:42:25 -04:00
2022-07-14 05:44:10 -04:00
if ( ret )
2021-03-16 00:42:25 -04:00
bch_err ( c , " error %i checking snapshots " , ret ) ;
bch2_trans_exit ( & trans ) ;
return ret ;
}
2022-07-14 01:10:24 -04:00
static int check_subvol ( struct btree_trans * trans ,
2022-07-17 00:44:19 -04:00
struct btree_iter * iter ,
struct bkey_s_c k )
2022-07-14 01:10:24 -04:00
{
struct bkey_s_c_subvolume subvol ;
2022-07-14 05:44:10 -04:00
struct bch_snapshot snapshot ;
unsigned snapid ;
2022-07-14 01:10:24 -04:00
int ret ;
if ( k . k - > type ! = KEY_TYPE_subvolume )
return 0 ;
subvol = bkey_s_c_to_subvolume ( k ) ;
2022-07-14 05:44:10 -04:00
snapid = le32_to_cpu ( subvol . v - > snapshot ) ;
ret = snapshot_lookup ( trans , snapid , & snapshot ) ;
if ( ret = = - ENOENT )
bch_err ( trans - > c , " subvolume %llu points to nonexistent snapshot %u " ,
k . k - > p . offset , snapid ) ;
if ( ret )
return ret ;
2022-07-14 01:10:24 -04:00
if ( BCH_SUBVOLUME_UNLINKED ( subvol . v ) ) {
ret = bch2_subvolume_delete ( trans , iter - > pos . offset ) ;
2022-07-17 23:06:38 -04:00
if ( ret & & ! bch2_err_matches ( ret , BCH_ERR_transaction_restart ) )
2022-07-18 19:42:58 -04:00
bch_err ( trans - > c , " error deleting subvolume %llu: %s " ,
iter - > pos . offset , bch2_err_str ( ret ) ) ;
2022-07-14 01:10:24 -04:00
if ( ret )
return ret ;
}
return 0 ;
}
int bch2_fs_check_subvols ( struct bch_fs * c )
{
struct btree_trans trans ;
struct btree_iter iter ;
2022-07-17 00:44:19 -04:00
struct bkey_s_c k ;
2022-07-14 01:10:24 -04:00
int ret ;
2022-07-14 05:44:10 -04:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2022-07-14 01:10:24 -04:00
2022-07-17 00:44:19 -04:00
ret = for_each_btree_key_commit ( & trans , iter ,
BTREE_ID_subvolumes , POS_MIN , BTREE_ITER_PREFETCH , k ,
NULL , NULL , BTREE_INSERT_LAZY_RW | BTREE_INSERT_NOFAIL ,
check_subvol ( & trans , & iter , k ) ) ;
2022-07-14 01:10:24 -04:00
bch2_trans_exit ( & trans ) ;
return ret ;
}
2021-03-16 00:42:25 -04:00
void bch2_fs_snapshots_exit ( struct bch_fs * c )
{
genradix_free ( & c - > snapshots ) ;
}
int bch2_fs_snapshots_start ( struct bch_fs * c )
{
struct btree_trans trans ;
struct btree_iter iter ;
struct bkey_s_c k ;
int ret = 0 ;
bch2_trans_init ( & trans , c , 0 , 0 ) ;
2022-07-15 20:51:09 -04:00
for_each_btree_key2 ( & trans , iter , BTREE_ID_snapshots ,
POS_MIN , 0 , k ,
2023-03-01 22:14:31 -05:00
bch2_mark_snapshot ( & trans , BTREE_ID_snapshots , 0 , bkey_s_c_null , k , 0 ) ? :
2022-07-15 20:51:09 -04:00
bch2_snapshot_set_equiv ( & trans , k ) ) ;
2021-03-16 00:42:25 -04:00
2022-07-14 05:44:10 -04:00
bch2_trans_exit ( & trans ) ;
2021-03-16 00:42:25 -04:00
if ( ret )
2022-07-18 19:42:58 -04:00
bch_err ( c , " error starting snapshots: %s " , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
return ret ;
}
/*
* Mark a snapshot as deleted , for future cleanup :
*/
static int bch2_snapshot_node_set_deleted ( struct btree_trans * trans , u32 id )
{
struct btree_iter iter ;
struct bkey_i_snapshot * s ;
int ret = 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_snapshots , POS ( 0 , id ) ,
BTREE_ITER_INTENT ) ;
2022-11-23 22:13:19 -05:00
s = bch2_bkey_get_mut_typed ( trans , & iter , snapshot ) ;
ret = PTR_ERR_OR_ZERO ( s ) ;
if ( unlikely ( ret ) ) {
bch2_fs_inconsistent_on ( ret = = - ENOENT , trans - > c , " missing snapshot %u " , id ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
/* already deleted? */
2022-11-23 22:13:19 -05:00
if ( BCH_SNAPSHOT_DELETED ( & s - > v ) )
2021-03-16 00:42:25 -04:00
goto err ;
SET_BCH_SNAPSHOT_DELETED ( & s - > v , true ) ;
2022-07-12 09:11:52 -04:00
SET_BCH_SNAPSHOT_SUBVOL ( & s - > v , false ) ;
s - > v . subvol = 0 ;
2021-03-16 00:42:25 -04:00
ret = bch2_trans_update ( trans , & iter , & s - > k_i , 0 ) ;
if ( ret )
goto err ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
static int bch2_snapshot_node_delete ( struct btree_trans * trans , u32 id )
{
struct btree_iter iter , p_iter = ( struct btree_iter ) { NULL } ;
struct bkey_s_c k ;
struct bkey_s_c_snapshot s ;
u32 parent_id ;
unsigned i ;
int ret = 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_snapshots , POS ( 0 , id ) ,
BTREE_ITER_INTENT ) ;
k = bch2_btree_iter_peek_slot ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
if ( k . k - > type ! = KEY_TYPE_snapshot ) {
bch2_fs_inconsistent ( trans - > c , " missing snapshot %u " , id ) ;
ret = - ENOENT ;
goto err ;
}
s = bkey_s_c_to_snapshot ( k ) ;
BUG_ON ( ! BCH_SNAPSHOT_DELETED ( s . v ) ) ;
parent_id = le32_to_cpu ( s . v - > parent ) ;
if ( parent_id ) {
2022-11-23 22:13:19 -05:00
struct bkey_i_snapshot * parent ;
2021-03-16 00:42:25 -04:00
bch2_trans_iter_init ( trans , & p_iter , BTREE_ID_snapshots ,
POS ( 0 , parent_id ) ,
BTREE_ITER_INTENT ) ;
2022-11-23 22:13:19 -05:00
parent = bch2_bkey_get_mut_typed ( trans , & p_iter , snapshot ) ;
2021-03-16 00:42:25 -04:00
ret = PTR_ERR_OR_ZERO ( parent ) ;
2022-11-23 22:13:19 -05:00
if ( unlikely ( ret ) ) {
bch2_fs_inconsistent_on ( ret = = - ENOENT , trans - > c , " missing snapshot %u " , parent_id ) ;
2021-03-16 00:42:25 -04:00
goto err ;
2022-11-23 22:13:19 -05:00
}
2021-03-16 00:42:25 -04:00
for ( i = 0 ; i < 2 ; i + + )
if ( le32_to_cpu ( parent - > v . children [ i ] ) = = id )
break ;
if ( i = = 2 )
bch_err ( trans - > c , " snapshot %u missing child pointer to %u " ,
parent_id , id ) ;
else
parent - > v . children [ i ] = 0 ;
if ( le32_to_cpu ( parent - > v . children [ 0 ] ) <
le32_to_cpu ( parent - > v . children [ 1 ] ) )
swap ( parent - > v . children [ 0 ] ,
parent - > v . children [ 1 ] ) ;
ret = bch2_trans_update ( trans , & p_iter , & parent - > k_i , 0 ) ;
if ( ret )
goto err ;
}
ret = bch2_btree_delete_at ( trans , & iter , 0 ) ;
err :
bch2_trans_iter_exit ( trans , & p_iter ) ;
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2021-12-29 13:50:50 -05:00
int bch2_snapshot_node_create ( struct btree_trans * trans , u32 parent ,
u32 * new_snapids ,
u32 * snapshot_subvols ,
unsigned nr_snapids )
2021-03-16 00:42:25 -04:00
{
struct btree_iter iter ;
struct bkey_i_snapshot * n ;
struct bkey_s_c k ;
unsigned i ;
int ret = 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_snapshots ,
POS_MIN , BTREE_ITER_INTENT ) ;
k = bch2_btree_iter_peek ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
for ( i = 0 ; i < nr_snapids ; i + + ) {
k = bch2_btree_iter_prev_slot ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
if ( ! k . k | | ! k . k - > p . offset ) {
2022-09-18 17:10:33 -04:00
ret = - BCH_ERR_ENOSPC_snapshot_create ;
2021-03-16 00:42:25 -04:00
goto err ;
}
2022-11-23 22:13:19 -05:00
n = bch2_bkey_alloc ( trans , & iter , snapshot ) ;
2021-03-16 00:42:25 -04:00
ret = PTR_ERR_OR_ZERO ( n ) ;
if ( ret )
2021-12-05 00:30:49 -05:00
goto err ;
2021-03-16 00:42:25 -04:00
n - > v . flags = 0 ;
n - > v . parent = cpu_to_le32 ( parent ) ;
n - > v . subvol = cpu_to_le32 ( snapshot_subvols [ i ] ) ;
n - > v . pad = 0 ;
SET_BCH_SNAPSHOT_SUBVOL ( & n - > v , true ) ;
2023-03-13 07:09:33 -04:00
ret = bch2_trans_update ( trans , & iter , & n - > k_i , 0 ) ? :
bch2_mark_snapshot ( trans , BTREE_ID_snapshots , 0 ,
bkey_s_c_null , bkey_i_to_s_c ( & n - > k_i ) , 0 ) ;
2021-03-16 00:42:25 -04:00
if ( ret )
2021-12-05 00:30:49 -05:00
goto err ;
2021-03-16 00:42:25 -04:00
new_snapids [ i ] = iter . pos . offset ;
}
if ( parent ) {
bch2_btree_iter_set_pos ( & iter , POS ( 0 , parent ) ) ;
2022-11-23 22:13:19 -05:00
n = bch2_bkey_get_mut_typed ( trans , & iter , snapshot ) ;
2021-03-16 00:42:25 -04:00
ret = PTR_ERR_OR_ZERO ( n ) ;
2022-11-23 22:13:19 -05:00
if ( unlikely ( ret ) ) {
if ( ret = = - ENOENT )
bch_err ( trans - > c , " snapshot %u not found " , parent ) ;
2022-01-08 19:07:32 -05:00
goto err ;
2022-11-23 22:13:19 -05:00
}
2021-03-16 00:42:25 -04:00
if ( n - > v . children [ 0 ] | | n - > v . children [ 1 ] ) {
bch_err ( trans - > c , " Trying to add child snapshot nodes to parent that already has children " ) ;
ret = - EINVAL ;
goto err ;
}
n - > v . children [ 0 ] = cpu_to_le32 ( new_snapids [ 0 ] ) ;
n - > v . children [ 1 ] = cpu_to_le32 ( new_snapids [ 1 ] ) ;
2022-07-14 05:44:10 -04:00
n - > v . subvol = 0 ;
2021-03-16 00:42:25 -04:00
SET_BCH_SNAPSHOT_SUBVOL ( & n - > v , false ) ;
2023-03-13 07:09:33 -04:00
ret = bch2_trans_update ( trans , & iter , & n - > k_i , 0 ) ;
2021-12-05 00:30:49 -05:00
if ( ret )
goto err ;
2021-03-16 00:42:25 -04:00
}
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2022-07-17 00:44:19 -04:00
static int snapshot_delete_key ( struct btree_trans * trans ,
struct btree_iter * iter ,
struct bkey_s_c k ,
snapshot_id_list * deleted ,
snapshot_id_list * equiv_seen ,
struct bpos * last_pos )
2021-03-16 00:42:25 -04:00
{
struct bch_fs * c = trans - > c ;
2022-07-17 00:44:19 -04:00
u32 equiv = snapshot_t ( c , k . k - > p . snapshot ) - > equiv ;
2021-03-16 00:42:25 -04:00
2022-11-24 03:12:22 -05:00
if ( ! bkey_eq ( k . k - > p , * last_pos ) )
2022-07-17 00:44:19 -04:00
equiv_seen - > nr = 0 ;
* last_pos = k . k - > p ;
2021-03-16 00:42:25 -04:00
2022-07-17 00:44:19 -04:00
if ( snapshot_list_has_id ( deleted , k . k - > p . snapshot ) | |
snapshot_list_has_id ( equiv_seen , equiv ) ) {
return bch2_btree_delete_at ( trans , iter ,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE ) ;
} else {
return snapshot_list_add ( c , equiv_seen , equiv ) ;
2021-03-16 00:42:25 -04:00
}
}
2022-07-15 20:51:09 -04:00
static int bch2_delete_redundant_snapshot ( struct btree_trans * trans , struct btree_iter * iter ,
struct bkey_s_c k )
{
struct bkey_s_c_snapshot snap ;
u32 children [ 2 ] ;
int ret ;
if ( k . k - > type ! = KEY_TYPE_snapshot )
return 0 ;
snap = bkey_s_c_to_snapshot ( k ) ;
if ( BCH_SNAPSHOT_DELETED ( snap . v ) | |
BCH_SNAPSHOT_SUBVOL ( snap . v ) )
return 0 ;
children [ 0 ] = le32_to_cpu ( snap . v - > children [ 0 ] ) ;
children [ 1 ] = le32_to_cpu ( snap . v - > children [ 1 ] ) ;
ret = snapshot_live ( trans , children [ 0 ] ) ? :
snapshot_live ( trans , children [ 1 ] ) ;
if ( ret < 0 )
return ret ;
if ( ! ret )
return bch2_snapshot_node_set_deleted ( trans , k . k - > p . offset ) ;
return 0 ;
}
2022-07-14 01:10:24 -04:00
int bch2_delete_dead_snapshots ( struct bch_fs * c )
2021-03-16 00:42:25 -04:00
{
struct btree_trans trans ;
struct btree_iter iter ;
struct bkey_s_c k ;
struct bkey_s_c_snapshot snap ;
2022-03-29 15:48:45 -04:00
snapshot_id_list deleted = { 0 } ;
2022-07-15 20:51:09 -04:00
u32 i , id ;
2021-03-16 00:42:25 -04:00
int ret = 0 ;
2022-07-14 01:10:24 -04:00
if ( ! test_bit ( BCH_FS_HAVE_DELETED_SNAPSHOTS , & c - > flags ) )
return 0 ;
if ( ! test_bit ( BCH_FS_STARTED , & c - > flags ) ) {
ret = bch2_fs_read_write_early ( c ) ;
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error deleleting dead snapshots: error going rw: %s " , bch2_err_str ( ret ) ) ;
2022-07-14 01:10:24 -04:00
return ret ;
}
}
2021-03-16 00:42:25 -04:00
bch2_trans_init ( & trans , c , 0 , 0 ) ;
/*
* For every snapshot node : If we have no live children and it ' s not
* pointed to by a subvolume , delete it :
*/
2022-07-15 20:51:09 -04:00
ret = for_each_btree_key_commit ( & trans , iter , BTREE_ID_snapshots ,
POS_MIN , 0 , k ,
NULL , NULL , 0 ,
bch2_delete_redundant_snapshot ( & trans , & iter , k ) ) ;
2021-03-16 00:42:25 -04:00
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error deleting redundant snapshots: %s " , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
2022-07-15 20:51:09 -04:00
for_each_btree_key2 ( & trans , iter , BTREE_ID_snapshots ,
POS_MIN , 0 , k ,
bch2_snapshot_set_equiv ( & trans , k ) ) ;
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error in bch2_snapshots_set_equiv: %s " , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
goto err ;
2022-07-15 20:51:09 -04:00
}
2021-03-16 00:42:25 -04:00
for_each_btree_key ( & trans , iter , BTREE_ID_snapshots ,
POS_MIN , 0 , k , ret ) {
if ( k . k - > type ! = KEY_TYPE_snapshot )
continue ;
snap = bkey_s_c_to_snapshot ( k ) ;
if ( BCH_SNAPSHOT_DELETED ( snap . v ) ) {
2022-07-14 02:34:48 -04:00
ret = snapshot_list_add ( c , & deleted , k . k - > p . offset ) ;
2021-03-16 00:42:25 -04:00
if ( ret )
break ;
}
}
bch2_trans_iter_exit ( & trans , & iter ) ;
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error walking snapshots: %s " , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
for ( id = 0 ; id < BTREE_ID_NR ; id + + ) {
2022-07-17 00:44:19 -04:00
struct bpos last_pos = POS_MIN ;
snapshot_id_list equiv_seen = { 0 } ;
2021-03-16 00:42:25 -04:00
if ( ! btree_type_has_snapshots ( id ) )
continue ;
2022-07-17 00:44:19 -04:00
ret = for_each_btree_key_commit ( & trans , iter ,
id , POS_MIN ,
BTREE_ITER_PREFETCH | BTREE_ITER_ALL_SNAPSHOTS , k ,
NULL , NULL , BTREE_INSERT_NOFAIL ,
snapshot_delete_key ( & trans , & iter , k , & deleted , & equiv_seen , & last_pos ) ) ;
darray_exit ( & equiv_seen ) ;
2021-03-16 00:42:25 -04:00
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error deleting snapshot keys: %s " , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
}
for ( i = 0 ; i < deleted . nr ; i + + ) {
2022-07-13 05:25:29 -04:00
ret = commit_do ( & trans , NULL , NULL , 0 ,
2022-03-29 15:48:45 -04:00
bch2_snapshot_node_delete ( & trans , deleted . data [ i ] ) ) ;
2021-03-16 00:42:25 -04:00
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error deleting snapshot %u: %s " ,
deleted . data [ i ] , bch2_err_str ( ret ) ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
}
2022-07-14 01:10:24 -04:00
clear_bit ( BCH_FS_HAVE_DELETED_SNAPSHOTS , & c - > flags ) ;
2021-03-16 00:42:25 -04:00
err :
2022-03-29 15:48:45 -04:00
darray_exit ( & deleted ) ;
2021-03-16 00:42:25 -04:00
bch2_trans_exit ( & trans ) ;
2022-07-14 01:10:24 -04:00
return ret ;
}
static void bch2_delete_dead_snapshots_work ( struct work_struct * work )
{
struct bch_fs * c = container_of ( work , struct bch_fs , snapshot_delete_work ) ;
bch2_delete_dead_snapshots ( c ) ;
2023-02-09 12:21:45 -05:00
bch2_write_ref_put ( c , BCH_WRITE_REF_delete_dead_snapshots ) ;
2021-03-16 00:42:25 -04:00
}
2022-07-14 01:10:24 -04:00
void bch2_delete_dead_snapshots_async ( struct bch_fs * c )
2021-03-16 00:42:25 -04:00
{
2023-02-09 12:21:45 -05:00
if ( bch2_write_ref_tryget ( c , BCH_WRITE_REF_delete_dead_snapshots ) & &
! queue_work ( system_long_wq , & c - > snapshot_delete_work ) )
bch2_write_ref_put ( c , BCH_WRITE_REF_delete_dead_snapshots ) ;
2021-03-16 00:42:25 -04:00
}
static int bch2_delete_dead_snapshots_hook ( struct btree_trans * trans ,
struct btree_trans_commit_hook * h )
{
2022-07-14 01:10:24 -04:00
struct bch_fs * c = trans - > c ;
set_bit ( BCH_FS_HAVE_DELETED_SNAPSHOTS , & c - > flags ) ;
if ( ! test_bit ( BCH_FS_FSCK_DONE , & c - > flags ) )
return 0 ;
bch2_delete_dead_snapshots_async ( c ) ;
2021-03-16 00:42:25 -04:00
return 0 ;
}
/* Subvolumes: */
2022-04-03 17:50:01 -04:00
int bch2_subvolume_invalid ( const struct bch_fs * c , struct bkey_s_c k ,
2022-12-20 19:58:16 -05:00
unsigned flags , struct printbuf * err )
2021-03-16 00:42:25 -04:00
{
2022-11-24 03:12:22 -05:00
if ( bkey_lt ( k . k - > p , SUBVOL_POS_MIN ) | |
bkey_gt ( k . k - > p , SUBVOL_POS_MAX ) ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " invalid pos " ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
2022-04-03 17:50:01 -04:00
if ( bkey_val_bytes ( k . k ) ! = sizeof ( struct bch_subvolume ) ) {
2023-02-03 21:01:40 -05:00
prt_printf ( err , " incorrect value size (%zu != %zu) " ,
2022-04-03 17:50:01 -04:00
bkey_val_bytes ( k . k ) , sizeof ( struct bch_subvolume ) ) ;
2022-11-19 22:39:08 -05:00
return - BCH_ERR_invalid_bkey ;
2022-04-03 17:50:01 -04:00
}
2021-03-16 00:42:25 -04:00
2022-04-03 17:50:01 -04:00
return 0 ;
2021-03-16 00:42:25 -04:00
}
void bch2_subvolume_to_text ( struct printbuf * out , struct bch_fs * c ,
struct bkey_s_c k )
{
struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume ( k ) ;
2023-02-03 21:01:40 -05:00
prt_printf ( out , " root %llu snapshot id %u " ,
2021-03-16 00:42:25 -04:00
le64_to_cpu ( s . v - > inode ) ,
le32_to_cpu ( s . v - > snapshot ) ) ;
}
2022-11-23 18:22:59 -05:00
static __always_inline int
bch2_subvolume_get_inlined ( struct btree_trans * trans , unsigned subvol ,
bool inconsistent_if_not_found ,
int iter_flags ,
struct bch_subvolume * s )
2021-03-16 00:42:25 -04:00
{
struct btree_iter iter ;
struct bkey_s_c k ;
int ret ;
2021-09-30 19:46:23 -04:00
bch2_trans_iter_init ( trans , & iter , BTREE_ID_subvolumes , POS ( 0 , subvol ) ,
iter_flags ) ;
2021-03-16 00:42:25 -04:00
k = bch2_btree_iter_peek_slot ( & iter ) ;
2021-09-30 19:46:23 -04:00
ret = bkey_err ( k ) ? : k . k - > type = = KEY_TYPE_subvolume ? 0 : - ENOENT ;
2021-03-16 00:42:25 -04:00
2021-09-30 19:46:23 -04:00
if ( ret = = - ENOENT & & inconsistent_if_not_found )
2021-03-16 00:42:25 -04:00
bch2_fs_inconsistent ( trans - > c , " missing subvolume %u " , subvol ) ;
2021-09-30 19:46:23 -04:00
if ( ! ret )
* s = * bkey_s_c_to_subvolume ( k ) . v ;
2021-03-16 00:42:25 -04:00
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2022-11-23 18:22:59 -05:00
int bch2_subvolume_get ( struct btree_trans * trans , unsigned subvol ,
bool inconsistent_if_not_found ,
int iter_flags ,
struct bch_subvolume * s )
{
return bch2_subvolume_get_inlined ( trans , subvol , inconsistent_if_not_found , iter_flags , s ) ;
}
2021-10-27 13:05:56 -04:00
int bch2_snapshot_get_subvol ( struct btree_trans * trans , u32 snapshot ,
struct bch_subvolume * subvol )
{
struct bch_snapshot snap ;
return snapshot_lookup ( trans , snapshot , & snap ) ? :
bch2_subvolume_get ( trans , le32_to_cpu ( snap . subvol ) , true , 0 , subvol ) ;
}
2021-09-30 19:46:23 -04:00
int bch2_subvolume_get_snapshot ( struct btree_trans * trans , u32 subvol ,
u32 * snapid )
{
struct bch_subvolume s ;
int ret ;
2022-11-23 18:22:59 -05:00
ret = bch2_subvolume_get_inlined ( trans , subvol , true ,
BTREE_ITER_CACHED |
BTREE_ITER_WITH_UPDATES ,
& s ) ;
if ( ! ret )
* snapid = le32_to_cpu ( s . snapshot ) ;
2021-09-30 19:46:23 -04:00
return ret ;
}
2021-10-11 12:03:19 -04:00
/*
* Delete subvolume , mark snapshot ID as deleted , queue up snapshot
* deletion / cleanup :
*/
int bch2_subvolume_delete ( struct btree_trans * trans , u32 subvolid )
2021-03-16 00:42:25 -04:00
{
struct btree_iter iter ;
struct bkey_s_c k ;
struct bkey_s_c_subvolume subvol ;
struct btree_trans_commit_hook * h ;
u32 snapid ;
int ret = 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_subvolumes ,
POS ( 0 , subvolid ) ,
BTREE_ITER_CACHED |
BTREE_ITER_INTENT ) ;
k = bch2_btree_iter_peek_slot ( & iter ) ;
ret = bkey_err ( k ) ;
if ( ret )
goto err ;
if ( k . k - > type ! = KEY_TYPE_subvolume ) {
bch2_fs_inconsistent ( trans - > c , " missing subvolume %u " , subvolid ) ;
ret = - EIO ;
goto err ;
}
subvol = bkey_s_c_to_subvolume ( k ) ;
snapid = le32_to_cpu ( subvol . v - > snapshot ) ;
2022-07-12 09:11:52 -04:00
ret = bch2_btree_delete_at ( trans , & iter , 0 ) ;
2021-03-16 00:42:25 -04:00
if ( ret )
goto err ;
ret = bch2_snapshot_node_set_deleted ( trans , snapid ) ;
2022-08-09 13:47:03 -04:00
if ( ret )
goto err ;
2021-03-16 00:42:25 -04:00
h = bch2_trans_kmalloc ( trans , sizeof ( * h ) ) ;
ret = PTR_ERR_OR_ZERO ( h ) ;
if ( ret )
goto err ;
h - > fn = bch2_delete_dead_snapshots_hook ;
bch2_trans_commit_hook ( trans , h ) ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2021-10-11 12:03:19 -04:00
void bch2_subvolume_wait_for_pagecache_and_delete ( struct work_struct * work )
{
struct bch_fs * c = container_of ( work , struct bch_fs ,
snapshot_wait_for_pagecache_and_delete_work ) ;
2022-03-29 15:48:45 -04:00
snapshot_id_list s ;
2021-10-11 12:03:19 -04:00
u32 * id ;
int ret = 0 ;
while ( ! ret ) {
mutex_lock ( & c - > snapshots_unlinked_lock ) ;
s = c - > snapshots_unlinked ;
2022-03-29 15:48:45 -04:00
darray_init ( & c - > snapshots_unlinked ) ;
2021-10-11 12:03:19 -04:00
mutex_unlock ( & c - > snapshots_unlinked_lock ) ;
if ( ! s . nr )
break ;
bch2_evict_subvolume_inodes ( c , & s ) ;
2022-03-29 15:48:45 -04:00
for ( id = s . data ; id < s . data + s . nr ; id + + ) {
2021-10-11 12:03:19 -04:00
ret = bch2_trans_do ( c , NULL , NULL , BTREE_INSERT_NOFAIL ,
bch2_subvolume_delete ( & trans , * id ) ) ;
if ( ret ) {
2022-07-18 19:42:58 -04:00
bch_err ( c , " error deleting subvolume %u: %s " , * id , bch2_err_str ( ret ) ) ;
2021-10-11 12:03:19 -04:00
break ;
}
}
2022-03-29 15:48:45 -04:00
darray_exit ( & s ) ;
2021-10-11 12:03:19 -04:00
}
2023-02-09 12:21:45 -05:00
bch2_write_ref_put ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) ;
2021-10-11 12:03:19 -04:00
}
struct subvolume_unlink_hook {
struct btree_trans_commit_hook h ;
u32 subvol ;
} ;
int bch2_subvolume_wait_for_pagecache_and_delete_hook ( struct btree_trans * trans ,
struct btree_trans_commit_hook * _h )
{
struct subvolume_unlink_hook * h = container_of ( _h , struct subvolume_unlink_hook , h ) ;
struct bch_fs * c = trans - > c ;
int ret = 0 ;
mutex_lock ( & c - > snapshots_unlinked_lock ) ;
if ( ! snapshot_list_has_id ( & c - > snapshots_unlinked , h - > subvol ) )
2022-07-14 02:34:48 -04:00
ret = snapshot_list_add ( c , & c - > snapshots_unlinked , h - > subvol ) ;
2021-10-11 12:03:19 -04:00
mutex_unlock ( & c - > snapshots_unlinked_lock ) ;
if ( ret )
return ret ;
2023-02-09 12:21:45 -05:00
if ( ! bch2_write_ref_tryget ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) )
2021-10-11 12:03:19 -04:00
return - EROFS ;
if ( ! queue_work ( system_long_wq , & c - > snapshot_wait_for_pagecache_and_delete_work ) )
2023-02-09 12:21:45 -05:00
bch2_write_ref_put ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) ;
2021-10-11 12:03:19 -04:00
return 0 ;
}
int bch2_subvolume_unlink ( struct btree_trans * trans , u32 subvolid )
{
struct btree_iter iter ;
struct bkey_i_subvolume * n ;
struct subvolume_unlink_hook * h ;
int ret = 0 ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_subvolumes ,
POS ( 0 , subvolid ) ,
BTREE_ITER_CACHED |
BTREE_ITER_INTENT ) ;
2022-11-23 22:13:19 -05:00
n = bch2_bkey_get_mut_typed ( trans , & iter , subvolume ) ;
2021-10-11 12:03:19 -04:00
ret = PTR_ERR_OR_ZERO ( n ) ;
2022-11-23 22:13:19 -05:00
if ( unlikely ( ret ) ) {
bch2_fs_inconsistent_on ( ret = = - ENOENT , trans - > c , " missing subvolume %u " , subvolid ) ;
2021-10-11 12:03:19 -04:00
goto err ;
2022-11-23 22:13:19 -05:00
}
2021-10-11 12:03:19 -04:00
SET_BCH_SUBVOLUME_UNLINKED ( & n - > v , true ) ;
ret = bch2_trans_update ( trans , & iter , & n - > k_i , 0 ) ;
if ( ret )
goto err ;
h = bch2_trans_kmalloc ( trans , sizeof ( * h ) ) ;
ret = PTR_ERR_OR_ZERO ( h ) ;
if ( ret )
goto err ;
h - > h . fn = bch2_subvolume_wait_for_pagecache_and_delete_hook ;
h - > subvol = subvolid ;
bch2_trans_commit_hook ( trans , & h - > h ) ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2021-03-16 00:42:25 -04:00
int bch2_subvolume_create ( struct btree_trans * trans , u64 inode ,
u32 src_subvolid ,
u32 * new_subvolid ,
u32 * new_snapshotid ,
bool ro )
{
2021-10-18 14:46:57 -04:00
struct bch_fs * c = trans - > c ;
2021-03-16 00:42:25 -04:00
struct btree_iter dst_iter , src_iter = ( struct btree_iter ) { NULL } ;
struct bkey_i_subvolume * new_subvol = NULL ;
struct bkey_i_subvolume * src_subvol = NULL ;
struct bkey_s_c k ;
u32 parent = 0 , new_nodes [ 2 ] , snapshot_subvols [ 2 ] ;
int ret = 0 ;
for_each_btree_key ( trans , dst_iter , BTREE_ID_subvolumes , SUBVOL_POS_MIN ,
BTREE_ITER_SLOTS | BTREE_ITER_INTENT , k , ret ) {
2022-11-24 03:12:22 -05:00
if ( bkey_gt ( k . k - > p , SUBVOL_POS_MAX ) )
2021-03-16 00:42:25 -04:00
break ;
2021-10-18 14:46:57 -04:00
/*
* bch2_subvolume_delete ( ) doesn ' t flush the btree key cache -
* ideally it would but that ' s tricky
*/
if ( bkey_deleted ( k . k ) & &
! bch2_btree_key_cache_find ( c , BTREE_ID_subvolumes , dst_iter . pos ) )
2021-03-16 00:42:25 -04:00
goto found_slot ;
}
if ( ! ret )
2022-09-18 17:10:33 -04:00
ret = - BCH_ERR_ENOSPC_subvolume_create ;
2021-03-16 00:42:25 -04:00
goto err ;
found_slot :
snapshot_subvols [ 0 ] = dst_iter . pos . offset ;
snapshot_subvols [ 1 ] = src_subvolid ;
if ( src_subvolid ) {
/* Creating a snapshot: */
bch2_trans_iter_init ( trans , & src_iter , BTREE_ID_subvolumes ,
POS ( 0 , src_subvolid ) ,
BTREE_ITER_CACHED |
BTREE_ITER_INTENT ) ;
2022-11-23 22:13:19 -05:00
src_subvol = bch2_bkey_get_mut_typed ( trans , & src_iter , subvolume ) ;
ret = PTR_ERR_OR_ZERO ( src_subvol ) ;
if ( unlikely ( ret ) ) {
bch2_fs_inconsistent_on ( ret = = - ENOENT , trans - > c ,
" subvolume %u not found " , src_subvolid ) ;
2021-03-16 00:42:25 -04:00
goto err ;
}
parent = le32_to_cpu ( src_subvol - > v . snapshot ) ;
}
ret = bch2_snapshot_node_create ( trans , parent , new_nodes ,
snapshot_subvols ,
src_subvolid ? 2 : 1 ) ;
if ( ret )
goto err ;
if ( src_subvolid ) {
src_subvol - > v . snapshot = cpu_to_le32 ( new_nodes [ 1 ] ) ;
2021-12-05 00:30:49 -05:00
ret = bch2_trans_update ( trans , & src_iter , & src_subvol - > k_i , 0 ) ;
if ( ret )
goto err ;
2021-03-16 00:42:25 -04:00
}
2022-11-23 22:13:19 -05:00
new_subvol = bch2_bkey_alloc ( trans , & dst_iter , subvolume ) ;
2021-03-16 00:42:25 -04:00
ret = PTR_ERR_OR_ZERO ( new_subvol ) ;
if ( ret )
goto err ;
new_subvol - > v . flags = 0 ;
new_subvol - > v . snapshot = cpu_to_le32 ( new_nodes [ 0 ] ) ;
new_subvol - > v . inode = cpu_to_le64 ( inode ) ;
SET_BCH_SUBVOLUME_RO ( & new_subvol - > v , ro ) ;
SET_BCH_SUBVOLUME_SNAP ( & new_subvol - > v , src_subvolid ! = 0 ) ;
2021-12-05 00:30:49 -05:00
ret = bch2_trans_update ( trans , & dst_iter , & new_subvol - > k_i , 0 ) ;
if ( ret )
goto err ;
2021-03-16 00:42:25 -04:00
* new_subvolid = new_subvol - > k . p . offset ;
* new_snapshotid = new_nodes [ 0 ] ;
err :
bch2_trans_iter_exit ( trans , & src_iter ) ;
bch2_trans_iter_exit ( trans , & dst_iter ) ;
return ret ;
}
int bch2_fs_subvolumes_init ( struct bch_fs * c )
{
INIT_WORK ( & c - > snapshot_delete_work , bch2_delete_dead_snapshots_work ) ;
2021-10-11 12:03:19 -04:00
INIT_WORK ( & c - > snapshot_wait_for_pagecache_and_delete_work ,
bch2_subvolume_wait_for_pagecache_and_delete ) ;
mutex_init ( & c - > snapshots_unlinked_lock ) ;
2021-03-16 00:42:25 -04:00
return 0 ;
}