Skip to content

Commit a7ccb25

Browse files
dennisszhoukdave
authored andcommitted
btrfs: keep track of which extents have been discarded
Async discard will use the free space cache as backing knowledge for which extents to discard. This patch plumbs knowledge about which extents need to be discarded into the free space cache from unpin_extent_range(). An untrimmed extent can merge with everything as this is a new region. Absorbing trimmed extents is a tradeoff to for greater coalescing which makes life better for find_free_extent(). Additionally, it seems the size of a trim isn't as problematic as the trim io itself. When reading in the free space cache from disk, if sync is set, mark all extents as trimmed. The current code ensures at transaction commit that all free space is trimmed when sync is set, so this reflects that. Signed-off-by: Dennis Zhou <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 46b27f5 commit a7ccb25

File tree

3 files changed

+79
-14
lines changed

3 files changed

+79
-14
lines changed

fs/btrfs/free-space-cache.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,14 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
752752
goto free_cache;
753753
}
754754

755+
/*
756+
* Sync discard ensures that the free space cache is always
757+
* trimmed. So when reading this in, the state should reflect
758+
* that.
759+
*/
760+
if (btrfs_test_opt(fs_info, DISCARD_SYNC))
761+
e->trim_state = BTRFS_TRIM_STATE_TRIMMED;
762+
755763
if (!e->bytes) {
756764
kmem_cache_free(btrfs_free_space_cachep, e);
757765
goto free_cache;
@@ -2161,6 +2169,22 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl,
21612169
return ret;
21622170
}
21632171

2172+
/*
2173+
* Free space merging rules:
2174+
* 1) Merge trimmed areas together
2175+
* 2) Let untrimmed areas coalesce with trimmed areas
2176+
* 3) Always pull neighboring regions from bitmaps
2177+
*
2178+
* The above rules are for when we merge free space based on btrfs_trim_state.
2179+
* Rules 2 and 3 are subtle because they are suboptimal, but are done for the
2180+
* same reason: to promote larger extent regions which makes life easier for
2181+
* find_free_extent(). Rule 2 enables coalescing based on the common path
2182+
* being returning free space from btrfs_finish_extent_commit(). So when free
2183+
* space is trimmed, it will prevent aggregating trimmed new region and
2184+
* untrimmed regions in the rb_tree. Rule 3 is purely to obtain larger extents
2185+
* and provide find_free_extent() with the largest extents possible hoping for
2186+
* the reuse path.
2187+
*/
21642188
static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
21652189
struct btrfs_free_space *info, bool update_stat)
21662190
{
@@ -2169,6 +2193,7 @@ static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
21692193
bool merged = false;
21702194
u64 offset = info->offset;
21712195
u64 bytes = info->bytes;
2196+
const bool is_trimmed = btrfs_free_space_trimmed(info);
21722197

21732198
/*
21742199
* first we want to see if there is free space adjacent to the range we
@@ -2182,7 +2207,9 @@ static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
21822207
else
21832208
left_info = tree_search_offset(ctl, offset - 1, 0, 0);
21842209

2185-
if (right_info && !right_info->bitmap) {
2210+
/* See try_merge_free_space() comment. */
2211+
if (right_info && !right_info->bitmap &&
2212+
(!is_trimmed || btrfs_free_space_trimmed(right_info))) {
21862213
if (update_stat)
21872214
unlink_free_space(ctl, right_info);
21882215
else
@@ -2192,8 +2219,10 @@ static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl,
21922219
merged = true;
21932220
}
21942221

2222+
/* See try_merge_free_space() comment. */
21952223
if (left_info && !left_info->bitmap &&
2196-
left_info->offset + left_info->bytes == offset) {
2224+
left_info->offset + left_info->bytes == offset &&
2225+
(!is_trimmed || btrfs_free_space_trimmed(left_info))) {
21972226
if (update_stat)
21982227
unlink_free_space(ctl, left_info);
21992228
else
@@ -2229,6 +2258,10 @@ static bool steal_from_bitmap_to_end(struct btrfs_free_space_ctl *ctl,
22292258
bytes = (j - i) * ctl->unit;
22302259
info->bytes += bytes;
22312260

2261+
/* See try_merge_free_space() comment. */
2262+
if (!btrfs_free_space_trimmed(bitmap))
2263+
info->trim_state = BTRFS_TRIM_STATE_UNTRIMMED;
2264+
22322265
if (update_stat)
22332266
bitmap_clear_bits(ctl, bitmap, end, bytes);
22342267
else
@@ -2282,6 +2315,10 @@ static bool steal_from_bitmap_to_front(struct btrfs_free_space_ctl *ctl,
22822315
info->offset -= bytes;
22832316
info->bytes += bytes;
22842317

2318+
/* See try_merge_free_space() comment. */
2319+
if (!btrfs_free_space_trimmed(bitmap))
2320+
info->trim_state = BTRFS_TRIM_STATE_UNTRIMMED;
2321+
22852322
if (update_stat)
22862323
bitmap_clear_bits(ctl, bitmap, info->offset, bytes);
22872324
else
@@ -2331,7 +2368,8 @@ static void steal_from_bitmap(struct btrfs_free_space_ctl *ctl,
23312368

23322369
int __btrfs_add_free_space(struct btrfs_fs_info *fs_info,
23332370
struct btrfs_free_space_ctl *ctl,
2334-
u64 offset, u64 bytes)
2371+
u64 offset, u64 bytes,
2372+
enum btrfs_trim_state trim_state)
23352373
{
23362374
struct btrfs_free_space *info;
23372375
int ret = 0;
@@ -2342,6 +2380,7 @@ int __btrfs_add_free_space(struct btrfs_fs_info *fs_info,
23422380

23432381
info->offset = offset;
23442382
info->bytes = bytes;
2383+
info->trim_state = trim_state;
23452384
RB_CLEAR_NODE(&info->offset_index);
23462385

23472386
spin_lock(&ctl->tree_lock);
@@ -2387,9 +2426,14 @@ int __btrfs_add_free_space(struct btrfs_fs_info *fs_info,
23872426
int btrfs_add_free_space(struct btrfs_block_group *block_group,
23882427
u64 bytenr, u64 size)
23892428
{
2429+
enum btrfs_trim_state trim_state = BTRFS_TRIM_STATE_UNTRIMMED;
2430+
2431+
if (btrfs_test_opt(block_group->fs_info, DISCARD_SYNC))
2432+
trim_state = BTRFS_TRIM_STATE_TRIMMED;
2433+
23902434
return __btrfs_add_free_space(block_group->fs_info,
23912435
block_group->free_space_ctl,
2392-
bytenr, size);
2436+
bytenr, size, trim_state);
23932437
}
23942438

23952439
int btrfs_remove_free_space(struct btrfs_block_group *block_group,
@@ -2464,8 +2508,10 @@ int btrfs_remove_free_space(struct btrfs_block_group *block_group,
24642508
}
24652509
spin_unlock(&ctl->tree_lock);
24662510

2467-
ret = btrfs_add_free_space(block_group, offset + bytes,
2468-
old_end - (offset + bytes));
2511+
ret = __btrfs_add_free_space(block_group->fs_info, ctl,
2512+
offset + bytes,
2513+
old_end - (offset + bytes),
2514+
info->trim_state);
24692515
WARN_ON(ret);
24702516
goto out;
24712517
}
@@ -2634,6 +2680,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
26342680
u64 ret = 0;
26352681
u64 align_gap = 0;
26362682
u64 align_gap_len = 0;
2683+
enum btrfs_trim_state align_gap_trim_state = BTRFS_TRIM_STATE_UNTRIMMED;
26372684

26382685
spin_lock(&ctl->tree_lock);
26392686
entry = find_free_space(ctl, &offset, &bytes_search,
@@ -2650,6 +2697,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
26502697
unlink_free_space(ctl, entry);
26512698
align_gap_len = offset - entry->offset;
26522699
align_gap = entry->offset;
2700+
align_gap_trim_state = entry->trim_state;
26532701

26542702
entry->offset = offset + bytes;
26552703
WARN_ON(entry->bytes < bytes + align_gap_len);
@@ -2665,7 +2713,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group *block_group,
26652713

26662714
if (align_gap_len)
26672715
__btrfs_add_free_space(block_group->fs_info, ctl,
2668-
align_gap, align_gap_len);
2716+
align_gap, align_gap_len,
2717+
align_gap_trim_state);
26692718
return ret;
26702719
}
26712720

fs/btrfs/free-space-cache.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,29 @@
66
#ifndef BTRFS_FREE_SPACE_CACHE_H
77
#define BTRFS_FREE_SPACE_CACHE_H
88

9+
/*
10+
* This is the trim state of an extent or bitmap.
11+
*/
12+
enum btrfs_trim_state {
13+
BTRFS_TRIM_STATE_UNTRIMMED,
14+
BTRFS_TRIM_STATE_TRIMMED,
15+
};
16+
917
struct btrfs_free_space {
1018
struct rb_node offset_index;
1119
u64 offset;
1220
u64 bytes;
1321
u64 max_extent_size;
1422
unsigned long *bitmap;
1523
struct list_head list;
24+
enum btrfs_trim_state trim_state;
1625
};
1726

27+
static inline bool btrfs_free_space_trimmed(struct btrfs_free_space *info)
28+
{
29+
return (info->trim_state == BTRFS_TRIM_STATE_TRIMMED);
30+
}
31+
1832
struct btrfs_free_space_ctl {
1933
spinlock_t tree_lock;
2034
struct rb_root free_space_offset;
@@ -83,7 +97,8 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
8397
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group);
8498
int __btrfs_add_free_space(struct btrfs_fs_info *fs_info,
8599
struct btrfs_free_space_ctl *ctl,
86-
u64 bytenr, u64 size);
100+
u64 bytenr, u64 size,
101+
enum btrfs_trim_state trim_state);
87102
int btrfs_add_free_space(struct btrfs_block_group *block_group,
88103
u64 bytenr, u64 size);
89104
int btrfs_remove_free_space(struct btrfs_block_group *block_group,

fs/btrfs/inode-map.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ static int caching_kthread(void *data)
107107

108108
if (last != (u64)-1 && last + 1 != key.objectid) {
109109
__btrfs_add_free_space(fs_info, ctl, last + 1,
110-
key.objectid - last - 1);
110+
key.objectid - last - 1, 0);
111111
wake_up(&root->ino_cache_wait);
112112
}
113113

@@ -118,7 +118,7 @@ static int caching_kthread(void *data)
118118

119119
if (last < root->highest_objectid - 1) {
120120
__btrfs_add_free_space(fs_info, ctl, last + 1,
121-
root->highest_objectid - last - 1);
121+
root->highest_objectid - last - 1, 0);
122122
}
123123

124124
spin_lock(&root->ino_cache_lock);
@@ -175,7 +175,8 @@ static void start_caching(struct btrfs_root *root)
175175
ret = btrfs_find_free_objectid(root, &objectid);
176176
if (!ret && objectid <= BTRFS_LAST_FREE_OBJECTID) {
177177
__btrfs_add_free_space(fs_info, ctl, objectid,
178-
BTRFS_LAST_FREE_OBJECTID - objectid + 1);
178+
BTRFS_LAST_FREE_OBJECTID - objectid + 1,
179+
0);
179180
wake_up(&root->ino_cache_wait);
180181
}
181182

@@ -221,7 +222,7 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
221222
return;
222223
again:
223224
if (root->ino_cache_state == BTRFS_CACHE_FINISHED) {
224-
__btrfs_add_free_space(fs_info, pinned, objectid, 1);
225+
__btrfs_add_free_space(fs_info, pinned, objectid, 1, 0);
225226
} else {
226227
down_write(&fs_info->commit_root_sem);
227228
spin_lock(&root->ino_cache_lock);
@@ -234,7 +235,7 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
234235

235236
start_caching(root);
236237

237-
__btrfs_add_free_space(fs_info, pinned, objectid, 1);
238+
__btrfs_add_free_space(fs_info, pinned, objectid, 1, 0);
238239

239240
up_write(&fs_info->commit_root_sem);
240241
}
@@ -281,7 +282,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
281282
spin_unlock(rbroot_lock);
282283
if (count)
283284
__btrfs_add_free_space(root->fs_info, ctl,
284-
info->offset, count);
285+
info->offset, count, 0);
285286
kmem_cache_free(btrfs_free_space_cachep, info);
286287
}
287288
}

0 commit comments

Comments
 (0)