diff options
author | Josef Bacik <josef@redhat.com> | 2011-04-06 14:53:07 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2011-04-08 13:00:41 -0400 |
commit | 16d299ac7446b5a75c5683a9ae11d7907d444c86 (patch) | |
tree | 95358c2fdd7af672ec68c18fb43e2e90a7cd4551 | |
parent | 1ae399382512b3e4d6c923e53da9e45935577040 (diff) |
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: Josef Bacik <josef@redhat.com>
-rw-r--r-- | fs/btrfs/inode.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2bb76c6157a4..24310c9cb14f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -5445,17 +5445,30 @@ out: | |||
5445 | } | 5445 | } |
5446 | 5446 | ||
5447 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | 5447 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, |
5448 | struct extent_map *em, | ||
5448 | u64 start, u64 len) | 5449 | u64 start, u64 len) |
5449 | { | 5450 | { |
5450 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5451 | struct btrfs_root *root = BTRFS_I(inode)->root; |
5451 | struct btrfs_trans_handle *trans; | 5452 | struct btrfs_trans_handle *trans; |
5452 | struct extent_map *em; | ||
5453 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 5453 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
5454 | struct btrfs_key ins; | 5454 | struct btrfs_key ins; |
5455 | u64 alloc_hint; | 5455 | u64 alloc_hint; |
5456 | int ret; | 5456 | int ret; |
5457 | bool insert = false; | ||
5457 | 5458 | ||
5458 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | 5459 | /* |
5460 | * Ok if the extent map we looked up is a hole and is for the exact | ||
5461 | * range we want, there is no reason to allocate a new one, however if | ||
5462 | * it is not right then we need to free this one and drop the cache for | ||
5463 | * our range. | ||
5464 | */ | ||
5465 | if (em->block_start != EXTENT_MAP_HOLE || em->start != start || | ||
5466 | em->len != len) { | ||
5467 | free_extent_map(em); | ||
5468 | em = NULL; | ||
5469 | insert = true; | ||
5470 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | ||
5471 | } | ||
5459 | 5472 | ||
5460 | trans = btrfs_join_transaction(root, 0); | 5473 | trans = btrfs_join_transaction(root, 0); |
5461 | if (IS_ERR(trans)) | 5474 | if (IS_ERR(trans)) |
@@ -5471,10 +5484,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5471 | goto out; | 5484 | goto out; |
5472 | } | 5485 | } |
5473 | 5486 | ||
5474 | em = alloc_extent_map(GFP_NOFS); | ||
5475 | if (!em) { | 5487 | if (!em) { |
5476 | em = ERR_PTR(-ENOMEM); | 5488 | em = alloc_extent_map(GFP_NOFS); |
5477 | goto out; | 5489 | if (!em) { |
5490 | em = ERR_PTR(-ENOMEM); | ||
5491 | goto out; | ||
5492 | } | ||
5478 | } | 5493 | } |
5479 | 5494 | ||
5480 | em->start = start; | 5495 | em->start = start; |
@@ -5484,9 +5499,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5484 | em->block_start = ins.objectid; | 5499 | em->block_start = ins.objectid; |
5485 | em->block_len = ins.offset; | 5500 | em->block_len = ins.offset; |
5486 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 5501 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
5502 | |||
5503 | /* | ||
5504 | * We need to do this because if we're using the original em we searched | ||
5505 | * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that. | ||
5506 | */ | ||
5507 | em->flags = 0; | ||
5487 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 5508 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
5488 | 5509 | ||
5489 | while (1) { | 5510 | while (insert) { |
5490 | write_lock(&em_tree->lock); | 5511 | write_lock(&em_tree->lock); |
5491 | ret = add_extent_mapping(em_tree, em); | 5512 | ret = add_extent_mapping(em_tree, em); |
5492 | write_unlock(&em_tree->lock); | 5513 | write_unlock(&em_tree->lock); |
@@ -5704,8 +5725,7 @@ must_cow: | |||
5704 | * it above | 5725 | * it above |
5705 | */ | 5726 | */ |
5706 | len = bh_result->b_size; | 5727 | len = bh_result->b_size; |
5707 | free_extent_map(em); | 5728 | em = btrfs_new_extent_direct(inode, em, start, len); |
5708 | em = btrfs_new_extent_direct(inode, start, len); | ||
5709 | if (IS_ERR(em)) | 5729 | if (IS_ERR(em)) |
5710 | return PTR_ERR(em); | 5730 | return PTR_ERR(em); |
5711 | len = min(len, em->len - (start - em->start)); | 5731 | len = min(len, em->len - (start - em->start)); |