Commit a1ba4c08 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

btrfs: add helper to replace extent map range with a new extent map

We have several places that need to drop all the extent maps in a given
file range and then add a new extent map for that range. Currently they
call btrfs_drop_extent_map_range() to delete all extent maps in the range
and then keep trying to add the new extent map in a loop that keeps
retrying while the insertion of the new extent map fails with -EEXIST.

So instead of repeating this logic, add a helper to extent_map.c that
does these steps and name it btrfs_replace_extent_map_range(). Also add
a comment about why the retry loop is necessary.
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 9c9d1b4f
...@@ -879,3 +879,44 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end, ...@@ -879,3 +879,44 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
free_extent_map(split); free_extent_map(split);
free_extent_map(split2); free_extent_map(split2);
} }
/*
* Replace a range in the inode's extent map tree with a new extent map.
*
* @inode: The target inode.
* @new_em: The new extent map to add to the inode's extent map tree.
* @modified: Indicate if the new extent map should be added to the list of
* modified extents (for fast fsync tracking).
*
* Drops all the extent maps in the inode's extent map tree that intersect the
* range of the new extent map and adds the new extent map to the tree.
* The caller should have locked an appropriate file range in the inode's io
* tree before calling this function.
*/
int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
struct extent_map *new_em,
bool modified)
{
const u64 end = new_em->start + new_em->len - 1;
struct extent_map_tree *tree = &inode->extent_tree;
int ret;
ASSERT(!extent_map_in_tree(new_em));
/*
* The caller has locked an appropriate file range in the inode's io
* tree, but getting -EEXIST when adding the new extent map can still
* happen in case there are extents that partially cover the range, and
* this is due to two tasks operating on different parts of the extent.
* See commit 18e83ac75bfe67 ("Btrfs: fix unexpected EEXIST from
* btrfs_get_extent") for an example and details.
*/
do {
btrfs_drop_extent_map_range(inode, new_em->start, end, false);
write_lock(&tree->lock);
ret = add_extent_mapping(tree, new_em, modified);
write_unlock(&tree->lock);
} while (ret == -EEXIST);
return ret;
}
...@@ -109,5 +109,8 @@ int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info, ...@@ -109,5 +109,8 @@ int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info,
void btrfs_drop_extent_map_range(struct btrfs_inode *inode, void btrfs_drop_extent_map_range(struct btrfs_inode *inode,
u64 start, u64 end, u64 start, u64 end,
bool skip_pinned); bool skip_pinned);
int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
struct extent_map *new_em,
bool modified);
#endif #endif
...@@ -2359,7 +2359,6 @@ static int fill_holes(struct btrfs_trans_handle *trans, ...@@ -2359,7 +2359,6 @@ static int fill_holes(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi; struct btrfs_file_extent_item *fi;
struct extent_map *hole_em; struct extent_map *hole_em;
struct extent_map_tree *em_tree = &inode->extent_tree;
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
...@@ -2440,12 +2439,7 @@ static int fill_holes(struct btrfs_trans_handle *trans, ...@@ -2440,12 +2439,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
hole_em->compress_type = BTRFS_COMPRESS_NONE; hole_em->compress_type = BTRFS_COMPRESS_NONE;
hole_em->generation = trans->transid; hole_em->generation = trans->transid;
do { ret = btrfs_replace_extent_map_range(inode, hole_em, true);
btrfs_drop_extent_map_range(inode, offset, end - 1, false);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, hole_em, 1);
write_unlock(&em_tree->lock);
} while (ret == -EEXIST);
free_extent_map(hole_em); free_extent_map(hole_em);
if (ret) if (ret)
btrfs_set_inode_full_sync(inode); btrfs_set_inode_full_sync(inode);
......
...@@ -5051,7 +5051,6 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size) ...@@ -5051,7 +5051,6 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size)
struct extent_io_tree *io_tree = &inode->io_tree; struct extent_io_tree *io_tree = &inode->io_tree;
struct extent_map *em = NULL; struct extent_map *em = NULL;
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
struct extent_map_tree *em_tree = &inode->extent_tree;
u64 hole_start = ALIGN(oldsize, fs_info->sectorsize); u64 hole_start = ALIGN(oldsize, fs_info->sectorsize);
u64 block_end = ALIGN(size, fs_info->sectorsize); u64 block_end = ALIGN(size, fs_info->sectorsize);
u64 last_byte; u64 last_byte;
...@@ -5099,11 +5098,11 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size) ...@@ -5099,11 +5098,11 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size)
if (err) if (err)
break; break;
hole_em = alloc_extent_map();
if (!hole_em) {
btrfs_drop_extent_map_range(inode, cur_offset, btrfs_drop_extent_map_range(inode, cur_offset,
cur_offset + hole_size - 1, cur_offset + hole_size - 1,
false); false);
hole_em = alloc_extent_map();
if (!hole_em) {
btrfs_set_inode_full_sync(inode); btrfs_set_inode_full_sync(inode);
goto next; goto next;
} }
...@@ -5118,16 +5117,7 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size) ...@@ -5118,16 +5117,7 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size)
hole_em->compress_type = BTRFS_COMPRESS_NONE; hole_em->compress_type = BTRFS_COMPRESS_NONE;
hole_em->generation = fs_info->generation; hole_em->generation = fs_info->generation;
while (1) { err = btrfs_replace_extent_map_range(inode, hole_em, true);
write_lock(&em_tree->lock);
err = add_extent_mapping(em_tree, hole_em, 1);
write_unlock(&em_tree->lock);
if (err != -EEXIST)
break;
btrfs_drop_extent_map_range(inode, cur_offset,
cur_offset + hole_size - 1,
false);
}
free_extent_map(hole_em); free_extent_map(hole_em);
} else { } else {
err = btrfs_inode_set_file_extent_range(inode, err = btrfs_inode_set_file_extent_range(inode,
...@@ -7353,7 +7343,6 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, ...@@ -7353,7 +7343,6 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
u64 ram_bytes, int compress_type, u64 ram_bytes, int compress_type,
int type) int type)
{ {
struct extent_map_tree *em_tree;
struct extent_map *em; struct extent_map *em;
int ret; int ret;
...@@ -7362,7 +7351,6 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, ...@@ -7362,7 +7351,6 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
type == BTRFS_ORDERED_NOCOW || type == BTRFS_ORDERED_NOCOW ||
type == BTRFS_ORDERED_REGULAR); type == BTRFS_ORDERED_REGULAR);
em_tree = &inode->extent_tree;
em = alloc_extent_map(); em = alloc_extent_map();
if (!em) if (!em)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -7383,18 +7371,7 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, ...@@ -7383,18 +7371,7 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
em->compress_type = compress_type; em->compress_type = compress_type;
} }
do { ret = btrfs_replace_extent_map_range(inode, em, true);
btrfs_drop_extent_map_range(inode, em->start,
em->start + em->len - 1, false);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em, 1);
write_unlock(&em_tree->lock);
/*
* The caller has taken lock_extent(), who could race with us
* to add em?
*/
} while (ret == -EEXIST);
if (ret) { if (ret) {
free_extent_map(em); free_extent_map(em);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -9893,7 +9870,6 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, ...@@ -9893,7 +9870,6 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
struct btrfs_trans_handle *trans) struct btrfs_trans_handle *trans)
{ {
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct extent_map *em; struct extent_map *em;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key ins; struct btrfs_key ins;
...@@ -9949,11 +9925,10 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, ...@@ -9949,11 +9925,10 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
break; break;
} }
btrfs_drop_extent_map_range(BTRFS_I(inode), cur_offset,
cur_offset + ins.offset - 1, false);
em = alloc_extent_map(); em = alloc_extent_map();
if (!em) { if (!em) {
btrfs_drop_extent_map_range(BTRFS_I(inode), cur_offset,
cur_offset + ins.offset - 1, false);
btrfs_set_inode_full_sync(BTRFS_I(inode)); btrfs_set_inode_full_sync(BTRFS_I(inode));
goto next; goto next;
} }
...@@ -9968,16 +9943,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, ...@@ -9968,16 +9943,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
set_bit(EXTENT_FLAG_PREALLOC, &em->flags); set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
em->generation = trans->transid; em->generation = trans->transid;
while (1) { ret = btrfs_replace_extent_map_range(BTRFS_I(inode), em, true);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em, 1);
write_unlock(&em_tree->lock);
if (ret != -EEXIST)
break;
btrfs_drop_extent_map_range(BTRFS_I(inode), cur_offset,
cur_offset + ins.offset - 1,
false);
}
free_extent_map(em); free_extent_map(em);
next: next:
num_bytes -= ins.offset; num_bytes -= ins.offset;
......
...@@ -2890,7 +2890,6 @@ static noinline_for_stack int prealloc_file_extent_cluster( ...@@ -2890,7 +2890,6 @@ static noinline_for_stack int prealloc_file_extent_cluster(
static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inode, static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inode,
u64 start, u64 end, u64 block_start) u64 start, u64 end, u64 block_start)
{ {
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct extent_map *em; struct extent_map *em;
int ret = 0; int ret = 0;
...@@ -2905,17 +2904,10 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inod ...@@ -2905,17 +2904,10 @@ static noinline_for_stack int setup_relocation_extent_mapping(struct inode *inod
set_bit(EXTENT_FLAG_PINNED, &em->flags); set_bit(EXTENT_FLAG_PINNED, &em->flags);
lock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL); lock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
while (1) { ret = btrfs_replace_extent_map_range(BTRFS_I(inode), em, false);
write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em, 0);
write_unlock(&em_tree->lock);
if (ret != -EEXIST) {
free_extent_map(em);
break;
}
btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, false);
}
unlock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL); unlock_extent(&BTRFS_I(inode)->io_tree, start, end, NULL);
free_extent_map(em);
return ret; return ret;
} }
......
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