diff options
Diffstat (limited to 'transaction.c')
-rw-r--r-- | transaction.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/transaction.c b/transaction.c index 20a78c73..db9f3398 100644 --- a/transaction.c +++ b/transaction.c @@ -61,7 +61,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, u64 old_root_bytenr; struct btrfs_root *tree_root = root->fs_info->tree_root; - btrfs_write_dirty_block_groups(trans); while(1) { old_root_bytenr = btrfs_root_bytenr(&root->root_item); if (old_root_bytenr == root->node->start) @@ -99,6 +98,17 @@ int commit_tree_roots(struct btrfs_trans_handle *trans, if (ret) return ret; + /* + * If the above CoW is the first one to dirty the current tree_root, + * delayed refs for it won't be run until after this function has + * finished executing, meaning we won't process the extent tree root, + * which will have been added to ->dirty_cowonly_roots. So run + * delayed refs here as well. + */ + ret = btrfs_run_delayed_refs(trans, -1); + if (ret) + return ret; + while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); @@ -150,6 +160,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, if (trans->fs_info->transaction_aborted) return -EROFS; + /* + * Flush all accumulated delayed refs so that root-tree updates are + * consistent + */ + ret = btrfs_run_delayed_refs(trans, -1); + BUG_ON(ret); if (root->commit_root == root->node) goto commit_tree; @@ -167,10 +183,18 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ret = btrfs_update_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); BUG_ON(ret); + commit_tree: ret = commit_tree_roots(trans, fs_info); BUG_ON(ret); - ret = __commit_transaction(trans, root); + /* + * Ensure that all comitted roots are properly accounted in the + * extent tree + */ + ret = btrfs_run_delayed_refs(trans, -1); + BUG_ON(ret); + btrfs_write_dirty_block_groups(trans); + __commit_transaction(trans, root); if (ret < 0) goto out; write_ctree_super(trans); |