Commit 6219872d authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason

Btrfs: lookup for block group only if needed when freeing a tree block

Very often our extent buffer's header generation doesn't match the current
transaction's id or it is also referenced by other trees (snapshots), so
we don't need the corresponding block group cache object. Therefore only
search for it if we are going to use it, so we avoid an unnecessary search
in the block groups rbtree (and acquiring and releasing its spinlock).

Freeing a tree block is performed when COWing or deleting a node/leaf,
which implies we are holding the node/leaf's parent node lock, therefore
reducing the amount of time spent when freeing a tree block helps reducing
the amount of time we are holding the parent node's lock.

For example, for a run of xfstests/generic/083, the block group cache
object was needed only 682 times for a total of 226691 calls to free
a tree block.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 730a78c7
...@@ -6136,7 +6136,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -6136,7 +6136,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
struct extent_buffer *buf, struct extent_buffer *buf,
u64 parent, int last_ref) u64 parent, int last_ref)
{ {
struct btrfs_block_group_cache *cache = NULL;
int pin = 1; int pin = 1;
int ret; int ret;
...@@ -6152,17 +6151,20 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -6152,17 +6151,20 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
if (!last_ref) if (!last_ref)
return; return;
cache = btrfs_lookup_block_group(root->fs_info, buf->start);
if (btrfs_header_generation(buf) == trans->transid) { if (btrfs_header_generation(buf) == trans->transid) {
struct btrfs_block_group_cache *cache;
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
ret = check_ref_cleanup(trans, root, buf->start); ret = check_ref_cleanup(trans, root, buf->start);
if (!ret) if (!ret)
goto out; goto out;
} }
cache = btrfs_lookup_block_group(root->fs_info, buf->start);
if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
pin_down_extent(root, cache, buf->start, buf->len, 1); pin_down_extent(root, cache, buf->start, buf->len, 1);
btrfs_put_block_group(cache);
goto out; goto out;
} }
...@@ -6170,6 +6172,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -6170,6 +6172,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
btrfs_add_free_space(cache, buf->start, buf->len); btrfs_add_free_space(cache, buf->start, buf->len);
btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE, 0); btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE, 0);
btrfs_put_block_group(cache);
trace_btrfs_reserved_extent_free(root, buf->start, buf->len); trace_btrfs_reserved_extent_free(root, buf->start, buf->len);
pin = 0; pin = 0;
} }
...@@ -6184,7 +6187,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -6184,7 +6187,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
* anymore. * anymore.
*/ */
clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags); clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags);
btrfs_put_block_group(cache);
} }
/* Can return -ENOMEM */ /* Can return -ENOMEM */
......
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