Commit 0e6ec385 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

Btrfs: allow clear_extent_dirty() to receive a cached extent state record

We can have a lot freed extents during the life span of transaction, so
the red black tree that keeps track of the ranges of each freed extent
(fs_info->freed_extents[]) can get quite big. When finishing a
transaction commit we find each range, process it (discard the extents,
unpin them) and then remove it from the red black tree.

We can use an extent state record as a cache when searching for a range,
so that when we clean the range we can use the cached extent state we
passed to the search function instead of iterating the red black tree
again. Doing things as fast as possible when finishing a transaction (in
state TRANS_STATE_UNBLOCKED) is convenient as it reduces the time we
block another task that wants to commit the next transaction.

So change clear_extent_dirty() to allow an optional extent state record to
be passed as an argument, which will be passed down to __clear_extent_bit.
Reviewed-by: default avatarNikolay Borisov <nborisov@suse.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent cc5de4e7
...@@ -4365,6 +4365,8 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, ...@@ -4365,6 +4365,8 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
unpin = pinned_extents; unpin = pinned_extents;
again: again:
while (1) { while (1) {
struct extent_state *cached_state = NULL;
/* /*
* The btrfs_finish_extent_commit() may get the same range as * The btrfs_finish_extent_commit() may get the same range as
* ours between find_first_extent_bit and clear_extent_dirty. * ours between find_first_extent_bit and clear_extent_dirty.
...@@ -4373,13 +4375,14 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info, ...@@ -4373,13 +4375,14 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
*/ */
mutex_lock(&fs_info->unused_bg_unpin_mutex); mutex_lock(&fs_info->unused_bg_unpin_mutex);
ret = find_first_extent_bit(unpin, 0, &start, &end, ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, NULL); EXTENT_DIRTY, &cached_state);
if (ret) { if (ret) {
mutex_unlock(&fs_info->unused_bg_unpin_mutex); mutex_unlock(&fs_info->unused_bg_unpin_mutex);
break; break;
} }
clear_extent_dirty(unpin, start, end); clear_extent_dirty(unpin, start, end, &cached_state);
free_extent_state(cached_state);
btrfs_error_unpin_extent_range(fs_info, start, end); btrfs_error_unpin_extent_range(fs_info, start, end);
mutex_unlock(&fs_info->unused_bg_unpin_mutex); mutex_unlock(&fs_info->unused_bg_unpin_mutex);
cond_resched(); cond_resched();
......
...@@ -6662,9 +6662,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) ...@@ -6662,9 +6662,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
unpin = &fs_info->freed_extents[0]; unpin = &fs_info->freed_extents[0];
while (!trans->aborted) { while (!trans->aborted) {
struct extent_state *cached_state = NULL;
mutex_lock(&fs_info->unused_bg_unpin_mutex); mutex_lock(&fs_info->unused_bg_unpin_mutex);
ret = find_first_extent_bit(unpin, 0, &start, &end, ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, NULL); EXTENT_DIRTY, &cached_state);
if (ret) { if (ret) {
mutex_unlock(&fs_info->unused_bg_unpin_mutex); mutex_unlock(&fs_info->unused_bg_unpin_mutex);
break; break;
...@@ -6674,9 +6676,10 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) ...@@ -6674,9 +6676,10 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
ret = btrfs_discard_extent(fs_info, start, ret = btrfs_discard_extent(fs_info, start,
end + 1 - start, NULL); end + 1 - start, NULL);
clear_extent_dirty(unpin, start, end); clear_extent_dirty(unpin, start, end, &cached_state);
unpin_extent_range(fs_info, start, end, true); unpin_extent_range(fs_info, start, end, true);
mutex_unlock(&fs_info->unused_bg_unpin_mutex); mutex_unlock(&fs_info->unused_bg_unpin_mutex);
free_extent_state(cached_state);
cond_resched(); cond_resched();
} }
......
...@@ -329,11 +329,11 @@ static inline int set_extent_dirty(struct extent_io_tree *tree, u64 start, ...@@ -329,11 +329,11 @@ static inline int set_extent_dirty(struct extent_io_tree *tree, u64 start,
} }
static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start, static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start,
u64 end) u64 end, struct extent_state **cached)
{ {
return clear_extent_bit(tree, start, end, return clear_extent_bit(tree, start, end,
EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING, 0, 0, NULL); EXTENT_DO_ACCOUNTING, 0, 0, cached);
} }
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment