diff options
-rw-r--r-- | fs/btrfs/extent_map.c | 48 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 10 |
3 files changed, 59 insertions, 1 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 5bc7a0d325e7..2c726b7b9faa 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -367,6 +367,54 @@ out: | |||
367 | } | 367 | } |
368 | 368 | ||
369 | /** | 369 | /** |
370 | * search_extent_mapping - find a nearby extent map | ||
371 | * @tree: tree to lookup in | ||
372 | * @start: byte offset to start the search | ||
373 | * @len: length of the lookup range | ||
374 | * | ||
375 | * Find and return the first extent_map struct in @tree that intersects the | ||
376 | * [start, len] range. | ||
377 | * | ||
378 | * If one can't be found, any nearby extent may be returned | ||
379 | */ | ||
380 | struct extent_map *search_extent_mapping(struct extent_map_tree *tree, | ||
381 | u64 start, u64 len) | ||
382 | { | ||
383 | struct extent_map *em; | ||
384 | struct rb_node *rb_node; | ||
385 | struct rb_node *prev = NULL; | ||
386 | struct rb_node *next = NULL; | ||
387 | |||
388 | rb_node = __tree_search(&tree->map, start, &prev, &next); | ||
389 | if (!rb_node && prev) { | ||
390 | em = rb_entry(prev, struct extent_map, rb_node); | ||
391 | goto found; | ||
392 | } | ||
393 | if (!rb_node && next) { | ||
394 | em = rb_entry(next, struct extent_map, rb_node); | ||
395 | goto found; | ||
396 | } | ||
397 | if (!rb_node) { | ||
398 | em = NULL; | ||
399 | goto out; | ||
400 | } | ||
401 | if (IS_ERR(rb_node)) { | ||
402 | em = ERR_PTR(PTR_ERR(rb_node)); | ||
403 | goto out; | ||
404 | } | ||
405 | em = rb_entry(rb_node, struct extent_map, rb_node); | ||
406 | goto found; | ||
407 | |||
408 | em = NULL; | ||
409 | goto out; | ||
410 | |||
411 | found: | ||
412 | atomic_inc(&em->refs); | ||
413 | out: | ||
414 | return em; | ||
415 | } | ||
416 | |||
417 | /** | ||
370 | * remove_extent_mapping - removes an extent_map from the extent tree | 418 | * remove_extent_mapping - removes an extent_map from the extent tree |
371 | * @tree: extent tree to remove from | 419 | * @tree: extent tree to remove from |
372 | * @em: extent map beeing removed | 420 | * @em: extent map beeing removed |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index d3d442f4bbbd..ab6d74b6e647 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -60,4 +60,6 @@ void free_extent_map(struct extent_map *em); | |||
60 | int __init extent_map_init(void); | 60 | int __init extent_map_init(void); |
61 | void extent_map_exit(void); | 61 | void extent_map_exit(void); |
62 | int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len); | 62 | int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len); |
63 | struct extent_map *search_extent_mapping(struct extent_map_tree *tree, | ||
64 | u64 start, u64 len); | ||
63 | #endif | 65 | #endif |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 941f1b71cd22..81ba6654c332 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -726,6 +726,15 @@ static noinline int cow_file_range(struct inode *inode, | |||
726 | BUG_ON(disk_num_bytes > | 726 | BUG_ON(disk_num_bytes > |
727 | btrfs_super_total_bytes(&root->fs_info->super_copy)); | 727 | btrfs_super_total_bytes(&root->fs_info->super_copy)); |
728 | 728 | ||
729 | |||
730 | read_lock(&BTRFS_I(inode)->extent_tree.lock); | ||
731 | em = search_extent_mapping(&BTRFS_I(inode)->extent_tree, | ||
732 | start, num_bytes); | ||
733 | if (em) { | ||
734 | alloc_hint = em->block_start; | ||
735 | free_extent_map(em); | ||
736 | } | ||
737 | read_unlock(&BTRFS_I(inode)->extent_tree.lock); | ||
729 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); | 738 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); |
730 | 739 | ||
731 | while (disk_num_bytes > 0) { | 740 | while (disk_num_bytes > 0) { |
@@ -738,7 +747,6 @@ static noinline int cow_file_range(struct inode *inode, | |||
738 | em = alloc_extent_map(GFP_NOFS); | 747 | em = alloc_extent_map(GFP_NOFS); |
739 | em->start = start; | 748 | em->start = start; |
740 | em->orig_start = em->start; | 749 | em->orig_start = em->start; |
741 | |||
742 | ram_size = ins.offset; | 750 | ram_size = ins.offset; |
743 | em->len = ins.offset; | 751 | em->len = ins.offset; |
744 | 752 | ||