aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);