Btrfs: do not allow logged extents to be merged or removed
We drop the extent map tree lock while we're logging extents, so somebody could come in and merge another extent into this one and screw up our logging, or they could even remove us from the list which would keep us from logging the extent or freeing our ref on it, so we need to make sure to not clear LOGGING until after the extent is logged, and then we can merge it to adjacent extents. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
This commit is contained in:
parent
a105bb88f4
commit
201a903894
3 changed files with 16 additions and 3 deletions
|
@ -171,6 +171,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
|
|||
if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags))
|
||||
return 0;
|
||||
|
||||
if (test_bit(EXTENT_FLAG_LOGGING, &prev->flags) ||
|
||||
test_bit(EXTENT_FLAG_LOGGING, &next->flags))
|
||||
return 0;
|
||||
|
||||
if (extent_map_end(prev) == next->start &&
|
||||
prev->flags == next->flags &&
|
||||
prev->bdev == next->bdev &&
|
||||
|
@ -256,7 +260,8 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
|
|||
if (!em)
|
||||
goto out;
|
||||
|
||||
list_move(&em->list, &tree->modified_extents);
|
||||
if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
|
||||
list_move(&em->list, &tree->modified_extents);
|
||||
em->generation = gen;
|
||||
clear_bit(EXTENT_FLAG_PINNED, &em->flags);
|
||||
em->mod_start = em->start;
|
||||
|
@ -281,6 +286,12 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
|
|||
|
||||
}
|
||||
|
||||
void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em)
|
||||
{
|
||||
clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
|
||||
try_merge_map(tree, em);
|
||||
}
|
||||
|
||||
/**
|
||||
* add_extent_mapping - add new extent map to the extent tree
|
||||
* @tree: tree to insert new map in
|
||||
|
|
|
@ -69,6 +69,7 @@ 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, u64 gen);
|
||||
void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em);
|
||||
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
|
||||
u64 start, u64 len);
|
||||
#endif
|
||||
|
|
|
@ -3410,13 +3410,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|||
em = list_entry(extents.next, struct extent_map, list);
|
||||
|
||||
list_del_init(&em->list);
|
||||
clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
|
||||
|
||||
/*
|
||||
* If we had an error we just need to delete everybody from our
|
||||
* private list.
|
||||
*/
|
||||
if (ret) {
|
||||
clear_em_logging(tree, em);
|
||||
free_extent_map(em);
|
||||
continue;
|
||||
}
|
||||
|
@ -3424,8 +3424,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
|
|||
write_unlock(&tree->lock);
|
||||
|
||||
ret = log_one_extent(trans, inode, root, em, path);
|
||||
free_extent_map(em);
|
||||
write_lock(&tree->lock);
|
||||
clear_em_logging(tree, em);
|
||||
free_extent_map(em);
|
||||
}
|
||||
WARN_ON(!list_empty(&extents));
|
||||
write_unlock(&tree->lock);
|
||||
|
|
Loading…
Reference in a new issue