@@ -2713,7 +2713,6 @@ retry_root_backup:
ret = PTR_ERR(extent_root);
goto recovery_tree_root;
}
- set_bit(BTRFS_ROOT_TRACK_DIRTY, &extent_root->state);
fs_info->extent_root = extent_root;
location.objectid = BTRFS_DEV_TREE_OBJECTID;
@@ -933,17 +933,16 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
}
/*
- * this is used to update the root pointer in the tree of tree roots.
+ * Update the extent_root pointer in the tree of tree roots.
*
- * But, in the case of the extent allocation tree, updating the root
- * pointer may allocate blocks which may change the root of the extent
- * allocation tree.
+ * In the case of the extent allocation tree, updating the root pointer may
+ * allocate blocks which may change the root of the extent allocation tree.
*
* So, this loops and repeats and makes sure the cowonly root didn't
* change while the root pointer was being updated in the metadata.
*/
-static int update_cowonly_root(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
+static int update_extent_root(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
{
int ret;
u64 old_root_bytenr;
@@ -986,6 +985,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_root *tree_root = fs_info->tree_root;
struct list_head *next;
struct extent_buffer *eb;
int ret;
@@ -1017,26 +1017,30 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
if (ret)
return ret;
- /* run_qgroups might have added some more refs */
- ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
- if (ret)
- return ret;
-
while (!list_empty(&fs_info->dirty_cowonly_roots)) {
next = fs_info->dirty_cowonly_roots.next;
list_del_init(next);
root = list_entry(next, struct btrfs_root, dirty_list);
- if (root != fs_info->extent_root)
- list_add_tail(&root->dirty_list,
- &trans->transaction->switch_commits);
- ret = update_cowonly_root(trans, root);
+ list_add_tail(&root->dirty_list,
+ &trans->transaction->switch_commits);
+ btrfs_set_root_node(&root->root_item, root->node);
+ ret = btrfs_update_root(trans, tree_root, &root->root_key,
+ &root->root_item);
if (ret)
return ret;
}
+ ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
+ if (ret)
+ return ret;
+
list_add_tail(&fs_info->extent_root->dirty_list,
&trans->transaction->switch_commits);
+ ret = update_extent_root(trans, fs_info->extent_root);
+ if (ret)
+ return ret;
+
btrfs_after_dev_replace_commit(fs_info);
return 0;
Depending on where the extent root shows up in the dirty list we could end up recowing the extent root a few times during commit. This is inefficient, so instead only track the other COW only roots and update them all at once, and then do the extent root/block group update loop by itself to try and reduce the amount of churn we do at commit time. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> --- fs/btrfs/disk-io.c | 1 - fs/btrfs/transaction.c | 34 +++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-)