2021-03-16 07:42:25 +03:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "btree_key_cache.h"
# include "btree_update.h"
2022-07-19 02:42:58 +03:00
# include "errcode.h"
2021-03-16 07:42:25 +03:00
# include "error.h"
2021-10-11 19:03:19 +03:00
# include "fs.h"
2023-08-16 23:54:33 +03:00
# include "snapshot.h"
2021-03-16 07:42:25 +03:00
# include "subvolume.h"
2023-06-26 01:04:46 +03:00
# include <linux/random.h>
2023-03-29 18:18:59 +03:00
static int bch2_subvolume_delete ( struct btree_trans * , u32 ) ;
2024-01-21 14:00:07 +03:00
static struct bpos subvolume_children_pos ( struct bkey_s_c k )
{
if ( k . k - > type ! = KEY_TYPE_subvolume )
return POS_MIN ;
struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume ( k ) ;
if ( ! s . v - > fs_path_parent )
return POS_MIN ;
return POS ( le32_to_cpu ( s . v - > fs_path_parent ) , s . k - > p . offset ) ;
}
2022-07-14 08:10:24 +03:00
static int check_subvol ( struct btree_trans * trans ,
2022-07-17 07:44:19 +03:00
struct btree_iter * iter ,
struct bkey_s_c k )
2022-07-14 08:10:24 +03:00
{
2023-03-29 18:18:52 +03:00
struct bch_fs * c = trans - > c ;
2022-07-14 08:10:24 +03:00
struct bkey_s_c_subvolume subvol ;
2024-01-21 14:00:07 +03:00
struct btree_iter subvol_children_iter = { } ;
2022-07-14 12:44:10 +03:00
struct bch_snapshot snapshot ;
2024-02-09 02:39:42 +03:00
struct printbuf buf = PRINTBUF ;
2022-07-14 12:44:10 +03:00
unsigned snapid ;
2023-03-29 18:18:52 +03:00
int ret = 0 ;
2022-07-14 08:10:24 +03:00
if ( k . k - > type ! = KEY_TYPE_subvolume )
return 0 ;
subvol = bkey_s_c_to_subvolume ( k ) ;
2022-07-14 12:44:10 +03:00
snapid = le32_to_cpu ( subvol . v - > snapshot ) ;
2023-08-16 23:54:33 +03:00
ret = bch2_snapshot_lookup ( trans , snapid , & snapshot ) ;
2022-07-14 12:44:10 +03:00
2023-03-29 18:18:52 +03:00
if ( bch2_err_matches ( ret , ENOENT ) )
bch_err ( c , " subvolume %llu points to nonexistent snapshot %u " ,
2022-07-14 12:44:10 +03:00
k . k - > p . offset , snapid ) ;
if ( ret )
return ret ;
2022-07-14 08:10:24 +03:00
if ( BCH_SUBVOLUME_UNLINKED ( subvol . v ) ) {
ret = bch2_subvolume_delete ( trans , iter - > pos . offset ) ;
2023-12-17 06:43:41 +03:00
bch_err_msg ( c , ret , " deleting subvolume %llu " , iter - > pos . offset ) ;
2023-03-29 18:18:59 +03:00
return ret ? : - BCH_ERR_transaction_restart_nested ;
2022-07-14 08:10:24 +03:00
}
2024-02-09 02:39:42 +03:00
if ( fsck_err_on ( subvol . k - > p . offset = = BCACHEFS_ROOT_SUBVOL & &
subvol . v - > fs_path_parent ,
2024-02-09 05:10:32 +03:00
trans , subvol_root_fs_path_parent_nonzero ,
2024-02-09 02:39:42 +03:00
" root subvolume has nonzero fs_path_parent \n %s " ,
( bch2_bkey_val_to_text ( & buf , c , k ) , buf . buf ) ) ) {
struct bkey_i_subvolume * n =
bch2_bkey_make_mut_typed ( trans , iter , & subvol . s_c , 0 , subvolume ) ;
ret = PTR_ERR_OR_ZERO ( n ) ;
if ( ret )
goto err ;
n - > v . fs_path_parent = 0 ;
}
2024-01-21 14:00:07 +03:00
if ( subvol . v - > fs_path_parent ) {
struct bpos pos = subvolume_children_pos ( k ) ;
struct bkey_s_c subvol_children_k =
bch2_bkey_get_iter ( trans , & subvol_children_iter ,
BTREE_ID_subvolume_children , pos , 0 ) ;
ret = bkey_err ( subvol_children_k ) ;
if ( ret )
goto err ;
if ( fsck_err_on ( subvol_children_k . k - > type ! = KEY_TYPE_set ,
2024-02-09 05:10:32 +03:00
trans , subvol_children_not_set ,
2024-01-21 14:00:07 +03:00
" subvolume not set in subvolume_children btree at %llu:%llu \n %s " ,
pos . inode , pos . offset ,
( printbuf_reset ( & buf ) ,
bch2_bkey_val_to_text ( & buf , c , k ) , buf . buf ) ) ) {
ret = bch2_btree_bit_mod ( trans , BTREE_ID_subvolume_children , pos , true ) ;
if ( ret )
goto err ;
}
}
2024-02-06 06:20:12 +03:00
struct bch_inode_unpacked inode ;
struct btree_iter inode_iter = { } ;
ret = bch2_inode_peek_nowarn ( trans , & inode_iter , & inode ,
( subvol_inum ) { k . k - > p . offset , le64_to_cpu ( subvol . v - > inode ) } ,
0 ) ;
bch2_trans_iter_exit ( trans , & inode_iter ) ;
if ( ret & & ! bch2_err_matches ( ret , ENOENT ) )
return ret ;
2024-02-09 05:10:32 +03:00
if ( fsck_err_on ( ret ,
trans , subvol_to_missing_root ,
2024-02-06 06:20:12 +03:00
" subvolume %llu points to missing subvolume root %llu:%u " ,
k . k - > p . offset , le64_to_cpu ( subvol . v - > inode ) ,
le32_to_cpu ( subvol . v - > snapshot ) ) ) {
ret = bch2_subvolume_delete ( trans , iter - > pos . offset ) ;
bch_err_msg ( c , ret , " deleting subvolume %llu " , iter - > pos . offset ) ;
return ret ? : - BCH_ERR_transaction_restart_nested ;
}
if ( fsck_err_on ( inode . bi_subvol ! = subvol . k - > p . offset ,
2024-02-09 05:10:32 +03:00
trans , subvol_root_wrong_bi_subvol ,
2024-02-06 06:20:12 +03:00
" subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu " ,
inode . bi_inum , inode_iter . k . p . snapshot ,
inode . bi_subvol , subvol . k - > p . offset ) ) {
inode . bi_subvol = subvol . k - > p . offset ;
ret = __bch2_fsck_write_inode ( trans , & inode , le32_to_cpu ( subvol . v - > snapshot ) ) ;
if ( ret )
goto err ;
}
2023-03-29 18:18:52 +03:00
if ( ! BCH_SUBVOLUME_SNAP ( subvol . v ) ) {
u32 snapshot_root = bch2_snapshot_root ( c , le32_to_cpu ( subvol . v - > snapshot ) ) ;
2023-07-12 20:55:03 +03:00
u32 snapshot_tree ;
2023-03-29 18:18:52 +03:00
struct bch_snapshot_tree st ;
2023-07-12 20:55:03 +03:00
rcu_read_lock ( ) ;
snapshot_tree = snapshot_t ( c , snapshot_root ) - > tree ;
rcu_read_unlock ( ) ;
2023-04-28 10:50:57 +03:00
ret = bch2_snapshot_tree_lookup ( trans , snapshot_tree , & st ) ;
2023-03-29 18:18:52 +03:00
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) , c ,
" %s: snapshot tree %u not found " , __func__ , snapshot_tree ) ;
if ( ret )
return ret ;
2023-10-25 03:44:36 +03:00
if ( fsck_err_on ( le32_to_cpu ( st . master_subvol ) ! = subvol . k - > p . offset ,
2024-02-09 05:10:32 +03:00
trans , subvol_not_master_and_not_snapshot ,
2023-03-29 18:18:52 +03:00
" subvolume %llu is not set as snapshot but is not master subvolume " ,
k . k - > p . offset ) ) {
struct bkey_i_subvolume * s =
2023-06-27 01:36:24 +03:00
bch2_bkey_make_mut_typed ( trans , iter , & subvol . s_c , 0 , subvolume ) ;
2023-03-29 18:18:52 +03:00
ret = PTR_ERR_OR_ZERO ( s ) ;
if ( ret )
return ret ;
SET_BCH_SUBVOLUME_SNAP ( & s - > v , true ) ;
}
}
2024-02-06 06:20:12 +03:00
err :
2023-03-29 18:18:52 +03:00
fsck_err :
2024-01-21 14:00:07 +03:00
bch2_trans_iter_exit ( trans , & subvol_children_iter ) ;
2024-02-09 02:39:42 +03:00
printbuf_exit ( & buf ) ;
2023-03-29 18:18:52 +03:00
return ret ;
2022-07-14 08:10:24 +03:00
}
2023-07-07 09:42:28 +03:00
int bch2_check_subvols ( struct bch_fs * c )
2022-07-14 08:10:24 +03:00
{
2023-12-17 06:30:09 +03:00
int ret = bch2_trans_run ( c ,
2023-09-13 00:16:02 +03:00
for_each_btree_key_commit ( trans , iter ,
2024-04-08 01:05:34 +03:00
BTREE_ID_subvolumes , POS_MIN , BTREE_ITER_prefetch , k ,
2023-12-17 06:43:41 +03:00
NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
check_subvol ( trans , & iter , k ) ) ) ;
bch_err_fn ( c , ret ) ;
2022-07-14 08:10:24 +03:00
return ret ;
}
2024-01-21 14:00:07 +03:00
static int check_subvol_child ( struct btree_trans * trans ,
struct btree_iter * child_iter ,
struct bkey_s_c child_k )
{
struct bch_subvolume s ;
int ret = bch2_bkey_get_val_typed ( trans , BTREE_ID_subvolumes , POS ( 0 , child_k . k - > p . offset ) ,
0 , subvolume , & s ) ;
if ( ret & & ! bch2_err_matches ( ret , ENOENT ) )
return ret ;
if ( fsck_err_on ( ret | |
le32_to_cpu ( s . fs_path_parent ) ! = child_k . k - > p . inode ,
2024-02-09 05:10:32 +03:00
trans , subvol_children_bad ,
2024-01-21 14:00:07 +03:00
" incorrect entry in subvolume_children btree %llu:%llu " ,
child_k . k - > p . inode , child_k . k - > p . offset ) ) {
ret = bch2_btree_delete_at ( trans , child_iter , 0 ) ;
if ( ret )
goto err ;
}
err :
fsck_err :
return ret ;
}
int bch2_check_subvol_children ( struct bch_fs * c )
{
int ret = bch2_trans_run ( c ,
for_each_btree_key_commit ( trans , iter ,
2024-04-08 01:05:34 +03:00
BTREE_ID_subvolume_children , POS_MIN , BTREE_ITER_prefetch , k ,
2024-01-21 14:00:07 +03:00
NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
check_subvol_child ( trans , & iter , k ) ) ) ;
bch_err_fn ( c , ret ) ;
return 0 ;
}
2021-03-16 07:42:25 +03:00
/* Subvolumes: */
2023-10-25 03:44:36 +03:00
int bch2_subvolume_invalid ( struct bch_fs * c , struct bkey_s_c k ,
2024-05-09 01:40:42 +03:00
enum bch_validate_flags flags , struct printbuf * err )
2021-03-16 07:42:25 +03:00
{
2024-05-20 08:11:20 +03:00
struct bkey_s_c_subvolume subvol = bkey_s_c_to_subvolume ( k ) ;
2023-10-25 03:44:36 +03:00
int ret = 0 ;
2021-03-16 07:42:25 +03:00
2023-10-25 03:44:36 +03:00
bkey_fsck_err_on ( bkey_lt ( k . k - > p , SUBVOL_POS_MIN ) | |
bkey_gt ( k . k - > p , SUBVOL_POS_MAX ) , c , err ,
subvol_pos_bad ,
" invalid pos " ) ;
2024-05-20 08:11:20 +03:00
bkey_fsck_err_on ( ! subvol . v - > snapshot , c , err ,
subvol_snapshot_bad ,
" invalid snapshot " ) ;
bkey_fsck_err_on ( ! subvol . v - > inode , c , err ,
subvol_inode_bad ,
" invalid inode " ) ;
2023-10-25 03:44:36 +03:00
fsck_err :
return ret ;
2021-03-16 07:42:25 +03: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-04 05:01:40 +03:00
prt_printf ( out , " root %llu snapshot id %u " ,
2023-03-29 18:18:59 +03:00
le64_to_cpu ( s . v - > inode ) ,
le32_to_cpu ( s . v - > snapshot ) ) ;
2024-02-09 02:39:42 +03:00
if ( bkey_val_bytes ( s . k ) > offsetof ( struct bch_subvolume , creation_parent ) ) {
2024-01-22 23:12:28 +03:00
prt_printf ( out , " creation_parent %u " , le32_to_cpu ( s . v - > creation_parent ) ) ;
2024-02-09 02:39:42 +03:00
prt_printf ( out , " fs_parent %u " , le32_to_cpu ( s . v - > fs_path_parent ) ) ;
}
2021-03-16 07:42:25 +03:00
}
2024-01-21 14:00:07 +03:00
static int subvolume_children_mod ( struct btree_trans * trans , struct bpos pos , bool set )
{
return ! bpos_eq ( pos , POS_MIN )
? bch2_btree_bit_mod ( trans , BTREE_ID_subvolume_children , pos , set )
: 0 ;
}
int bch2_subvolume_trigger ( struct btree_trans * trans ,
enum btree_id btree_id , unsigned level ,
struct bkey_s_c old , struct bkey_s new ,
bcachefs: Fix type of flags parameter for some ->trigger() implementations
When building with clang's -Wincompatible-function-pointer-types-strict
(a warning designed to catch potential kCFI failures at build time),
there are several warnings along the lines of:
fs/bcachefs/bkey_methods.c:118:2: error: incompatible function pointer types initializing 'int (*)(struct btree_trans *, enum btree_id, unsigned int, struct bkey_s_c, struct bkey_s, enum btree_iter_update_trigger_flags)' with an expression of type 'int (struct btree_trans *, enum btree_id, unsigned int, struct bkey_s_c, struct bkey_s, unsigned int)' [-Werror,-Wincompatible-function-pointer-types-strict]
118 | BCH_BKEY_TYPES()
| ^~~~~~~~~~~~~~~~
fs/bcachefs/bcachefs_format.h:394:2: note: expanded from macro 'BCH_BKEY_TYPES'
394 | x(inode, 8) \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
fs/bcachefs/bkey_methods.c:117:41: note: expanded from macro 'x'
117 | #define x(name, nr) [KEY_TYPE_##name] = bch2_bkey_ops_##name,
| ^~~~~~~~~~~~~~~~~~~~
<scratch space>:277:1: note: expanded from here
277 | bch2_bkey_ops_inode
| ^~~~~~~~~~~~~~~~~~~
fs/bcachefs/inode.h:26:13: note: expanded from macro 'bch2_bkey_ops_inode'
26 | .trigger = bch2_trigger_inode, \
| ^~~~~~~~~~~~~~~~~~
There are several functions that did not have their flags parameter
converted to 'enum btree_iter_update_trigger_flags' in the recent
unification, which will cause kCFI failures at runtime because the
types, while ABI compatible (hence no warning from the non-strict
version of this warning), do not match exactly.
Fix up these functions (as well as a few other obvious functions that
should have it, even if there are no warnings currently) to resolve the
warnings and potential kCFI runtime failures.
Fixes: 31e4ef3280c8 ("bcachefs: iter/update/trigger/str_hash flag cleanup")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2024-04-23 21:58:09 +03:00
enum btree_iter_update_trigger_flags flags )
2024-01-21 14:00:07 +03:00
{
2024-04-08 01:05:34 +03:00
if ( flags & BTREE_TRIGGER_transactional ) {
2024-01-21 14:00:07 +03:00
struct bpos children_pos_old = subvolume_children_pos ( old ) ;
struct bpos children_pos_new = subvolume_children_pos ( new . s_c ) ;
if ( ! bpos_eq ( children_pos_old , children_pos_new ) ) {
int ret = subvolume_children_mod ( trans , children_pos_old , false ) ? :
subvolume_children_mod ( trans , children_pos_new , true ) ;
if ( ret )
return ret ;
}
}
return 0 ;
}
2024-02-10 05:01:04 +03:00
int bch2_subvol_has_children ( struct btree_trans * trans , u32 subvol )
{
struct btree_iter iter ;
bch2_trans_iter_init ( trans , & iter , BTREE_ID_subvolume_children , POS ( subvol , 0 ) , 0 ) ;
struct bkey_s_c k = bch2_btree_iter_peek ( & iter ) ;
bch2_trans_iter_exit ( trans , & iter ) ;
return bkey_err ( k ) ? : k . k & & k . k - > p . inode = = subvol
? - BCH_ERR_ENOTEMPTY_subvol_not_empty
: 0 ;
}
2022-11-24 02:22:59 +03: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 07:42:25 +03:00
{
2023-04-30 02:33:09 +03:00
int ret = bch2_bkey_get_val_typed ( trans , BTREE_ID_subvolumes , POS ( 0 , subvol ) ,
iter_flags , subvolume , s ) ;
2023-03-29 18:18:52 +03:00
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) & &
inconsistent_if_not_found ,
2023-04-30 02:33:09 +03:00
trans - > c , " missing subvolume %u " , subvol ) ;
2021-03-16 07:42:25 +03:00
return ret ;
}
2022-11-24 02:22:59 +03: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 ) ;
}
2023-12-30 05:16:32 +03:00
int bch2_subvol_is_ro_trans ( struct btree_trans * trans , u32 subvol )
{
struct bch_subvolume s ;
int ret = bch2_subvolume_get_inlined ( trans , subvol , true , 0 , & s ) ;
if ( ret )
return ret ;
if ( BCH_SUBVOLUME_RO ( & s ) )
return - EROFS ;
return 0 ;
}
int bch2_subvol_is_ro ( struct bch_fs * c , u32 subvol )
{
return bch2_trans_do ( c , NULL , NULL , 0 ,
bch2_subvol_is_ro_trans ( trans , subvol ) ) ;
}
2021-10-27 20:05:56 +03:00
int bch2_snapshot_get_subvol ( struct btree_trans * trans , u32 snapshot ,
struct bch_subvolume * subvol )
{
struct bch_snapshot snap ;
2023-08-16 23:54:33 +03:00
return bch2_snapshot_lookup ( trans , snapshot , & snap ) ? :
2021-10-27 20:05:56 +03:00
bch2_subvolume_get ( trans , le32_to_cpu ( snap . subvol ) , true , 0 , subvol ) ;
}
2023-08-16 23:54:33 +03:00
int bch2_subvolume_get_snapshot ( struct btree_trans * trans , u32 subvolid ,
2021-10-01 02:46:23 +03:00
u32 * snapid )
{
2023-03-29 18:18:59 +03:00
struct btree_iter iter ;
2023-08-16 23:54:33 +03:00
struct bkey_s_c_subvolume subvol ;
2021-10-01 02:46:23 +03:00
int ret ;
2023-08-16 23:54:33 +03:00
subvol = bch2_bkey_get_iter_typed ( trans , & iter ,
BTREE_ID_subvolumes , POS ( 0 , subvolid ) ,
2024-04-08 01:05:34 +03:00
BTREE_ITER_cached | BTREE_ITER_with_updates ,
2023-08-16 23:54:33 +03:00
subvolume ) ;
ret = bkey_err ( subvol ) ;
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) , trans - > c ,
" missing subvolume %u " , subvolid ) ;
2023-03-29 18:18:59 +03:00
if ( likely ( ! ret ) )
2023-08-16 23:54:33 +03:00
* snapid = le32_to_cpu ( subvol . v - > snapshot ) ;
2023-03-29 18:18:59 +03:00
bch2_trans_iter_exit ( trans , & iter ) ;
2021-10-01 02:46:23 +03:00
return ret ;
}
2023-03-29 18:18:59 +03:00
static int bch2_subvolume_reparent ( struct btree_trans * trans ,
struct btree_iter * iter ,
struct bkey_s_c k ,
u32 old_parent , u32 new_parent )
{
struct bkey_i_subvolume * s ;
int ret ;
if ( k . k - > type ! = KEY_TYPE_subvolume )
return 0 ;
2024-01-22 23:12:28 +03:00
if ( bkey_val_bytes ( k . k ) > offsetof ( struct bch_subvolume , creation_parent ) & &
le32_to_cpu ( bkey_s_c_to_subvolume ( k ) . v - > creation_parent ) ! = old_parent )
2023-03-29 18:18:59 +03:00
return 0 ;
2023-06-27 01:36:24 +03:00
s = bch2_bkey_make_mut_typed ( trans , iter , & k , 0 , subvolume ) ;
2023-03-29 18:18:59 +03:00
ret = PTR_ERR_OR_ZERO ( s ) ;
if ( ret )
return ret ;
2024-01-22 23:12:28 +03:00
s - > v . creation_parent = cpu_to_le32 ( new_parent ) ;
2023-03-29 18:18:59 +03:00
return 0 ;
}
/*
2023-08-16 23:54:33 +03:00
* Separate from the snapshot tree in the snapshots btree , we record the tree
* structure of how snapshot subvolumes were created - the parent subvolume of
* each snapshot subvolume .
*
* When a subvolume is deleted , we scan for child subvolumes and reparant them ,
* to avoid dangling references :
2023-03-29 18:18:59 +03:00
*/
static int bch2_subvolumes_reparent ( struct btree_trans * trans , u32 subvolid_to_delete )
{
struct bch_subvolume s ;
return lockrestart_do ( trans ,
bch2_subvolume_get ( trans , subvolid_to_delete , true ,
2024-04-08 01:05:34 +03:00
BTREE_ITER_cached , & s ) ) ? :
2023-03-29 18:18:59 +03:00
for_each_btree_key_commit ( trans , iter ,
2024-04-08 01:05:34 +03:00
BTREE_ID_subvolumes , POS_MIN , BTREE_ITER_prefetch , k ,
2023-11-12 00:31:50 +03:00
NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
2023-03-29 18:18:59 +03:00
bch2_subvolume_reparent ( trans , & iter , k ,
2024-01-22 23:12:28 +03:00
subvolid_to_delete , le32_to_cpu ( s . creation_parent ) ) ) ;
2023-03-29 18:18:59 +03:00
}
2021-10-11 19:03:19 +03:00
/*
* Delete subvolume , mark snapshot ID as deleted , queue up snapshot
* deletion / cleanup :
*/
2023-03-29 18:18:59 +03:00
static int __bch2_subvolume_delete ( struct btree_trans * trans , u32 subvolid )
2021-03-16 07:42:25 +03:00
{
struct btree_iter iter ;
struct bkey_s_c_subvolume subvol ;
u32 snapid ;
int ret = 0 ;
2023-04-30 02:33:09 +03:00
subvol = bch2_bkey_get_iter_typed ( trans , & iter ,
BTREE_ID_subvolumes , POS ( 0 , subvolid ) ,
2024-04-08 01:05:34 +03:00
BTREE_ITER_cached | BTREE_ITER_intent ,
2023-04-30 02:33:09 +03:00
subvolume ) ;
ret = bkey_err ( subvol ) ;
2023-03-29 18:18:52 +03:00
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) , trans - > c ,
" missing subvolume %u " , subvolid ) ;
2021-03-16 07:42:25 +03:00
if ( ret )
2023-04-30 02:33:09 +03:00
return ret ;
2021-03-16 07:42:25 +03:00
snapid = le32_to_cpu ( subvol . v - > snapshot ) ;
2023-10-20 04:25:04 +03:00
ret = bch2_btree_delete_at ( trans , & iter , 0 ) ? :
bch2_snapshot_node_set_deleted ( trans , snapid ) ;
2021-03-16 07:42:25 +03:00
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2023-03-29 18:18:59 +03:00
static int bch2_subvolume_delete ( struct btree_trans * trans , u32 subvolid )
{
return bch2_subvolumes_reparent ( trans , subvolid ) ? :
2023-11-12 00:31:50 +03:00
commit_do ( trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc ,
2023-03-29 18:18:59 +03:00
__bch2_subvolume_delete ( trans , subvolid ) ) ;
}
2023-07-07 05:47:42 +03:00
static void bch2_subvolume_wait_for_pagecache_and_delete ( struct work_struct * work )
2021-10-11 19:03:19 +03:00
{
struct bch_fs * c = container_of ( work , struct bch_fs ,
snapshot_wait_for_pagecache_and_delete_work ) ;
2022-03-29 22:48:45 +03:00
snapshot_id_list s ;
2021-10-11 19:03:19 +03:00
u32 * id ;
int ret = 0 ;
while ( ! ret ) {
mutex_lock ( & c - > snapshots_unlinked_lock ) ;
s = c - > snapshots_unlinked ;
2022-03-29 22:48:45 +03:00
darray_init ( & c - > snapshots_unlinked ) ;
2021-10-11 19:03:19 +03:00
mutex_unlock ( & c - > snapshots_unlinked_lock ) ;
if ( ! s . nr )
break ;
bch2_evict_subvolume_inodes ( c , & s ) ;
2022-03-29 22:48:45 +03:00
for ( id = s . data ; id < s . data + s . nr ; id + + ) {
2023-09-13 00:16:02 +03:00
ret = bch2_trans_run ( c , bch2_subvolume_delete ( trans , * id ) ) ;
2023-12-17 06:43:41 +03:00
bch_err_msg ( c , ret , " deleting subvolume %u " , * id ) ;
if ( ret )
2021-10-11 19:03:19 +03:00
break ;
}
2022-03-29 22:48:45 +03:00
darray_exit ( & s ) ;
2021-10-11 19:03:19 +03:00
}
2023-02-09 20:21:45 +03:00
bch2_write_ref_put ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) ;
2021-10-11 19:03:19 +03:00
}
struct subvolume_unlink_hook {
struct btree_trans_commit_hook h ;
u32 subvol ;
} ;
2023-07-07 05:47:42 +03:00
static int bch2_subvolume_wait_for_pagecache_and_delete_hook ( struct btree_trans * trans ,
2021-10-11 19:03:19 +03:00
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 09:34:48 +03:00
ret = snapshot_list_add ( c , & c - > snapshots_unlinked , h - > subvol ) ;
2021-10-11 19:03:19 +03:00
mutex_unlock ( & c - > snapshots_unlinked_lock ) ;
if ( ret )
return ret ;
2023-02-09 20:21:45 +03:00
if ( ! bch2_write_ref_tryget ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) )
2021-10-11 19:03:19 +03:00
return - EROFS ;
2023-03-23 21:09:05 +03:00
if ( ! queue_work ( c - > write_ref_wq , & c - > snapshot_wait_for_pagecache_and_delete_work ) )
2023-02-09 20:21:45 +03:00
bch2_write_ref_put ( c , BCH_WRITE_REF_snapshot_delete_pagecache ) ;
2021-10-11 19:03:19 +03: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 ;
2023-05-01 01:46:24 +03:00
h = bch2_trans_kmalloc ( trans , sizeof ( * h ) ) ;
ret = PTR_ERR_OR_ZERO ( h ) ;
if ( ret )
return ret ;
h - > h . fn = bch2_subvolume_wait_for_pagecache_and_delete_hook ;
h - > subvol = subvolid ;
bch2_trans_commit_hook ( trans , & h - > h ) ;
2023-04-28 06:48:33 +03:00
n = bch2_bkey_get_mut_typed ( trans , & iter ,
BTREE_ID_subvolumes , POS ( 0 , subvolid ) ,
2024-04-08 01:05:34 +03:00
BTREE_ITER_cached , subvolume ) ;
2021-10-11 19:03:19 +03:00
ret = PTR_ERR_OR_ZERO ( n ) ;
2022-11-24 06:13:19 +03:00
if ( unlikely ( ret ) ) {
2023-03-29 18:18:52 +03:00
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) , trans - > c ,
" missing subvolume %u " , subvolid ) ;
2023-05-01 01:46:24 +03:00
return ret ;
2022-11-24 06:13:19 +03:00
}
2021-10-11 19:03:19 +03:00
SET_BCH_SUBVOLUME_UNLINKED ( & n - > v , true ) ;
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
2021-03-16 07:42:25 +03:00
int bch2_subvolume_create ( struct btree_trans * trans , u64 inode ,
2024-02-09 02:39:42 +03:00
u32 parent_subvolid ,
2021-03-16 07:42:25 +03:00
u32 src_subvolid ,
u32 * new_subvolid ,
u32 * new_snapshotid ,
bool ro )
{
2023-03-29 18:18:59 +03:00
struct bch_fs * c = trans - > c ;
2021-03-16 07:42:25 +03: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 ;
u32 parent = 0 , new_nodes [ 2 ] , snapshot_subvols [ 2 ] ;
int ret = 0 ;
2023-04-28 06:20:18 +03:00
ret = bch2_bkey_get_empty_slot ( trans , & dst_iter ,
BTREE_ID_subvolumes , POS ( 0 , U32_MAX ) ) ;
if ( ret = = - BCH_ERR_ENOSPC_btree_slot )
2022-09-19 00:10:33 +03:00
ret = - BCH_ERR_ENOSPC_subvolume_create ;
2023-04-28 06:20:18 +03:00
if ( ret )
return ret ;
2021-03-16 07:42:25 +03:00
snapshot_subvols [ 0 ] = dst_iter . pos . offset ;
snapshot_subvols [ 1 ] = src_subvolid ;
if ( src_subvolid ) {
/* Creating a snapshot: */
2023-04-28 06:48:33 +03:00
src_subvol = bch2_bkey_get_mut_typed ( trans , & src_iter ,
BTREE_ID_subvolumes , POS ( 0 , src_subvolid ) ,
2024-04-08 01:05:34 +03:00
BTREE_ITER_cached , subvolume ) ;
2022-11-24 06:13:19 +03:00
ret = PTR_ERR_OR_ZERO ( src_subvol ) ;
if ( unlikely ( ret ) ) {
2023-05-28 02:59:59 +03:00
bch2_fs_inconsistent_on ( bch2_err_matches ( ret , ENOENT ) , c ,
2022-11-24 06:13:19 +03:00
" subvolume %u not found " , src_subvolid ) ;
2021-03-16 07:42:25 +03: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 08:30:49 +03:00
ret = bch2_trans_update ( trans , & src_iter , & src_subvol - > k_i , 0 ) ;
if ( ret )
goto err ;
2021-03-16 07:42:25 +03:00
}
2023-05-01 01:59:28 +03:00
new_subvol = bch2_bkey_alloc ( trans , & dst_iter , 0 , subvolume ) ;
2021-03-16 07:42:25 +03:00
ret = PTR_ERR_OR_ZERO ( new_subvol ) ;
if ( ret )
goto err ;
2024-01-22 23:12:28 +03:00
new_subvol - > v . flags = 0 ;
new_subvol - > v . snapshot = cpu_to_le32 ( new_nodes [ 0 ] ) ;
new_subvol - > v . inode = cpu_to_le64 ( inode ) ;
new_subvol - > v . creation_parent = cpu_to_le32 ( src_subvolid ) ;
2024-02-09 02:39:42 +03:00
new_subvol - > v . fs_path_parent = cpu_to_le32 ( parent_subvolid ) ;
2024-01-22 23:12:28 +03:00
new_subvol - > v . otime . lo = cpu_to_le64 ( bch2_current_time ( c ) ) ;
new_subvol - > v . otime . hi = 0 ;
2023-03-29 18:18:59 +03:00
2021-03-16 07:42:25 +03:00
SET_BCH_SUBVOLUME_RO ( & new_subvol - > v , ro ) ;
SET_BCH_SUBVOLUME_SNAP ( & new_subvol - > v , src_subvolid ! = 0 ) ;
* 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 ;
}
2024-03-24 03:07:46 +03:00
int bch2_initialize_subvolumes ( struct bch_fs * c )
{
struct bkey_i_snapshot_tree root_tree ;
struct bkey_i_snapshot root_snapshot ;
struct bkey_i_subvolume root_volume ;
int ret ;
bkey_snapshot_tree_init ( & root_tree . k_i ) ;
root_tree . k . p . offset = 1 ;
root_tree . v . master_subvol = cpu_to_le32 ( 1 ) ;
root_tree . v . root_snapshot = cpu_to_le32 ( U32_MAX ) ;
bkey_snapshot_init ( & root_snapshot . k_i ) ;
root_snapshot . k . p . offset = U32_MAX ;
root_snapshot . v . flags = 0 ;
root_snapshot . v . parent = 0 ;
root_snapshot . v . subvol = cpu_to_le32 ( BCACHEFS_ROOT_SUBVOL ) ;
root_snapshot . v . tree = cpu_to_le32 ( 1 ) ;
SET_BCH_SNAPSHOT_SUBVOL ( & root_snapshot . v , true ) ;
bkey_subvolume_init ( & root_volume . k_i ) ;
root_volume . k . p . offset = BCACHEFS_ROOT_SUBVOL ;
root_volume . v . flags = 0 ;
root_volume . v . snapshot = cpu_to_le32 ( U32_MAX ) ;
root_volume . v . inode = cpu_to_le64 ( BCACHEFS_ROOT_INO ) ;
2024-06-03 23:47:31 +03:00
ret = bch2_btree_insert ( c , BTREE_ID_snapshot_trees , & root_tree . k_i , NULL , 0 , 0 ) ? :
bch2_btree_insert ( c , BTREE_ID_snapshots , & root_snapshot . k_i , NULL , 0 , 0 ) ? :
bch2_btree_insert ( c , BTREE_ID_subvolumes , & root_volume . k_i , NULL , 0 , 0 ) ;
2024-03-24 03:07:46 +03:00
bch_err_fn ( c , ret ) ;
return ret ;
}
static int __bch2_fs_upgrade_for_subvolumes ( struct btree_trans * trans )
{
struct btree_iter iter ;
struct bkey_s_c k ;
struct bch_inode_unpacked inode ;
int ret ;
k = bch2_bkey_get_iter ( trans , & iter , BTREE_ID_inodes ,
SPOS ( 0 , BCACHEFS_ROOT_INO , U32_MAX ) , 0 ) ;
ret = bkey_err ( k ) ;
if ( ret )
return ret ;
if ( ! bkey_is_inode ( k . k ) ) {
bch_err ( trans - > c , " root inode not found " ) ;
ret = - BCH_ERR_ENOENT_inode ;
goto err ;
}
ret = bch2_inode_unpack ( k , & inode ) ;
BUG_ON ( ret ) ;
inode . bi_subvol = BCACHEFS_ROOT_SUBVOL ;
ret = bch2_inode_write ( trans , & iter , & inode ) ;
err :
bch2_trans_iter_exit ( trans , & iter ) ;
return ret ;
}
/* set bi_subvol on root inode */
int bch2_fs_upgrade_for_subvolumes ( struct bch_fs * c )
{
int ret = bch2_trans_do ( c , NULL , NULL , BCH_TRANS_COMMIT_lazy_rw ,
__bch2_fs_upgrade_for_subvolumes ( trans ) ) ;
bch_err_fn ( c , ret ) ;
return ret ;
}
2021-03-16 07:42:25 +03:00
int bch2_fs_subvolumes_init ( struct bch_fs * c )
{
INIT_WORK ( & c - > snapshot_delete_work , bch2_delete_dead_snapshots_work ) ;
2021-10-11 19:03:19 +03: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 07:42:25 +03:00
return 0 ;
}