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 5bc7a0d325e..2c726b7b9fa 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -367,6 +367,54 @@ out:  }  /** + * search_extent_mapping - find a nearby extent map + * @tree:	tree to lookup in + * @start:	byte offset to start the search + * @len:	length of the lookup range + * + * Find and return the first extent_map struct in @tree that intersects the + * [start, len] range. + * + * If one can't be found, any nearby extent may be returned + */ +struct extent_map *search_extent_mapping(struct extent_map_tree *tree, +					 u64 start, u64 len) +{ +	struct extent_map *em; +	struct rb_node *rb_node; +	struct rb_node *prev = NULL; +	struct rb_node *next = NULL; + +	rb_node = __tree_search(&tree->map, start, &prev, &next); +	if (!rb_node && prev) { +		em = rb_entry(prev, struct extent_map, rb_node); +		goto found; +	} +	if (!rb_node && next) { +		em = rb_entry(next, struct extent_map, rb_node); +		goto found; +	} +	if (!rb_node) { +		em = NULL; +		goto out; +	} +	if (IS_ERR(rb_node)) { +		em = ERR_PTR(PTR_ERR(rb_node)); +		goto out; +	} +	em = rb_entry(rb_node, struct extent_map, rb_node); +	goto found; + +	em = NULL; +	goto out; + +found: +	atomic_inc(&em->refs); +out: +	return em; +} + +/**   * remove_extent_mapping - removes an extent_map from the extent tree   * @tree:	extent tree to remove from   * @em:		extent map beeing removed diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index d3d442f4bbb..ab6d74b6e64 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);  int __init extent_map_init(void);  void extent_map_exit(void);  int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len); +struct extent_map *search_extent_mapping(struct extent_map_tree *tree, +					 u64 start, u64 len);  #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 941f1b71cd2..81ba6654c33 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -726,6 +726,15 @@ static noinline int cow_file_range(struct inode *inode,  	BUG_ON(disk_num_bytes >  	       btrfs_super_total_bytes(&root->fs_info->super_copy)); + +	read_lock(&BTRFS_I(inode)->extent_tree.lock); +	em = search_extent_mapping(&BTRFS_I(inode)->extent_tree, +				   start, num_bytes); +	if (em) { +		alloc_hint = em->block_start; +		free_extent_map(em); +	} +	read_unlock(&BTRFS_I(inode)->extent_tree.lock);  	btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);  	while (disk_num_bytes > 0) { @@ -738,7 +747,6 @@ static noinline int cow_file_range(struct inode *inode,  		em = alloc_extent_map(GFP_NOFS);  		em->start = start;  		em->orig_start = em->start; -  		ram_size = ins.offset;  		em->len = ins.offset;  |