Commit 16d299ac authored by Josef Bacik's avatar Josef Bacik

Btrfs: reuse the extent_map we found when calling btrfs_get_extent

In btrfs_get_block_direct we call btrfs_get_extent to lookup the extent for the
range that we are looking for.  If we don't find an extent, btrfs_get_extent
will insert a extent_map for that area and mark it as a hole.  So it does the
job of allocating a new extent map and inserting it into the io tree.  But if
we're creating a new extent we free it up and redo all of that work.  So instead
pass the em to btrfs_new_extent_direct(), and if it will work just allocate the
disk space and set it up properly and bypass the freeing/allocating of a new
extent map and the expensive operation of inserting the thing into the io_tree.
Thanks,
Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
parent 1ae39938
...@@ -5445,17 +5445,30 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag ...@@ -5445,17 +5445,30 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
} }
static struct extent_map *btrfs_new_extent_direct(struct inode *inode, static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
struct extent_map *em,
u64 start, u64 len) u64 start, u64 len)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct extent_map *em;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct btrfs_key ins; struct btrfs_key ins;
u64 alloc_hint; u64 alloc_hint;
int ret; int ret;
bool insert = false;
/*
* Ok if the extent map we looked up is a hole and is for the exact
* range we want, there is no reason to allocate a new one, however if
* it is not right then we need to free this one and drop the cache for
* our range.
*/
if (em->block_start != EXTENT_MAP_HOLE || em->start != start ||
em->len != len) {
free_extent_map(em);
em = NULL;
insert = true;
btrfs_drop_extent_cache(inode, start, start + len - 1, 0); btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
}
trans = btrfs_join_transaction(root, 0); trans = btrfs_join_transaction(root, 0);
if (IS_ERR(trans)) if (IS_ERR(trans))
...@@ -5471,11 +5484,13 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -5471,11 +5484,13 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
goto out; goto out;
} }
if (!em) {
em = alloc_extent_map(GFP_NOFS); em = alloc_extent_map(GFP_NOFS);
if (!em) { if (!em) {
em = ERR_PTR(-ENOMEM); em = ERR_PTR(-ENOMEM);
goto out; goto out;
} }
}
em->start = start; em->start = start;
em->orig_start = em->start; em->orig_start = em->start;
...@@ -5484,9 +5499,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -5484,9 +5499,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
em->block_start = ins.objectid; em->block_start = ins.objectid;
em->block_len = ins.offset; em->block_len = ins.offset;
em->bdev = root->fs_info->fs_devices->latest_bdev; em->bdev = root->fs_info->fs_devices->latest_bdev;
/*
* We need to do this because if we're using the original em we searched
* for, we could have EXTENT_FLAG_VACANCY set, and we don't want that.
*/
em->flags = 0;
set_bit(EXTENT_FLAG_PINNED, &em->flags); set_bit(EXTENT_FLAG_PINNED, &em->flags);
while (1) { while (insert) {
write_lock(&em_tree->lock); write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em); ret = add_extent_mapping(em_tree, em);
write_unlock(&em_tree->lock); write_unlock(&em_tree->lock);
...@@ -5704,8 +5725,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -5704,8 +5725,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
* it above * it above
*/ */
len = bh_result->b_size; len = bh_result->b_size;
free_extent_map(em); em = btrfs_new_extent_direct(inode, em, start, len);
em = btrfs_new_extent_direct(inode, start, len);
if (IS_ERR(em)) if (IS_ERR(em))
return PTR_ERR(em); return PTR_ERR(em);
len = min(len, em->len - (start - em->start)); len = min(len, em->len - (start - em->start));
......
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