diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 39 | 
1 files changed, 25 insertions, 14 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 88e51aded6bd..8be4278e25e8 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1023,17 +1023,13 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,  	u64 old_root_bytenr;  	u64 old_root_used;  	struct btrfs_root *tree_root = root->fs_info->tree_root; -	bool extent_root = (root->objectid == BTRFS_EXTENT_TREE_OBJECTID);  	old_root_used = btrfs_root_used(&root->root_item); -	btrfs_write_dirty_block_groups(trans, root);  	while (1) {  		old_root_bytenr = btrfs_root_bytenr(&root->root_item);  		if (old_root_bytenr == root->node->start && -		    old_root_used == btrfs_root_used(&root->root_item) && -		    (!extent_root || -		     list_empty(&trans->transaction->dirty_bgs))) +		    old_root_used == btrfs_root_used(&root->root_item))  			break;  		btrfs_set_root_node(&root->root_item, root->node); @@ -1044,14 +1040,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,  			return ret;  		old_root_used = btrfs_root_used(&root->root_item); -		if (extent_root) { -			ret = btrfs_write_dirty_block_groups(trans, root); -			if (ret) -				return ret; -		} -		ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); -		if (ret) -			return ret;  	}  	return 0; @@ -1068,6 +1056,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 list_head *dirty_bgs = &trans->transaction->dirty_bgs;  	struct list_head *next;  	struct extent_buffer *eb;  	int ret; @@ -1095,11 +1084,15 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,  	if (ret)  		return ret; +	ret = btrfs_setup_space_cache(trans, root); +	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; - +again:  	while (!list_empty(&fs_info->dirty_cowonly_roots)) {  		next = fs_info->dirty_cowonly_roots.next;  		list_del_init(next); @@ -1112,8 +1105,23 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,  		ret = update_cowonly_root(trans, root);  		if (ret)  			return ret; +		ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); +		if (ret) +			return ret;  	} +	while (!list_empty(dirty_bgs)) { +		ret = btrfs_write_dirty_block_groups(trans, root); +		if (ret) +			return ret; +		ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); +		if (ret) +			return ret; +	} + +	if (!list_empty(&fs_info->dirty_cowonly_roots)) +		goto again; +  	list_add_tail(&fs_info->extent_root->dirty_list,  		      &trans->transaction->switch_commits);  	btrfs_after_dev_replace_commit(fs_info); @@ -1811,6 +1819,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,  		wait_for_commit(root, cur_trans); +		if (unlikely(cur_trans->aborted)) +			ret = cur_trans->aborted; +  		btrfs_put_transaction(cur_trans);  		return ret;  |