@@ -1979,11 +1979,18 @@ static noinline int remove_from_bitmap(struct btrfs_free_space_ctl *ctl,
1979
1979
1980
1980
static u64 add_bytes_to_bitmap (struct btrfs_free_space_ctl * ctl ,
1981
1981
struct btrfs_free_space * info , u64 offset ,
1982
- u64 bytes )
1982
+ u64 bytes , enum btrfs_trim_state trim_state )
1983
1983
{
1984
1984
u64 bytes_to_set = 0 ;
1985
1985
u64 end ;
1986
1986
1987
+ /*
1988
+ * This is a tradeoff to make bitmap trim state minimal. We mark the
1989
+ * whole bitmap untrimmed if at any point we add untrimmed regions.
1990
+ */
1991
+ if (trim_state == BTRFS_TRIM_STATE_UNTRIMMED )
1992
+ info -> trim_state = BTRFS_TRIM_STATE_UNTRIMMED ;
1993
+
1987
1994
end = info -> offset + (u64 )(BITS_PER_BITMAP * ctl -> unit );
1988
1995
1989
1996
bytes_to_set = min (end - offset , bytes );
@@ -2058,10 +2065,12 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
2058
2065
struct btrfs_block_group * block_group = NULL ;
2059
2066
int added = 0 ;
2060
2067
u64 bytes , offset , bytes_added ;
2068
+ enum btrfs_trim_state trim_state ;
2061
2069
int ret ;
2062
2070
2063
2071
bytes = info -> bytes ;
2064
2072
offset = info -> offset ;
2073
+ trim_state = info -> trim_state ;
2065
2074
2066
2075
if (!ctl -> op -> use_bitmap (ctl , info ))
2067
2076
return 0 ;
@@ -2096,8 +2105,8 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
2096
2105
}
2097
2106
2098
2107
if (entry -> offset == offset_to_bitmap (ctl , offset )) {
2099
- bytes_added = add_bytes_to_bitmap (ctl , entry ,
2100
- offset , bytes );
2108
+ bytes_added = add_bytes_to_bitmap (ctl , entry , offset ,
2109
+ bytes , trim_state );
2101
2110
bytes -= bytes_added ;
2102
2111
offset += bytes_added ;
2103
2112
}
@@ -2116,7 +2125,8 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
2116
2125
goto new_bitmap ;
2117
2126
}
2118
2127
2119
- bytes_added = add_bytes_to_bitmap (ctl , bitmap_info , offset , bytes );
2128
+ bytes_added = add_bytes_to_bitmap (ctl , bitmap_info , offset , bytes ,
2129
+ trim_state );
2120
2130
bytes -= bytes_added ;
2121
2131
offset += bytes_added ;
2122
2132
added = 0 ;
@@ -2150,6 +2160,7 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
2150
2160
/* allocate the bitmap */
2151
2161
info -> bitmap = kmem_cache_zalloc (btrfs_free_space_bitmap_cachep ,
2152
2162
GFP_NOFS );
2163
+ info -> trim_state = BTRFS_TRIM_STATE_TRIMMED ;
2153
2164
spin_lock (& ctl -> tree_lock );
2154
2165
if (!info -> bitmap ) {
2155
2166
ret = - ENOMEM ;
@@ -3324,6 +3335,37 @@ static int trim_no_bitmap(struct btrfs_block_group *block_group,
3324
3335
return ret ;
3325
3336
}
3326
3337
3338
+ /*
3339
+ * If we break out of trimming a bitmap prematurely, we should reset the
3340
+ * trimming bit. In a rather contrieved case, it's possible to race here so
3341
+ * reset the state to BTRFS_TRIM_STATE_UNTRIMMED.
3342
+ *
3343
+ * start = start of bitmap
3344
+ * end = near end of bitmap
3345
+ *
3346
+ * Thread 1: Thread 2:
3347
+ * trim_bitmaps(start)
3348
+ * trim_bitmaps(end)
3349
+ * end_trimming_bitmap()
3350
+ * reset_trimming_bitmap()
3351
+ */
3352
+ static void reset_trimming_bitmap (struct btrfs_free_space_ctl * ctl , u64 offset )
3353
+ {
3354
+ struct btrfs_free_space * entry ;
3355
+
3356
+ spin_lock (& ctl -> tree_lock );
3357
+ entry = tree_search_offset (ctl , offset , 1 , 0 );
3358
+ if (entry )
3359
+ entry -> trim_state = BTRFS_TRIM_STATE_UNTRIMMED ;
3360
+ spin_unlock (& ctl -> tree_lock );
3361
+ }
3362
+
3363
+ static void end_trimming_bitmap (struct btrfs_free_space * entry )
3364
+ {
3365
+ if (btrfs_free_space_trimming_bitmap (entry ))
3366
+ entry -> trim_state = BTRFS_TRIM_STATE_TRIMMED ;
3367
+ }
3368
+
3327
3369
static int trim_bitmaps (struct btrfs_block_group * block_group ,
3328
3370
u64 * total_trimmed , u64 start , u64 end , u64 minlen )
3329
3371
{
@@ -3348,16 +3390,33 @@ static int trim_bitmaps(struct btrfs_block_group *block_group,
3348
3390
}
3349
3391
3350
3392
entry = tree_search_offset (ctl , offset , 1 , 0 );
3351
- if (!entry ) {
3393
+ if (!entry || btrfs_free_space_trimmed ( entry ) ) {
3352
3394
spin_unlock (& ctl -> tree_lock );
3353
3395
mutex_unlock (& ctl -> cache_writeout_mutex );
3354
3396
next_bitmap = true;
3355
3397
goto next ;
3356
3398
}
3357
3399
3400
+ /*
3401
+ * Async discard bitmap trimming begins at by setting the start
3402
+ * to be key.objectid and the offset_to_bitmap() aligns to the
3403
+ * start of the bitmap. This lets us know we are fully
3404
+ * scanning the bitmap rather than only some portion of it.
3405
+ */
3406
+ if (start == offset )
3407
+ entry -> trim_state = BTRFS_TRIM_STATE_TRIMMING ;
3408
+
3358
3409
bytes = minlen ;
3359
3410
ret2 = search_bitmap (ctl , entry , & start , & bytes , false);
3360
3411
if (ret2 || start >= end ) {
3412
+ /*
3413
+ * This keeps the invariant that all bytes are trimmed
3414
+ * if BTRFS_TRIM_STATE_TRIMMED is set on a bitmap.
3415
+ */
3416
+ if (ret2 && !minlen )
3417
+ end_trimming_bitmap (entry );
3418
+ else
3419
+ entry -> trim_state = BTRFS_TRIM_STATE_UNTRIMMED ;
3361
3420
spin_unlock (& ctl -> tree_lock );
3362
3421
mutex_unlock (& ctl -> cache_writeout_mutex );
3363
3422
next_bitmap = true;
@@ -3366,6 +3425,7 @@ static int trim_bitmaps(struct btrfs_block_group *block_group,
3366
3425
3367
3426
bytes = min (bytes , end - start );
3368
3427
if (bytes < minlen ) {
3428
+ entry -> trim_state = BTRFS_TRIM_STATE_UNTRIMMED ;
3369
3429
spin_unlock (& ctl -> tree_lock );
3370
3430
mutex_unlock (& ctl -> cache_writeout_mutex );
3371
3431
goto next ;
@@ -3383,18 +3443,21 @@ static int trim_bitmaps(struct btrfs_block_group *block_group,
3383
3443
3384
3444
ret = do_trimming (block_group , total_trimmed , start , bytes ,
3385
3445
start , bytes , & trim_entry );
3386
- if (ret )
3446
+ if (ret ) {
3447
+ reset_trimming_bitmap (ctl , offset );
3387
3448
break ;
3449
+ }
3388
3450
next :
3389
3451
if (next_bitmap ) {
3390
3452
offset += BITS_PER_BITMAP * ctl -> unit ;
3453
+ start = offset ;
3391
3454
} else {
3392
3455
start += bytes ;
3393
- if (start >= offset + BITS_PER_BITMAP * ctl -> unit )
3394
- offset += BITS_PER_BITMAP * ctl -> unit ;
3395
3456
}
3396
3457
3397
3458
if (fatal_signal_pending (current )) {
3459
+ if (start != offset )
3460
+ reset_trimming_bitmap (ctl , offset );
3398
3461
ret = - ERESTARTSYS ;
3399
3462
break ;
3400
3463
}
@@ -3448,7 +3511,9 @@ void btrfs_put_block_group_trimming(struct btrfs_block_group *block_group)
3448
3511
int btrfs_trim_block_group (struct btrfs_block_group * block_group ,
3449
3512
u64 * trimmed , u64 start , u64 end , u64 minlen )
3450
3513
{
3514
+ struct btrfs_free_space_ctl * ctl = block_group -> free_space_ctl ;
3451
3515
int ret ;
3516
+ u64 rem = 0 ;
3452
3517
3453
3518
* trimmed = 0 ;
3454
3519
@@ -3465,6 +3530,10 @@ int btrfs_trim_block_group(struct btrfs_block_group *block_group,
3465
3530
goto out ;
3466
3531
3467
3532
ret = trim_bitmaps (block_group , trimmed , start , end , minlen );
3533
+ div64_u64_rem (end , BITS_PER_BITMAP * ctl -> unit , & rem );
3534
+ /* If we ended in the middle of a bitmap, reset the trimming flag */
3535
+ if (rem )
3536
+ reset_trimming_bitmap (ctl , offset_to_bitmap (ctl , end ));
3468
3537
out :
3469
3538
btrfs_put_block_group_trimming (block_group );
3470
3539
return ret ;
@@ -3649,6 +3718,7 @@ int test_add_free_space_entry(struct btrfs_block_group *cache,
3649
3718
struct btrfs_free_space_ctl * ctl = cache -> free_space_ctl ;
3650
3719
struct btrfs_free_space * info = NULL , * bitmap_info ;
3651
3720
void * map = NULL ;
3721
+ enum btrfs_trim_state trim_state = BTRFS_TRIM_STATE_TRIMMED ;
3652
3722
u64 bytes_added ;
3653
3723
int ret ;
3654
3724
@@ -3690,7 +3760,8 @@ int test_add_free_space_entry(struct btrfs_block_group *cache,
3690
3760
info = NULL ;
3691
3761
}
3692
3762
3693
- bytes_added = add_bytes_to_bitmap (ctl , bitmap_info , offset , bytes );
3763
+ bytes_added = add_bytes_to_bitmap (ctl , bitmap_info , offset , bytes ,
3764
+ trim_state );
3694
3765
3695
3766
bytes -= bytes_added ;
3696
3767
offset += bytes_added ;
0 commit comments