mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	btrfs: update btrfs_space_info's bytes_may_use timely
This patch can fix some false ENOSPC errors, below test script can
reproduce one false ENOSPC error:
	#!/bin/bash
	dd if=/dev/zero of=fs.img bs=$((1024*1024)) count=128
	dev=$(losetup --show -f fs.img)
	mkfs.btrfs -f -M $dev
	mkdir /tmp/mntpoint
	mount $dev /tmp/mntpoint
	cd /tmp/mntpoint
	xfs_io -f -c "falloc 0 $((64*1024*1024))" testfile
Above script will fail for ENOSPC reason, but indeed fs still has free
space to satisfy this request. Please see call graph:
btrfs_fallocate()
|-> btrfs_alloc_data_chunk_ondemand()
|   bytes_may_use += 64M
|-> btrfs_prealloc_file_range()
    |-> btrfs_reserve_extent()
        |-> btrfs_add_reserved_bytes()
        |   alloc_type is RESERVE_ALLOC_NO_ACCOUNT, so it does not
        |   change bytes_may_use, and bytes_reserved += 64M. Now
        |   bytes_may_use + bytes_reserved == 128M, which is greater
        |   than btrfs_space_info's total_bytes, false enospc occurs.
        |   Note, the bytes_may_use decrease operation will be done in
        |   end of btrfs_fallocate(), which is too late.
Here is another simple case for buffered write:
                    CPU 1              |              CPU 2
                                       |
|-> cow_file_range()                   |-> __btrfs_buffered_write()
    |-> btrfs_reserve_extent()         |   |
    |                                  |   |
    |                                  |   |
    |    .....                         |   |-> btrfs_check_data_free_space()
    |                                  |
    |                                  |
    |-> extent_clear_unlock_delalloc() |
In CPU 1, btrfs_reserve_extent()->find_free_extent()->
btrfs_add_reserved_bytes() do not decrease bytes_may_use, the decrease
operation will be delayed to be done in extent_clear_unlock_delalloc().
Assume in this case, btrfs_reserve_extent() reserved 128MB data, CPU2's
btrfs_check_data_free_space() tries to reserve 100MB data space.
If
	100MB > data_sinfo->total_bytes - data_sinfo->bytes_used -
		data_sinfo->bytes_reserved - data_sinfo->bytes_pinned -
		data_sinfo->bytes_readonly - data_sinfo->bytes_may_use
btrfs_check_data_free_space() will try to allcate new data chunk or call
btrfs_start_delalloc_roots(), or commit current transaction in order to
reserve some free space, obviously a lot of work. But indeed it's not
necessary as long as decreasing bytes_may_use timely, we still have
free space, decreasing 128M from bytes_may_use.
To fix this issue, this patch chooses to update bytes_may_use for both
data and metadata in btrfs_add_reserved_bytes(). For compress path, real
extent length may not be equal to file content length, so introduce a
ram_bytes argument for btrfs_reserve_extent(), find_free_extent() and
btrfs_add_reserved_bytes(), it's becasue bytes_may_use is increased by
file content length. Then compress path can update bytes_may_use
correctly. Also now we can discard RESERVE_ALLOC_NO_ACCOUNT, RESERVE_ALLOC
and RESERVE_FREE.
As we know, usually EXTENT_DO_ACCOUNTING is used for error path. In
run_delalloc_nocow(), for inode marked as NODATACOW or extent marked as
PREALLOC, we also need to update bytes_may_use, but can not pass
EXTENT_DO_ACCOUNTING, because it also clears metadata reservation, so
here we introduce EXTENT_CLEAR_DATA_RESV flag to indicate btrfs_clear_bit_hook()
to update btrfs_space_info's bytes_may_use.
Meanwhile __btrfs_prealloc_file_range() will call
btrfs_free_reserved_data_space() internally for both sucessful and failed
path, btrfs_prealloc_file_range()'s callers does not need to call
btrfs_free_reserved_data_space() any more.
Signed-off-by: Wang Xiaoguang <wangxg.fnst@cn.fujitsu.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
			
			
This commit is contained in:
		
							parent
							
								
									4824f1f412
								
							
						
					
					
						commit
						18513091af
					
				
					 7 changed files with 73 additions and 63 deletions
				
			
		|  | @ -2579,7 +2579,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
| 				   struct btrfs_root *root, | ||||
| 				   u64 root_objectid, u64 owner, u64 offset, | ||||
| 				   struct btrfs_key *ins); | ||||
| int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes, | ||||
| int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes, | ||||
| 			 u64 min_alloc_size, u64 empty_size, u64 hint_byte, | ||||
| 			 struct btrfs_key *ins, int is_data, int delalloc); | ||||
| int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||||
|  |  | |||
|  | @ -60,21 +60,6 @@ enum { | |||
| 	CHUNK_ALLOC_FORCE = 2, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Control how reservations are dealt with. | ||||
|  * | ||||
|  * RESERVE_FREE - freeing a reservation. | ||||
|  * RESERVE_ALLOC - allocating space and we need to update bytes_may_use for | ||||
|  *   ENOSPC accounting | ||||
|  * RESERVE_ALLOC_NO_ACCOUNT - allocating space and we should not update | ||||
|  *   bytes_may_use as the ENOSPC accounting is done elsewhere | ||||
|  */ | ||||
| enum { | ||||
| 	RESERVE_FREE = 0, | ||||
| 	RESERVE_ALLOC = 1, | ||||
| 	RESERVE_ALLOC_NO_ACCOUNT = 2, | ||||
| }; | ||||
| 
 | ||||
| static int update_block_group(struct btrfs_trans_handle *trans, | ||||
| 			      struct btrfs_root *root, u64 bytenr, | ||||
| 			      u64 num_bytes, int alloc); | ||||
|  | @ -105,7 +90,7 @@ static int find_next_key(struct btrfs_path *path, int level, | |||
| static void dump_space_info(struct btrfs_space_info *info, u64 bytes, | ||||
| 			    int dump_block_groups); | ||||
| static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, | ||||
| 				    u64 num_bytes, int reserve, int delalloc); | ||||
| 				    u64 ram_bytes, u64 num_bytes, int delalloc); | ||||
| static int btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, | ||||
| 				     u64 num_bytes, int delalloc); | ||||
| static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, | ||||
|  | @ -3502,7 +3487,6 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, | |||
| 		dcs = BTRFS_DC_SETUP; | ||||
| 	else if (ret == -ENOSPC) | ||||
| 		set_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags); | ||||
| 	btrfs_free_reserved_data_space(inode, 0, num_pages); | ||||
| 
 | ||||
| out_put: | ||||
| 	iput(inode); | ||||
|  | @ -6500,8 +6484,9 @@ void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg) | |||
| /**
 | ||||
|  * btrfs_add_reserved_bytes - update the block_group and space info counters | ||||
|  * @cache:	The cache we are manipulating | ||||
|  * @ram_bytes:  The number of bytes of file content, and will be same to | ||||
|  *              @num_bytes except for the compress path. | ||||
|  * @num_bytes:	The number of bytes in question | ||||
|  * @reserve:	One of the reservation enums | ||||
|  * @delalloc:   The blocks are allocated for the delalloc write | ||||
|  * | ||||
|  * This is called by the allocator when it reserves space. Metadata | ||||
|  | @ -6516,7 +6501,7 @@ void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg) | |||
|  * succeeds. | ||||
|  */ | ||||
| static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, | ||||
| 				    u64 num_bytes, int reserve, int delalloc) | ||||
| 				    u64 ram_bytes, u64 num_bytes, int delalloc) | ||||
| { | ||||
| 	struct btrfs_space_info *space_info = cache->space_info; | ||||
| 	int ret = 0; | ||||
|  | @ -6528,13 +6513,11 @@ static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, | |||
| 	} else { | ||||
| 		cache->reserved += num_bytes; | ||||
| 		space_info->bytes_reserved += num_bytes; | ||||
| 		if (reserve == RESERVE_ALLOC) { | ||||
| 			trace_btrfs_space_reservation(cache->fs_info, | ||||
| 					"space_info", space_info->flags, | ||||
| 					num_bytes, 0); | ||||
| 			space_info->bytes_may_use -= num_bytes; | ||||
| 		} | ||||
| 
 | ||||
| 		trace_btrfs_space_reservation(cache->fs_info, | ||||
| 				"space_info", space_info->flags, | ||||
| 				ram_bytes, 0); | ||||
| 		space_info->bytes_may_use -= ram_bytes; | ||||
| 		if (delalloc) | ||||
| 			cache->delalloc_bytes += num_bytes; | ||||
| 	} | ||||
|  | @ -7433,9 +7416,9 @@ btrfs_release_block_group(struct btrfs_block_group_cache *cache, | |||
|  * the free space extent currently. | ||||
|  */ | ||||
| static noinline int find_free_extent(struct btrfs_root *orig_root, | ||||
| 				     u64 num_bytes, u64 empty_size, | ||||
| 				     u64 hint_byte, struct btrfs_key *ins, | ||||
| 				     u64 flags, int delalloc) | ||||
| 				u64 ram_bytes, u64 num_bytes, u64 empty_size, | ||||
| 				u64 hint_byte, struct btrfs_key *ins, | ||||
| 				u64 flags, int delalloc) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	struct btrfs_root *root = orig_root->fs_info->extent_root; | ||||
|  | @ -7447,8 +7430,6 @@ static noinline int find_free_extent(struct btrfs_root *orig_root, | |||
| 	struct btrfs_space_info *space_info; | ||||
| 	int loop = 0; | ||||
| 	int index = __get_raid_index(flags); | ||||
| 	int alloc_type = (flags & BTRFS_BLOCK_GROUP_DATA) ? | ||||
| 		RESERVE_ALLOC_NO_ACCOUNT : RESERVE_ALLOC; | ||||
| 	bool failed_cluster_refill = false; | ||||
| 	bool failed_alloc = false; | ||||
| 	bool use_cluster = true; | ||||
|  | @ -7780,8 +7761,8 @@ static noinline int find_free_extent(struct btrfs_root *orig_root, | |||
| 					     search_start - offset); | ||||
| 		BUG_ON(offset > search_start); | ||||
| 
 | ||||
| 		ret = btrfs_add_reserved_bytes(block_group, num_bytes, | ||||
| 				alloc_type, delalloc); | ||||
| 		ret = btrfs_add_reserved_bytes(block_group, ram_bytes, | ||||
| 				num_bytes, delalloc); | ||||
| 		if (ret == -EAGAIN) { | ||||
| 			btrfs_add_free_space(block_group, offset, num_bytes); | ||||
| 			goto loop; | ||||
|  | @ -7953,7 +7934,7 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes, | |||
| 	up_read(&info->groups_sem); | ||||
| } | ||||
| 
 | ||||
| int btrfs_reserve_extent(struct btrfs_root *root, | ||||
| int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, | ||||
| 			 u64 num_bytes, u64 min_alloc_size, | ||||
| 			 u64 empty_size, u64 hint_byte, | ||||
| 			 struct btrfs_key *ins, int is_data, int delalloc) | ||||
|  | @ -7965,8 +7946,8 @@ int btrfs_reserve_extent(struct btrfs_root *root, | |||
| 	flags = btrfs_get_alloc_profile(root, is_data); | ||||
| again: | ||||
| 	WARN_ON(num_bytes < root->sectorsize); | ||||
| 	ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins, | ||||
| 			       flags, delalloc); | ||||
| 	ret = find_free_extent(root, ram_bytes, num_bytes, empty_size, | ||||
| 			       hint_byte, ins, flags, delalloc); | ||||
| 	if (!ret && !is_data) { | ||||
| 		btrfs_dec_block_group_reservations(root->fs_info, | ||||
| 						   ins->objectid); | ||||
|  | @ -7975,6 +7956,7 @@ int btrfs_reserve_extent(struct btrfs_root *root, | |||
| 			num_bytes = min(num_bytes >> 1, ins->offset); | ||||
| 			num_bytes = round_down(num_bytes, root->sectorsize); | ||||
| 			num_bytes = max(num_bytes, min_alloc_size); | ||||
| 			ram_bytes = num_bytes; | ||||
| 			if (num_bytes == min_alloc_size) | ||||
| 				final_tried = true; | ||||
| 			goto again; | ||||
|  | @ -8241,7 +8223,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ret = btrfs_add_reserved_bytes(block_group, ins->offset, | ||||
| 			RESERVE_ALLOC_NO_ACCOUNT, 0); | ||||
| 				       ins->offset, 0); | ||||
| 	BUG_ON(ret); /* logic error */ | ||||
| 	ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, | ||||
| 					 0, owner, offset, ins, 1); | ||||
|  | @ -8385,7 +8367,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | |||
| 	if (IS_ERR(block_rsv)) | ||||
| 		return ERR_CAST(block_rsv); | ||||
| 
 | ||||
| 	ret = btrfs_reserve_extent(root, blocksize, blocksize, | ||||
| 	ret = btrfs_reserve_extent(root, blocksize, blocksize, blocksize, | ||||
| 				   empty_size, hint, &ins, 0, 0); | ||||
| 	if (ret) | ||||
| 		goto out_unuse; | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| #define EXTENT_DAMAGED		(1U << 14) | ||||
| #define EXTENT_NORESERVE	(1U << 15) | ||||
| #define EXTENT_QGROUP_RESERVED	(1U << 16) | ||||
| #define EXTENT_CLEAR_DATA_RESV	(1U << 17) | ||||
| #define EXTENT_IOBITS		(EXTENT_LOCKED | EXTENT_WRITEBACK) | ||||
| #define EXTENT_CTLBITS		(EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2675,6 +2675,7 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 
 | ||||
| 	alloc_start = round_down(offset, blocksize); | ||||
| 	alloc_end = round_up(offset + len, blocksize); | ||||
| 	cur_offset = alloc_start; | ||||
| 
 | ||||
| 	/* Make sure we aren't being give some crap mode */ | ||||
| 	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||||
|  | @ -2767,7 +2768,6 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 
 | ||||
| 	/* First, check if we exceed the qgroup limit */ | ||||
| 	INIT_LIST_HEAD(&reserve_list); | ||||
| 	cur_offset = alloc_start; | ||||
| 	while (1) { | ||||
| 		em = btrfs_get_extent(inode, NULL, 0, cur_offset, | ||||
| 				      alloc_end - cur_offset, 0); | ||||
|  | @ -2794,6 +2794,14 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 					last_byte - cur_offset); | ||||
| 			if (ret < 0) | ||||
| 				break; | ||||
| 		} else { | ||||
| 			/*
 | ||||
| 			 * Do not need to reserve unwritten extent for this | ||||
| 			 * range, free reserved data space first, otherwise | ||||
| 			 * it'll result in false ENOSPC error. | ||||
| 			 */ | ||||
| 			btrfs_free_reserved_data_space(inode, cur_offset, | ||||
| 				last_byte - cur_offset); | ||||
| 		} | ||||
| 		free_extent_map(em); | ||||
| 		cur_offset = last_byte; | ||||
|  | @ -2811,6 +2819,9 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 					range->start, | ||||
| 					range->len, 1 << inode->i_blkbits, | ||||
| 					offset + len, &alloc_hint); | ||||
| 		else | ||||
| 			btrfs_free_reserved_data_space(inode, range->start, | ||||
| 						       range->len); | ||||
| 		list_del(&range->list); | ||||
| 		kfree(range); | ||||
| 	} | ||||
|  | @ -2845,18 +2856,11 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 	unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, | ||||
| 			     &cached_state, GFP_KERNEL); | ||||
| out: | ||||
| 	/*
 | ||||
| 	 * As we waited the extent range, the data_rsv_map must be empty | ||||
| 	 * in the range, as written data range will be released from it. | ||||
| 	 * And for prealloacted extent, it will also be released when | ||||
| 	 * its metadata is written. | ||||
| 	 * So this is completely used as cleanup. | ||||
| 	 */ | ||||
| 	btrfs_qgroup_free_data(inode, alloc_start, alloc_end - alloc_start); | ||||
| 	inode_unlock(inode); | ||||
| 	/* Let go of our reservation. */ | ||||
| 	btrfs_free_reserved_data_space(inode, alloc_start, | ||||
| 				       alloc_end - alloc_start); | ||||
| 	if (ret != 0) | ||||
| 		btrfs_free_reserved_data_space(inode, alloc_start, | ||||
| 				       alloc_end - cur_offset); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -495,10 +495,9 @@ int btrfs_save_ino_cache(struct btrfs_root *root, | |||
| 	ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc, | ||||
| 					      prealloc, prealloc, &alloc_hint); | ||||
| 	if (ret) { | ||||
| 		btrfs_delalloc_release_space(inode, 0, prealloc); | ||||
| 		btrfs_delalloc_release_metadata(inode, prealloc); | ||||
| 		goto out_put; | ||||
| 	} | ||||
| 	btrfs_free_reserved_data_space(inode, 0, prealloc); | ||||
| 
 | ||||
| 	ret = btrfs_write_out_ino_cache(root, trans, path, inode); | ||||
| out_put: | ||||
|  |  | |||
|  | @ -566,6 +566,8 @@ static noinline void compress_file_range(struct inode *inode, | |||
| 						     PAGE_SET_WRITEBACK | | ||||
| 						     page_error_op | | ||||
| 						     PAGE_END_WRITEBACK); | ||||
| 			btrfs_free_reserved_data_space_noquota(inode, start, | ||||
| 						end - start + 1); | ||||
| 			goto free_pages_out; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -742,7 +744,7 @@ static noinline void submit_compressed_extents(struct inode *inode, | |||
| 		lock_extent(io_tree, async_extent->start, | ||||
| 			    async_extent->start + async_extent->ram_size - 1); | ||||
| 
 | ||||
| 		ret = btrfs_reserve_extent(root, | ||||
| 		ret = btrfs_reserve_extent(root, async_extent->ram_size, | ||||
| 					   async_extent->compressed_size, | ||||
| 					   async_extent->compressed_size, | ||||
| 					   0, alloc_hint, &ins, 1, 1); | ||||
|  | @ -969,7 +971,8 @@ static noinline int cow_file_range(struct inode *inode, | |||
| 				     EXTENT_DEFRAG, PAGE_UNLOCK | | ||||
| 				     PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | | ||||
| 				     PAGE_END_WRITEBACK); | ||||
| 
 | ||||
| 			btrfs_free_reserved_data_space_noquota(inode, start, | ||||
| 						end - start + 1); | ||||
| 			*nr_written = *nr_written + | ||||
| 			     (end - start + PAGE_SIZE) / PAGE_SIZE; | ||||
| 			*page_started = 1; | ||||
|  | @ -989,7 +992,7 @@ static noinline int cow_file_range(struct inode *inode, | |||
| 		unsigned long op; | ||||
| 
 | ||||
| 		cur_alloc_size = disk_num_bytes; | ||||
| 		ret = btrfs_reserve_extent(root, cur_alloc_size, | ||||
| 		ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size, | ||||
| 					   root->sectorsize, 0, alloc_hint, | ||||
| 					   &ins, 1, 1); | ||||
| 		if (ret < 0) | ||||
|  | @ -1489,8 +1492,10 @@ static noinline int run_delalloc_nocow(struct inode *inode, | |||
| 		extent_clear_unlock_delalloc(inode, cur_offset, | ||||
| 					     cur_offset + num_bytes - 1, | ||||
| 					     locked_page, EXTENT_LOCKED | | ||||
| 					     EXTENT_DELALLOC, PAGE_UNLOCK | | ||||
| 					     PAGE_SET_PRIVATE2); | ||||
| 					     EXTENT_DELALLOC | | ||||
| 					     EXTENT_CLEAR_DATA_RESV, | ||||
| 					     PAGE_UNLOCK | PAGE_SET_PRIVATE2); | ||||
| 
 | ||||
| 		if (!nolock && nocow) | ||||
| 			btrfs_end_write_no_snapshoting(root); | ||||
| 		cur_offset = extent_end; | ||||
|  | @ -1807,7 +1812,9 @@ static void btrfs_clear_bit_hook(struct inode *inode, | |||
| 			return; | ||||
| 
 | ||||
| 		if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID | ||||
| 		    && do_list && !(state->state & EXTENT_NORESERVE)) | ||||
| 		    && do_list && !(state->state & EXTENT_NORESERVE) | ||||
| 		    && (*bits & (EXTENT_DO_ACCOUNTING | | ||||
| 		    EXTENT_CLEAR_DATA_RESV))) | ||||
| 			btrfs_free_reserved_data_space_noquota(inode, | ||||
| 					state->start, len); | ||||
| 
 | ||||
|  | @ -7252,7 +7259,7 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
| 	int ret; | ||||
| 
 | ||||
| 	alloc_hint = get_extent_allocation_hint(inode, start, len); | ||||
| 	ret = btrfs_reserve_extent(root, len, root->sectorsize, 0, | ||||
| 	ret = btrfs_reserve_extent(root, len, len, root->sectorsize, 0, | ||||
| 				   alloc_hint, &ins, 1, 1); | ||||
| 	if (ret) | ||||
| 		return ERR_PTR(ret); | ||||
|  | @ -7752,6 +7759,13 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
| 				ret = PTR_ERR(em2); | ||||
| 				goto unlock_err; | ||||
| 			} | ||||
| 			/*
 | ||||
| 			 * For inode marked NODATACOW or extent marked PREALLOC, | ||||
| 			 * use the existing or preallocated extent, so does not | ||||
| 			 * need to adjust btrfs_space_info's bytes_may_use. | ||||
| 			 */ | ||||
| 			btrfs_free_reserved_data_space_noquota(inode, | ||||
| 					start, len); | ||||
| 			goto unlock; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -7786,7 +7800,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
| 			i_size_write(inode, start + len); | ||||
| 
 | ||||
| 		adjust_dio_outstanding_extents(inode, dio_data, len); | ||||
| 		btrfs_free_reserved_data_space(inode, start, len); | ||||
| 		WARN_ON(dio_data->reserve < len); | ||||
| 		dio_data->reserve -= len; | ||||
| 		dio_data->unsubmitted_oe_range_end = start + len; | ||||
|  | @ -10306,6 +10319,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, | |||
| 	u64 last_alloc = (u64)-1; | ||||
| 	int ret = 0; | ||||
| 	bool own_trans = true; | ||||
| 	u64 end = start + num_bytes - 1; | ||||
| 
 | ||||
| 	if (trans) | ||||
| 		own_trans = false; | ||||
|  | @ -10327,8 +10341,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, | |||
| 		 * sized chunks. | ||||
| 		 */ | ||||
| 		cur_bytes = min(cur_bytes, last_alloc); | ||||
| 		ret = btrfs_reserve_extent(root, cur_bytes, min_size, 0, | ||||
| 					   *alloc_hint, &ins, 1, 0); | ||||
| 		ret = btrfs_reserve_extent(root, cur_bytes, cur_bytes, | ||||
| 				min_size, 0, *alloc_hint, &ins, 1, 0); | ||||
| 		if (ret) { | ||||
| 			if (own_trans) | ||||
| 				btrfs_end_transaction(trans, root); | ||||
|  | @ -10414,6 +10428,9 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, | |||
| 		if (own_trans) | ||||
| 			btrfs_end_transaction(trans, root); | ||||
| 	} | ||||
| 	if (cur_offset < end) | ||||
| 		btrfs_free_reserved_data_space(inode, cur_offset, | ||||
| 			end - cur_offset + 1); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3040,6 +3040,7 @@ int prealloc_file_extent_cluster(struct inode *inode, | |||
| 	int ret = 0; | ||||
| 	u64 prealloc_start = cluster->start - offset; | ||||
| 	u64 prealloc_end = cluster->end - offset; | ||||
| 	u64 cur_offset; | ||||
| 
 | ||||
| 	BUG_ON(cluster->start != cluster->boundary[0]); | ||||
| 	inode_lock(inode); | ||||
|  | @ -3049,6 +3050,7 @@ int prealloc_file_extent_cluster(struct inode *inode, | |||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	cur_offset = prealloc_start; | ||||
| 	while (nr < cluster->nr) { | ||||
| 		start = cluster->boundary[nr] - offset; | ||||
| 		if (nr + 1 < cluster->nr) | ||||
|  | @ -3058,16 +3060,21 @@ int prealloc_file_extent_cluster(struct inode *inode, | |||
| 
 | ||||
| 		lock_extent(&BTRFS_I(inode)->io_tree, start, end); | ||||
| 		num_bytes = end + 1 - start; | ||||
| 		if (cur_offset < start) | ||||
| 			btrfs_free_reserved_data_space(inode, cur_offset, | ||||
| 					start - cur_offset); | ||||
| 		ret = btrfs_prealloc_file_range(inode, 0, start, | ||||
| 						num_bytes, num_bytes, | ||||
| 						end + 1, &alloc_hint); | ||||
| 		cur_offset = end + 1; | ||||
| 		unlock_extent(&BTRFS_I(inode)->io_tree, start, end); | ||||
| 		if (ret) | ||||
| 			break; | ||||
| 		nr++; | ||||
| 	} | ||||
| 	btrfs_free_reserved_data_space(inode, prealloc_start, | ||||
| 				       prealloc_end + 1 - prealloc_start); | ||||
| 	if (cur_offset < prealloc_end) | ||||
| 		btrfs_free_reserved_data_space(inode, cur_offset, | ||||
| 				       prealloc_end + 1 - cur_offset); | ||||
| out: | ||||
| 	inode_unlock(inode); | ||||
| 	return ret; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Wang Xiaoguang
						Wang Xiaoguang