aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent_map.c48
-rw-r--r--fs/btrfs/extent_map.h2
-rw-r--r--fs/btrfs/inode.c10
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 */
380struct 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
411found:
412 atomic_inc(&em->refs);
413out:
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);
60int __init extent_map_init(void); 60int __init extent_map_init(void);
61void extent_map_exit(void); 61void extent_map_exit(void);
62int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len); 62int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len);
63struct 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