Commit 201a9038 authored by Josef Bacik's avatar Josef Bacik

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: default avatarJosef Bacik <jbacik@fusionio.com>
parent a105bb88
...@@ -171,6 +171,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next) ...@@ -171,6 +171,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags)) if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags))
return 0; 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 && if (extent_map_end(prev) == next->start &&
prev->flags == next->flags && prev->flags == next->flags &&
prev->bdev == next->bdev && prev->bdev == next->bdev &&
...@@ -256,6 +260,7 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, ...@@ -256,6 +260,7 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
if (!em) if (!em)
goto out; goto out;
if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
list_move(&em->list, &tree->modified_extents); list_move(&em->list, &tree->modified_extents);
em->generation = gen; em->generation = gen;
clear_bit(EXTENT_FLAG_PINNED, &em->flags); clear_bit(EXTENT_FLAG_PINNED, &em->flags);
...@@ -281,6 +286,12 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, ...@@ -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 * add_extent_mapping - add new extent map to the extent tree
* @tree: tree to insert new map in * @tree: tree to insert new map in
......
...@@ -69,6 +69,7 @@ void free_extent_map(struct extent_map *em); ...@@ -69,6 +69,7 @@ void free_extent_map(struct extent_map *em);
int __init extent_map_init(void); int __init extent_map_init(void);
void extent_map_exit(void); void extent_map_exit(void);
int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen); 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, struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
u64 start, u64 len); u64 start, u64 len);
#endif #endif
...@@ -3410,13 +3410,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, ...@@ -3410,13 +3410,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
em = list_entry(extents.next, struct extent_map, list); em = list_entry(extents.next, struct extent_map, list);
list_del_init(&em->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 * If we had an error we just need to delete everybody from our
* private list. * private list.
*/ */
if (ret) { if (ret) {
clear_em_logging(tree, em);
free_extent_map(em); free_extent_map(em);
continue; continue;
} }
...@@ -3424,8 +3424,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, ...@@ -3424,8 +3424,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
write_unlock(&tree->lock); write_unlock(&tree->lock);
ret = log_one_extent(trans, inode, root, em, path); ret = log_one_extent(trans, inode, root, em, path);
free_extent_map(em);
write_lock(&tree->lock); write_lock(&tree->lock);
clear_em_logging(tree, em);
free_extent_map(em);
} }
WARN_ON(!list_empty(&extents)); WARN_ON(!list_empty(&extents));
write_unlock(&tree->lock); write_unlock(&tree->lock);
......
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