diff options
Diffstat (limited to 'fs/btrfs/delayed-inode.c')
| -rw-r--r-- | fs/btrfs/delayed-inode.c | 50 | 
1 files changed, 35 insertions, 15 deletions
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index ae4d9cd1096..3a1b939c9ae 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -591,7 +591,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,  		return 0;  	src_rsv = trans->block_rsv; -	dst_rsv = &root->fs_info->global_block_rsv; +	dst_rsv = &root->fs_info->delayed_block_rsv;  	num_bytes = btrfs_calc_trans_metadata_size(root, 1);  	ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); @@ -609,7 +609,7 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,  	if (!item->bytes_reserved)  		return; -	rsv = &root->fs_info->global_block_rsv; +	rsv = &root->fs_info->delayed_block_rsv;  	btrfs_block_rsv_release(root, rsv,  				item->bytes_reserved);  } @@ -624,13 +624,36 @@ static int btrfs_delayed_inode_reserve_metadata(  	u64 num_bytes;  	int ret; -	if (!trans->bytes_reserved) -		return 0; -  	src_rsv = trans->block_rsv; -	dst_rsv = &root->fs_info->global_block_rsv; +	dst_rsv = &root->fs_info->delayed_block_rsv;  	num_bytes = btrfs_calc_trans_metadata_size(root, 1); + +	/* +	 * btrfs_dirty_inode will update the inode under btrfs_join_transaction +	 * which doesn't reserve space for speed.  This is a problem since we +	 * still need to reserve space for this update, so try to reserve the +	 * space. +	 * +	 * Now if src_rsv == delalloc_block_rsv we'll let it just steal since +	 * we're accounted for. +	 */ +	if (!trans->bytes_reserved && +	    src_rsv != &root->fs_info->delalloc_block_rsv) { +		ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes); +		/* +		 * Since we're under a transaction reserve_metadata_bytes could +		 * try to commit the transaction which will make it return +		 * EAGAIN to make us stop the transaction we have, so return +		 * ENOSPC instead so that btrfs_dirty_inode knows what to do. +		 */ +		if (ret == -EAGAIN) +			ret = -ENOSPC; +		if (!ret) +			node->bytes_reserved = num_bytes; +		return ret; +	} +  	ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);  	if (!ret)  		node->bytes_reserved = num_bytes; @@ -646,7 +669,7 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,  	if (!node->bytes_reserved)  		return; -	rsv = &root->fs_info->global_block_rsv; +	rsv = &root->fs_info->delayed_block_rsv;  	btrfs_block_rsv_release(root, rsv,  				node->bytes_reserved);  	node->bytes_reserved = 0; @@ -1026,7 +1049,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,  	path->leave_spinning = 1;  	block_rsv = trans->block_rsv; -	trans->block_rsv = &root->fs_info->global_block_rsv; +	trans->block_rsv = &root->fs_info->delayed_block_rsv;  	delayed_root = btrfs_get_delayed_root(root); @@ -1069,7 +1092,7 @@ static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,  	path->leave_spinning = 1;  	block_rsv = trans->block_rsv; -	trans->block_rsv = &node->root->fs_info->global_block_rsv; +	trans->block_rsv = &node->root->fs_info->delayed_block_rsv;  	ret = btrfs_insert_delayed_items(trans, path, node->root, node);  	if (!ret) @@ -1149,7 +1172,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)  		goto free_path;  	block_rsv = trans->block_rsv; -	trans->block_rsv = &root->fs_info->global_block_rsv; +	trans->block_rsv = &root->fs_info->delayed_block_rsv;  	ret = btrfs_insert_delayed_items(trans, path, root, delayed_node);  	if (!ret) @@ -1686,11 +1709,8 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,  	}  	ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node); -	/* -	 * we must reserve enough space when we start a new transaction, -	 * so reserving metadata failure is impossible -	 */ -	BUG_ON(ret); +	if (ret) +		goto release_node;  	fill_stack_inode_item(trans, &delayed_node->inode_item, inode);  	delayed_node->inode_dirty = 1;  |