aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2015-03-13 16:40:45 -0400
committerChris Mason <clm@fb.com>2015-03-13 16:47:04 -0400
commitea526d18990018f224e5734748975bea1824545f (patch)
tree810176d97b84699b286b8c05d0fae200dd7322b1
parent6a41dd0922e3c63e677c2d8f7906ce6a3e097af1 (diff)
Btrfs: fix ASSERT(list_empty(&cur_trans->dirty_bgs_list)
Dave could hit this assert consistently running btrfs/078. This is because when we update the block groups we could truncate the free space, which would try to delete the csums for that range and dirty the csum root. For this to happen we have to have already written out the csum root so it's kind of hard to hit this case. This patch fixes this by changing the logic to only write the dirty block groups if the dirty_cowonly_roots list is empty. This will get us the same effect as before since we add the extent root last, and will cover the case that we dirty some other root again but not the extent root. Thanks, Reported-by: David Sterba <dsterba@suse.cz> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r--fs/btrfs/transaction.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 07b985f2a814..2fe3ef5e9de3 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1023,7 +1023,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
1023 u64 old_root_bytenr; 1023 u64 old_root_bytenr;
1024 u64 old_root_used; 1024 u64 old_root_used;
1025 struct btrfs_root *tree_root = root->fs_info->tree_root; 1025 struct btrfs_root *tree_root = root->fs_info->tree_root;
1026 bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);
1027 1026
1028 old_root_used = btrfs_root_used(&root->root_item); 1027 old_root_used = btrfs_root_used(&root->root_item);
1029 btrfs_write_dirty_block_groups(trans, root); 1028 btrfs_write_dirty_block_groups(trans, root);
@@ -1031,9 +1030,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
1031 while (1) { 1030 while (1) {
1032 old_root_bytenr = btrfs_root_bytenr(&root->root_item); 1031 old_root_bytenr = btrfs_root_bytenr(&root->root_item);
1033 if (old_root_bytenr == root->node->start && 1032 if (old_root_bytenr == root->node->start &&
1034 old_root_used == btrfs_root_used(&root->root_item) && 1033 old_root_used == btrfs_root_used(&root->root_item))
1035 (!extent_root ||
1036 list_empty(&trans->transaction->dirty_bgs)))
1037 break; 1034 break;
1038 1035
1039 btrfs_set_root_node(&root->root_item, root->node); 1036 btrfs_set_root_node(&root->root_item, root->node);
@@ -1044,14 +1041,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
1044 return ret; 1041 return ret;
1045 1042
1046 old_root_used = btrfs_root_used(&root->root_item); 1043 old_root_used = btrfs_root_used(&root->root_item);
1047 if (extent_root) {
1048 ret = btrfs_write_dirty_block_groups(trans, root);
1049 if (ret)
1050 return ret;
1051 }
1052 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
1053 if (ret)
1054 return ret;
1055 } 1044 }
1056 1045
1057 return 0; 1046 return 0;
@@ -1068,6 +1057,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
1068 struct btrfs_root *root) 1057 struct btrfs_root *root)
1069{ 1058{
1070 struct btrfs_fs_info *fs_info = root->fs_info; 1059 struct btrfs_fs_info *fs_info = root->fs_info;
1060 struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
1071 struct list_head *next; 1061 struct list_head *next;
1072 struct extent_buffer *eb; 1062 struct extent_buffer *eb;
1073 int ret; 1063 int ret;
@@ -1099,7 +1089,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
1099 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); 1089 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
1100 if (ret) 1090 if (ret)
1101 return ret; 1091 return ret;
1102 1092again:
1103 while (!list_empty(&fs_info->dirty_cowonly_roots)) { 1093 while (!list_empty(&fs_info->dirty_cowonly_roots)) {
1104 next = fs_info->dirty_cowonly_roots.next; 1094 next = fs_info->dirty_cowonly_roots.next;
1105 list_del_init(next); 1095 list_del_init(next);
@@ -1112,8 +1102,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
1112 ret = update_cowonly_root(trans, root); 1102 ret = update_cowonly_root(trans, root);
1113 if (ret) 1103 if (ret)
1114 return ret; 1104 return ret;
1105 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
1106 if (ret)
1107 return ret;
1115 } 1108 }
1116 1109
1110 while (!list_empty(dirty_bgs)) {
1111 ret = btrfs_write_dirty_block_groups(trans, root);
1112 if (ret)
1113 return ret;
1114 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
1115 if (ret)
1116 return ret;
1117 }
1118
1119 if (!list_empty(&fs_info->dirty_cowonly_roots))
1120 goto again;
1121
1117 list_add_tail(&fs_info->extent_root->dirty_list, 1122 list_add_tail(&fs_info->extent_root->dirty_list,
1118 &trans->transaction->switch_commits); 1123 &trans->transaction->switch_commits);
1119 btrfs_after_dev_replace_commit(fs_info); 1124 btrfs_after_dev_replace_commit(fs_info);