@@ -2766,6 +2766,20 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
2766
2766
root = root -> fs_info -> chunk_root ;
2767
2767
extent_root = root -> fs_info -> extent_root ;
2768
2768
2769
+ /*
2770
+ * Prevent races with automatic removal of unused block groups.
2771
+ * After we relocate and before we remove the chunk with offset
2772
+ * chunk_offset, automatic removal of the block group can kick in,
2773
+ * resulting in a failure when calling btrfs_remove_chunk() below.
2774
+ *
2775
+ * Make sure to acquire this mutex before doing a tree search (dev
2776
+ * or chunk trees) to find chunks. Otherwise the cleaner kthread might
2777
+ * call btrfs_remove_chunk() (through btrfs_delete_unused_bgs()) after
2778
+ * we release the path used to search the chunk/dev tree and before
2779
+ * the current task acquires this mutex and calls us.
2780
+ */
2781
+ ASSERT (mutex_is_locked (& root -> fs_info -> delete_unused_bgs_mutex ));
2782
+
2769
2783
ret = btrfs_can_relocate (extent_root , chunk_offset );
2770
2784
if (ret )
2771
2785
return - ENOSPC ;
@@ -2814,13 +2828,18 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
2814
2828
key .type = BTRFS_CHUNK_ITEM_KEY ;
2815
2829
2816
2830
while (1 ) {
2831
+ mutex_lock (& root -> fs_info -> delete_unused_bgs_mutex );
2817
2832
ret = btrfs_search_slot (NULL , chunk_root , & key , path , 0 , 0 );
2818
- if (ret < 0 )
2833
+ if (ret < 0 ) {
2834
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
2819
2835
goto error ;
2836
+ }
2820
2837
BUG_ON (ret == 0 ); /* Corruption */
2821
2838
2822
2839
ret = btrfs_previous_item (chunk_root , path , key .objectid ,
2823
2840
key .type );
2841
+ if (ret )
2842
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
2824
2843
if (ret < 0 )
2825
2844
goto error ;
2826
2845
if (ret > 0 )
@@ -2843,6 +2862,7 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
2843
2862
else
2844
2863
BUG_ON (ret );
2845
2864
}
2865
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
2846
2866
2847
2867
if (found_key .offset == 0 )
2848
2868
break ;
@@ -3299,9 +3319,12 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3299
3319
goto error ;
3300
3320
}
3301
3321
3322
+ mutex_lock (& fs_info -> delete_unused_bgs_mutex );
3302
3323
ret = btrfs_search_slot (NULL , chunk_root , & key , path , 0 , 0 );
3303
- if (ret < 0 )
3324
+ if (ret < 0 ) {
3325
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3304
3326
goto error ;
3327
+ }
3305
3328
3306
3329
/*
3307
3330
* this shouldn't happen, it means the last relocate
@@ -3313,6 +3336,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3313
3336
ret = btrfs_previous_item (chunk_root , path , 0 ,
3314
3337
BTRFS_CHUNK_ITEM_KEY );
3315
3338
if (ret ) {
3339
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3316
3340
ret = 0 ;
3317
3341
break ;
3318
3342
}
@@ -3321,8 +3345,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3321
3345
slot = path -> slots [0 ];
3322
3346
btrfs_item_key_to_cpu (leaf , & found_key , slot );
3323
3347
3324
- if (found_key .objectid != key .objectid )
3348
+ if (found_key .objectid != key .objectid ) {
3349
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3325
3350
break ;
3351
+ }
3326
3352
3327
3353
chunk = btrfs_item_ptr (leaf , slot , struct btrfs_chunk );
3328
3354
@@ -3335,10 +3361,13 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3335
3361
ret = should_balance_chunk (chunk_root , leaf , chunk ,
3336
3362
found_key .offset );
3337
3363
btrfs_release_path (path );
3338
- if (!ret )
3364
+ if (!ret ) {
3365
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3339
3366
goto loop ;
3367
+ }
3340
3368
3341
3369
if (counting ) {
3370
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3342
3371
spin_lock (& fs_info -> balance_lock );
3343
3372
bctl -> stat .expected ++ ;
3344
3373
spin_unlock (& fs_info -> balance_lock );
@@ -3348,6 +3377,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3348
3377
ret = btrfs_relocate_chunk (chunk_root ,
3349
3378
found_key .objectid ,
3350
3379
found_key .offset );
3380
+ mutex_unlock (& fs_info -> delete_unused_bgs_mutex );
3351
3381
if (ret && ret != - ENOSPC )
3352
3382
goto error ;
3353
3383
if (ret == - ENOSPC ) {
@@ -4087,11 +4117,16 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
4087
4117
key .type = BTRFS_DEV_EXTENT_KEY ;
4088
4118
4089
4119
do {
4120
+ mutex_lock (& root -> fs_info -> delete_unused_bgs_mutex );
4090
4121
ret = btrfs_search_slot (NULL , root , & key , path , 0 , 0 );
4091
- if (ret < 0 )
4122
+ if (ret < 0 ) {
4123
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
4092
4124
goto done ;
4125
+ }
4093
4126
4094
4127
ret = btrfs_previous_item (root , path , 0 , key .type );
4128
+ if (ret )
4129
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
4095
4130
if (ret < 0 )
4096
4131
goto done ;
4097
4132
if (ret ) {
@@ -4105,6 +4140,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
4105
4140
btrfs_item_key_to_cpu (l , & key , path -> slots [0 ]);
4106
4141
4107
4142
if (key .objectid != device -> devid ) {
4143
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
4108
4144
btrfs_release_path (path );
4109
4145
break ;
4110
4146
}
@@ -4113,6 +4149,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
4113
4149
length = btrfs_dev_extent_length (l , dev_extent );
4114
4150
4115
4151
if (key .offset + length <= new_size ) {
4152
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
4116
4153
btrfs_release_path (path );
4117
4154
break ;
4118
4155
}
@@ -4122,6 +4159,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
4122
4159
btrfs_release_path (path );
4123
4160
4124
4161
ret = btrfs_relocate_chunk (root , chunk_objectid , chunk_offset );
4162
+ mutex_unlock (& root -> fs_info -> delete_unused_bgs_mutex );
4125
4163
if (ret && ret != - ENOSPC )
4126
4164
goto done ;
4127
4165
if (ret == - ENOSPC )
0 commit comments