diff options
| -rw-r--r-- | fs/btrfs/extent-tree.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/free-space-cache.c | 39 | ||||
| -rw-r--r-- | fs/btrfs/free-space-cache.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/inode-map.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/relocation.c | 5 | 
5 files changed, 34 insertions, 22 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c4c94b30c72..162a66bfbff 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3106,6 +3106,11 @@ again:  	WARN_ON(ret);  	if (i_size_read(inode) > 0) { +		ret = btrfs_check_trunc_cache_free_space(root, +					&root->fs_info->global_block_rsv); +		if (ret) +			goto out_put; +  		ret = btrfs_truncate_free_space_cache(root, trans, path,  						      inode);  		if (ret) diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 6a8bb9c7967..e53009657f0 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -197,30 +197,32 @@ int create_free_space_inode(struct btrfs_root *root,  					 block_group->key.objectid);  } -int btrfs_truncate_free_space_cache(struct btrfs_root *root, -				    struct btrfs_trans_handle *trans, -				    struct btrfs_path *path, -				    struct inode *inode) +int btrfs_check_trunc_cache_free_space(struct btrfs_root *root, +				       struct btrfs_block_rsv *rsv)  { -	struct btrfs_block_rsv *rsv;  	u64 needed_bytes; -	loff_t oldsize; -	int ret = 0; - -	rsv = trans->block_rsv; -	trans->block_rsv = &root->fs_info->global_block_rsv; +	int ret;  	/* 1 for slack space, 1 for updating the inode */  	needed_bytes = btrfs_calc_trunc_metadata_size(root, 1) +  		btrfs_calc_trans_metadata_size(root, 1); -	spin_lock(&trans->block_rsv->lock); -	if (trans->block_rsv->reserved < needed_bytes) { -		spin_unlock(&trans->block_rsv->lock); -		trans->block_rsv = rsv; -		return -ENOSPC; -	} -	spin_unlock(&trans->block_rsv->lock); +	spin_lock(&rsv->lock); +	if (rsv->reserved < needed_bytes) +		ret = -ENOSPC; +	else +		ret = 0; +	spin_unlock(&rsv->lock); +	return 0; +} + +int btrfs_truncate_free_space_cache(struct btrfs_root *root, +				    struct btrfs_trans_handle *trans, +				    struct btrfs_path *path, +				    struct inode *inode) +{ +	loff_t oldsize; +	int ret = 0;  	oldsize = i_size_read(inode);  	btrfs_i_size_write(inode, 0); @@ -232,9 +234,7 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,  	 */  	ret = btrfs_truncate_inode_items(trans, root, inode,  					 0, BTRFS_EXTENT_DATA_KEY); -  	if (ret) { -		trans->block_rsv = rsv;  		btrfs_abort_transaction(trans, root, ret);  		return ret;  	} @@ -242,7 +242,6 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,  	ret = btrfs_update_inode(trans, root, inode);  	if (ret)  		btrfs_abort_transaction(trans, root, ret); -	trans->block_rsv = rsv;  	return ret;  } diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h index 4dc17d8809c..8b7f19f4496 100644 --- a/fs/btrfs/free-space-cache.h +++ b/fs/btrfs/free-space-cache.h @@ -54,6 +54,8 @@ int create_free_space_inode(struct btrfs_root *root,  			    struct btrfs_block_group_cache *block_group,  			    struct btrfs_path *path); +int btrfs_check_trunc_cache_free_space(struct btrfs_root *root, +				       struct btrfs_block_rsv *rsv);  int btrfs_truncate_free_space_cache(struct btrfs_root *root,  				    struct btrfs_trans_handle *trans,  				    struct btrfs_path *path, diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 9818d4a3f82..2c66ddbbe67 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -429,11 +429,12 @@ int btrfs_save_ino_cache(struct btrfs_root *root,  	num_bytes = trans->bytes_reserved;  	/*  	 * 1 item for inode item insertion if need -	 * 3 items for inode item update (in the worst case) +	 * 4 items for inode item update (in the worst case) +	 * 1 items for slack space if we need do truncation  	 * 1 item for free space object  	 * 3 items for pre-allocation  	 */ -	trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8); +	trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 10);  	ret = btrfs_block_rsv_add(root, trans->block_rsv,  				  trans->bytes_reserved,  				  BTRFS_RESERVE_NO_FLUSH); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 5c5b8bb44ee..395b82031a4 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -3350,6 +3350,11 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,  	}  truncate: +	ret = btrfs_check_trunc_cache_free_space(root, +						 &fs_info->global_block_rsv); +	if (ret) +		goto out; +  	path = btrfs_alloc_path();  	if (!path) {  		ret = -ENOMEM;  |