aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-01-24 12:02:07 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-01-24 12:49:48 -0500
commit201a90389424d6771d24fc5d72f7e34cb4a8f967 (patch)
tree2e184b0b5a702855163d7da2fa5bee2a6fb8ef98 /fs
parenta105bb88f46b60de2adf1ee98745bd59362b09ab (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent_map.c13
-rw-r--r--fs/btrfs/extent_map.h1
-rw-r--r--fs/btrfs/tree-log.c5
3 files changed, 16 insertions, 3 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index fff2c28497b6..ed88f5ee4bea 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -171,6 +171,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
171 if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags)) 171 if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags))
172 return 0; 172 return 0;
173 173
174 if (test_bit(EXTENT_FLAG_LOGGING, &prev->flags) ||
175 test_bit(EXTENT_FLAG_LOGGING, &next->flags))
176 return 0;
177
174 if (extent_map_end(prev) == next->start && 178 if (extent_map_end(prev) == next->start &&
175 prev->flags == next->flags && 179 prev->flags == next->flags &&
176 prev->bdev == next->bdev && 180 prev->bdev == next->bdev &&
@@ -256,7 +260,8 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
256 if (!em) 260 if (!em)
257 goto out; 261 goto out;
258 262
259 list_move(&em->list, &tree->modified_extents); 263 if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
264 list_move(&em->list, &tree->modified_extents);
260 em->generation = gen; 265 em->generation = gen;
261 clear_bit(EXTENT_FLAG_PINNED, &em->flags); 266 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
262 em->mod_start = em->start; 267 em->mod_start = em->start;
@@ -281,6 +286,12 @@ out:
281 286
282} 287}
283 288
289void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em)
290{
291 clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
292 try_merge_map(tree, em);
293}
294
284/** 295/**
285 * add_extent_mapping - add new extent map to the extent tree 296 * add_extent_mapping - add new extent map to the extent tree
286 * @tree: tree to insert new map in 297 * @tree: tree to insert new map in
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index 922943ce29e8..c6598c89cff8 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -69,6 +69,7 @@ void free_extent_map(struct extent_map *em);
69int __init extent_map_init(void); 69int __init extent_map_init(void);
70void extent_map_exit(void); 70void extent_map_exit(void);
71int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen); 71int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen);
72void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em);
72struct extent_map *search_extent_mapping(struct extent_map_tree *tree, 73struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
73 u64 start, u64 len); 74 u64 start, u64 len);
74#endif 75#endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 83186c7e45d4..de8899b04d69 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3410,13 +3410,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
3410 em = list_entry(extents.next, struct extent_map, list); 3410 em = list_entry(extents.next, struct extent_map, list);
3411 3411
3412 list_del_init(&em->list); 3412 list_del_init(&em->list);
3413 clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
3414 3413
3415 /* 3414 /*
3416 * If we had an error we just need to delete everybody from our 3415 * If we had an error we just need to delete everybody from our
3417 * private list. 3416 * private list.
3418 */ 3417 */
3419 if (ret) { 3418 if (ret) {
3419 clear_em_logging(tree, em);
3420 free_extent_map(em); 3420 free_extent_map(em);
3421 continue; 3421 continue;
3422 } 3422 }
@@ -3424,8 +3424,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
3424 write_unlock(&tree->lock); 3424 write_unlock(&tree->lock);
3425 3425
3426 ret = log_one_extent(trans, inode, root, em, path); 3426 ret = log_one_extent(trans, inode, root, em, path);
3427 free_extent_map(em);
3428 write_lock(&tree->lock); 3427 write_lock(&tree->lock);
3428 clear_em_logging(tree, em);
3429 free_extent_map(em);
3429 } 3430 }
3430 WARN_ON(!list_empty(&extents)); 3431 WARN_ON(!list_empty(&extents));
3431 write_unlock(&tree->lock); 3432 write_unlock(&tree->lock);