aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2015-01-06 15:18:45 -0500
committerChris Mason <clm@fb.com>2015-01-21 21:02:04 -0500
commit6219872dc6e56529159f04e73587ed0fcd63eb20 (patch)
tree4129c11c168f2ed78e945d72f9017ee6a3d81e32 /fs
parent730a78c741df4eaa24589015191f03c2d1240091 (diff)
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: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1c591d6eae58..3af53f8313af 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6136,7 +6136,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
6136 struct extent_buffer *buf, 6136 struct extent_buffer *buf,
6137 u64 parent, int last_ref) 6137 u64 parent, int last_ref)
6138{ 6138{
6139 struct btrfs_block_group_cache *cache = NULL;
6140 int pin = 1; 6139 int pin = 1;
6141 int ret; 6140 int ret;
6142 6141
@@ -6152,17 +6151,20 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
6152 if (!last_ref) 6151 if (!last_ref)
6153 return; 6152 return;
6154 6153
6155 cache = btrfs_lookup_block_group(root->fs_info, buf->start);
6156
6157 if (btrfs_header_generation(buf) == trans->transid) { 6154 if (btrfs_header_generation(buf) == trans->transid) {
6155 struct btrfs_block_group_cache *cache;
6156
6158 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { 6157 if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
6159 ret = check_ref_cleanup(trans, root, buf->start); 6158 ret = check_ref_cleanup(trans, root, buf->start);
6160 if (!ret) 6159 if (!ret)
6161 goto out; 6160 goto out;
6162 } 6161 }
6163 6162
6163 cache = btrfs_lookup_block_group(root->fs_info, buf->start);
6164
6164 if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { 6165 if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
6165 pin_down_extent(root, cache, buf->start, buf->len, 1); 6166 pin_down_extent(root, cache, buf->start, buf->len, 1);
6167 btrfs_put_block_group(cache);
6166 goto out; 6168 goto out;
6167 } 6169 }
6168 6170
@@ -6170,6 +6172,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
6170 6172
6171 btrfs_add_free_space(cache, buf->start, buf->len); 6173 btrfs_add_free_space(cache, buf->start, buf->len);
6172 btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE, 0); 6174 btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE, 0);
6175 btrfs_put_block_group(cache);
6173 trace_btrfs_reserved_extent_free(root, buf->start, buf->len); 6176 trace_btrfs_reserved_extent_free(root, buf->start, buf->len);
6174 pin = 0; 6177 pin = 0;
6175 } 6178 }
@@ -6184,7 +6187,6 @@ out:
6184 * anymore. 6187 * anymore.
6185 */ 6188 */
6186 clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags); 6189 clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags);
6187 btrfs_put_block_group(cache);
6188} 6190}
6189 6191
6190/* Can return -ENOMEM */ 6192/* Can return -ENOMEM */