aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Schmidt2013-03-20 08:49:48 -0500
committerGreg Kroah-Hartman2013-04-05 11:26:02 -0500
commit8e0bf542fadde9a9ef58c46fa1411dd6cdfb3b14 (patch)
tree2b5bed12a68e37234954da4a3c222622038bcb6b /fs
parentb9cde88f39769f464346db07253ce926e671a6e7 (diff)
downloadkernel-omap-8e0bf542fadde9a9ef58c46fa1411dd6cdfb3b14.tar.gz
kernel-omap-8e0bf542fadde9a9ef58c46fa1411dd6cdfb3b14.tar.xz
kernel-omap-8e0bf542fadde9a9ef58c46fa1411dd6cdfb3b14.zip
Btrfs: fix locking on ROOT_REPLACE operations in tree mod log
commit d9abbf1c3131b679379762700201ae69367f3f62 upstream. To resolve backrefs, ROOT_REPLACE operations in the tree mod log are required to be tied to at least one KEY_REMOVE_WHILE_FREEING operation. Therefore, those operations must be enclosed by tree_mod_log_write_lock() and tree_mod_log_write_unlock() calls. Those calls are private to the tree_mod_log_* functions, which means that removal of the elements of an old root node must be logged from tree_mod_log_insert_root. This partly reverts and corrects commit ba1bfbd5 (Btrfs: fix a tree mod logging issue for root replacement operations). This fixes the brand-new version of xfstest 276 as of commit cfe73f71. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index eea5da7a2b9a..ce1c16937167 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -651,6 +651,8 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
651 if (tree_mod_dont_log(fs_info, NULL)) 651 if (tree_mod_dont_log(fs_info, NULL))
652 return 0; 652 return 0;
653 653
654 __tree_mod_log_free_eb(fs_info, old_root);
655
654 ret = tree_mod_alloc(fs_info, flags, &tm); 656 ret = tree_mod_alloc(fs_info, flags, &tm);
655 if (ret < 0) 657 if (ret < 0)
656 goto out; 658 goto out;
@@ -736,7 +738,7 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq)
736static noinline void 738static noinline void
737tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, 739tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
738 struct extent_buffer *src, unsigned long dst_offset, 740 struct extent_buffer *src, unsigned long dst_offset,
739 unsigned long src_offset, int nr_items) 741 unsigned long src_offset, int nr_items, int log_removal)
740{ 742{
741 int ret; 743 int ret;
742 int i; 744 int i;
@@ -750,10 +752,12 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
750 } 752 }
751 753
752 for (i = 0; i < nr_items; i++) { 754 for (i = 0; i < nr_items; i++) {
753 ret = tree_mod_log_insert_key_locked(fs_info, src, 755 if (log_removal) {
754 i + src_offset, 756 ret = tree_mod_log_insert_key_locked(fs_info, src,
755 MOD_LOG_KEY_REMOVE); 757 i + src_offset,
756 BUG_ON(ret < 0); 758 MOD_LOG_KEY_REMOVE);
759 BUG_ON(ret < 0);
760 }
757 ret = tree_mod_log_insert_key_locked(fs_info, dst, 761 ret = tree_mod_log_insert_key_locked(fs_info, dst,
758 i + dst_offset, 762 i + dst_offset,
759 MOD_LOG_KEY_ADD); 763 MOD_LOG_KEY_ADD);
@@ -927,7 +931,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
927 ret = btrfs_dec_ref(trans, root, buf, 1, 1); 931 ret = btrfs_dec_ref(trans, root, buf, 1, 1);
928 BUG_ON(ret); /* -ENOMEM */ 932 BUG_ON(ret); /* -ENOMEM */
929 } 933 }
930 tree_mod_log_free_eb(root->fs_info, buf);
931 clean_tree_block(trans, root, buf); 934 clean_tree_block(trans, root, buf);
932 *last_ref = 1; 935 *last_ref = 1;
933 } 936 }
@@ -1046,6 +1049,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
1046 btrfs_set_node_ptr_generation(parent, parent_slot, 1049 btrfs_set_node_ptr_generation(parent, parent_slot,
1047 trans->transid); 1050 trans->transid);
1048 btrfs_mark_buffer_dirty(parent); 1051 btrfs_mark_buffer_dirty(parent);
1052 tree_mod_log_free_eb(root->fs_info, buf);
1049 btrfs_free_tree_block(trans, root, buf, parent_start, 1053 btrfs_free_tree_block(trans, root, buf, parent_start,
1050 last_ref); 1054 last_ref);
1051 } 1055 }
@@ -1755,7 +1759,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
1755 goto enospc; 1759 goto enospc;
1756 } 1760 }
1757 1761
1758 tree_mod_log_free_eb(root->fs_info, root->node);
1759 tree_mod_log_set_root_pointer(root, child); 1762 tree_mod_log_set_root_pointer(root, child);
1760 rcu_assign_pointer(root->node, child); 1763 rcu_assign_pointer(root->node, child);
1761 1764
@@ -3000,7 +3003,7 @@ static int push_node_left(struct btrfs_trans_handle *trans,
3000 push_items = min(src_nritems - 8, push_items); 3003 push_items = min(src_nritems - 8, push_items);
3001 3004
3002 tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, 3005 tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
3003 push_items); 3006 push_items, 1);
3004 copy_extent_buffer(dst, src, 3007 copy_extent_buffer(dst, src,
3005 btrfs_node_key_ptr_offset(dst_nritems), 3008 btrfs_node_key_ptr_offset(dst_nritems),
3006 btrfs_node_key_ptr_offset(0), 3009 btrfs_node_key_ptr_offset(0),
@@ -3071,7 +3074,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
3071 sizeof(struct btrfs_key_ptr)); 3074 sizeof(struct btrfs_key_ptr));
3072 3075
3073 tree_mod_log_eb_copy(root->fs_info, dst, src, 0, 3076 tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
3074 src_nritems - push_items, push_items); 3077 src_nritems - push_items, push_items, 1);
3075 copy_extent_buffer(dst, src, 3078 copy_extent_buffer(dst, src,
3076 btrfs_node_key_ptr_offset(0), 3079 btrfs_node_key_ptr_offset(0),
3077 btrfs_node_key_ptr_offset(src_nritems - push_items), 3080 btrfs_node_key_ptr_offset(src_nritems - push_items),
@@ -3223,12 +3226,18 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
3223 int mid; 3226 int mid;
3224 int ret; 3227 int ret;
3225 u32 c_nritems; 3228 u32 c_nritems;
3229 int tree_mod_log_removal = 1;
3226 3230
3227 c = path->nodes[level]; 3231 c = path->nodes[level];
3228 WARN_ON(btrfs_header_generation(c) != trans->transid); 3232 WARN_ON(btrfs_header_generation(c) != trans->transid);
3229 if (c == root->node) { 3233 if (c == root->node) {
3230 /* trying to split the root, lets make a new one */ 3234 /* trying to split the root, lets make a new one */
3231 ret = insert_new_root(trans, root, path, level + 1); 3235 ret = insert_new_root(trans, root, path, level + 1);
3236 /*
3237 * removal of root nodes has been logged by
3238 * tree_mod_log_set_root_pointer due to locking
3239 */
3240 tree_mod_log_removal = 0;
3232 if (ret) 3241 if (ret)
3233 return ret; 3242 return ret;
3234 } else { 3243 } else {
@@ -3266,7 +3275,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
3266 (unsigned long)btrfs_header_chunk_tree_uuid(split), 3275 (unsigned long)btrfs_header_chunk_tree_uuid(split),
3267 BTRFS_UUID_SIZE); 3276 BTRFS_UUID_SIZE);
3268 3277
3269 tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid); 3278 tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid,
3279 tree_mod_log_removal);
3270 copy_extent_buffer(split, c, 3280 copy_extent_buffer(split, c,
3271 btrfs_node_key_ptr_offset(0), 3281 btrfs_node_key_ptr_offset(0),
3272 btrfs_node_key_ptr_offset(mid), 3282 btrfs_node_key_ptr_offset(mid),