All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group
@ 2020-06-09 10:19 fdmanana
  2020-06-09 10:50 ` Nikolay Borisov
  2020-06-09 12:07 ` kernel test robot
  0 siblings, 2 replies; 5+ messages in thread
From: fdmanana @ 2020-06-09 10:19 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

When relocating a data block group we group extents from the block group
into a cluster and when the cluster reaches a certain number of extents
we do the relocation.

The first step is reserving data space and we try to reserve more space
than we need if the block group is not full, when there are gaps between
the collected extents. What happens is we attempt to reserve an amount of
space that corresponds to the different between the end offset of the last
extent and the start offset of the first extent. This can cause us to fail
with -ENOSPC even when we have enough free space for relocating all the
extents. We should skip space reservation for any gaps which always exist
for block groups that are not full. Non full block groups are the ones
which are useful to relocate, therefore a common use case.

So fix this by tracking the total number of bytes used for all the extents
in the cluster and then reserving an amount of space that matches exactly
the sum of the sizes of all the collected extents.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/relocation.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 11d156995446..7ec75229d86f 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -108,6 +108,7 @@ struct tree_block {
 struct file_extent_cluster {
 	u64 start;
 	u64 end;
+	u64 total_bytes;
 	u64 boundary[MAX_EXTENTS];
 	unsigned int nr;
 };
@@ -2583,14 +2584,14 @@ int prealloc_file_extent_cluster(struct inode *inode,
 	int nr = 0;
 	int ret = 0;
 	u64 prealloc_start = cluster->start - offset;
-	u64 prealloc_end = cluster->end - offset;
 	u64 cur_offset;
+	u64 allocated = 0;
 
 	BUG_ON(cluster->start != cluster->boundary[0]);
 	inode_lock(inode);
 
 	ret = btrfs_alloc_data_chunk_ondemand(BTRFS_I(inode),
-					      prealloc_end + 1 - prealloc_start);
+					      cluster->total_bytes);
 	if (ret)
 		goto out;
 
@@ -2604,21 +2605,19 @@ 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_noquota(inode,
-						       start - cur_offset);
 		ret = btrfs_prealloc_file_range(inode, 0, start,
 						num_bytes, num_bytes,
 						end + 1, &alloc_hint);
 		cur_offset = end + 1;
+		allocated += num_bytes;
 		unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
 		if (ret)
 			break;
 		nr++;
 	}
-	if (cur_offset < prealloc_end)
+	if (allocated < cluster->total_bytes)
 		btrfs_free_reserved_data_space_noquota(inode,
-					       prealloc_end + 1 - cur_offset);
+				       cluster->total_bytes - allocated);
 out:
 	inode_unlock(inode);
 	return ret;
@@ -2809,6 +2808,7 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key,
 		if (ret)
 			return ret;
 		cluster->nr = 0;
+		cluster->total_bytes = 0;
 	}
 
 	if (!cluster->nr)
@@ -2818,12 +2818,14 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key,
 	cluster->end = extent_key->objectid + extent_key->offset - 1;
 	cluster->boundary[cluster->nr] = extent_key->objectid;
 	cluster->nr++;
+	cluster->total_bytes += extent_key->offset;
 
 	if (cluster->nr >= MAX_EXTENTS) {
 		ret = relocate_file_extent_cluster(inode, cluster);
 		if (ret)
 			return ret;
 		cluster->nr = 0;
+		cluster->total_bytes = 0;
 	}
 	return 0;
 }
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group
  2020-06-09 10:19 [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group fdmanana
@ 2020-06-09 10:50 ` Nikolay Borisov
  2020-06-09 10:57   ` Filipe Manana
  2020-06-09 12:07 ` kernel test robot
  1 sibling, 1 reply; 5+ messages in thread
From: Nikolay Borisov @ 2020-06-09 10:50 UTC (permalink / raw)
  To: fdmanana, linux-btrfs



On 9.06.20 г. 13:19 ч., fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> When relocating a data block group we group extents from the block group
> into a cluster and when the cluster reaches a certain number of extents
> we do the relocation.

We don't reserve more space because the cluster is guaranteed to contain
contiguous extents, namely in relocate_data_extent we have:

if (cluster->nr > 0 && extent_key->objectid != cluster->end + 1)
{
   ret = relocate_file_extent_cluster(inode, cluster);
   if (ret)
      return ret;
   cluster->nr = 0;
}

Cluster->end points to the end offset of the last added extent and the
check above ensures that the one which is currently added is also
contiguous. So relocate_file_extent_cluster is always called with
contiguous range of data extents, which might actually be less than
MAX_EXTENTS.

As a matter of fact this is a rather hard requirement since
prealloc_file_extent_cluster assumes that since when it iterates the
extents in the cluster it does:

if (nr + 1 < cluster->nr)

   end = cluster->boundary[nr + 1] - 1 - offset;

else

   end = cluster->end - offset;

If those extents weren't contiguous we'd be preallocating more space in
the data reloc inode.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group
  2020-06-09 10:50 ` Nikolay Borisov
@ 2020-06-09 10:57   ` Filipe Manana
  2020-06-09 11:28     ` Nikolay Borisov
  0 siblings, 1 reply; 5+ messages in thread
From: Filipe Manana @ 2020-06-09 10:57 UTC (permalink / raw)
  To: Nikolay Borisov; +Cc: linux-btrfs

On Tue, Jun 9, 2020 at 11:50 AM Nikolay Borisov <nborisov@suse.com> wrote:
>
>
>
> On 9.06.20 г. 13:19 ч., fdmanana@kernel.org wrote:
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > When relocating a data block group we group extents from the block group
> > into a cluster and when the cluster reaches a certain number of extents
> > we do the relocation.
>
> We don't reserve more space because the cluster is guaranteed to contain
> contiguous extents, namely in relocate_data_extent we have:
>
> if (cluster->nr > 0 && extent_key->objectid != cluster->end + 1)
> {
>    ret = relocate_file_extent_cluster(inode, cluster);
>    if (ret)
>       return ret;
>    cluster->nr = 0;
> }
>
> Cluster->end points to the end offset of the last added extent and the
> check above ensures that the one which is currently added is also
> contiguous. So relocate_file_extent_cluster is always called with
> contiguous range of data extents, which might actually be less than
> MAX_EXTENTS.
>
> As a matter of fact this is a rather hard requirement since
> prealloc_file_extent_cluster assumes that since when it iterates the
> extents in the cluster it does:
>
> if (nr + 1 < cluster->nr)
>
>    end = cluster->boundary[nr + 1] - 1 - offset;
>
> else
>
>    end = cluster->end - offset;
>
> If those extents weren't contiguous we'd be preallocating more space in
> the data reloc inode.

Yes, thanks.
I was biased by the gap detection at prealloc_file_extent_cluster()
and missed that, which in this case can't happen.

So lets drop this.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group
  2020-06-09 10:57   ` Filipe Manana
@ 2020-06-09 11:28     ` Nikolay Borisov
  0 siblings, 0 replies; 5+ messages in thread
From: Nikolay Borisov @ 2020-06-09 11:28 UTC (permalink / raw)
  To: Filipe Manana; +Cc: linux-btrfs



On 9.06.20 г. 13:57 ч., Filipe Manana wrote:
> On Tue, Jun 9, 2020 at 11:50 AM Nikolay Borisov <nborisov@suse.com> wrote:
>>
>>
>>
>> On 9.06.20 г. 13:19 ч., fdmanana@kernel.org wrote:
>>> From: Filipe Manana <fdmanana@suse.com>
>>>
>>> When relocating a data block group we group extents from the block group
>>> into a cluster and when the cluster reaches a certain number of extents
>>> we do the relocation.
>>
>> We don't reserve more space because the cluster is guaranteed to contain
>> contiguous extents, namely in relocate_data_extent we have:
>>
>> if (cluster->nr > 0 && extent_key->objectid != cluster->end + 1)
>> {
>>    ret = relocate_file_extent_cluster(inode, cluster);
>>    if (ret)
>>       return ret;
>>    cluster->nr = 0;
>> }
>>
>> Cluster->end points to the end offset of the last added extent and the
>> check above ensures that the one which is currently added is also
>> contiguous. So relocate_file_extent_cluster is always called with
>> contiguous range of data extents, which might actually be less than
>> MAX_EXTENTS.
>>
>> As a matter of fact this is a rather hard requirement since
>> prealloc_file_extent_cluster assumes that since when it iterates the
>> extents in the cluster it does:
>>
>> if (nr + 1 < cluster->nr)
>>
>>    end = cluster->boundary[nr + 1] - 1 - offset;
>>
>> else
>>
>>    end = cluster->end - offset;
>>
>> If those extents weren't contiguous we'd be preallocating more space in
>> the data reloc inode.
> 
> Yes, thanks.
> I was biased by the gap detection at prealloc_file_extent_cluster()
> and missed that, which in this case can't happen.
> 
> So lets drop this.
> 

Thinking a bit more about this the following check is redundant, since
extents are guaranteed to be contiguous:


if (cur_offset < start)

   btrfs_free_reserved_data_space(inode, data_reserved,

                                        cur_offset, start - cur_offset);



This was added as part of 18513091af948 but IMO it's bogus since
clustered data extent reloc landed much earlier, in
0257bb82d21bedff26541bcf12f1461c23f9ed61. A good cleanup would be to
simply remove this check.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group
  2020-06-09 10:19 [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group fdmanana
  2020-06-09 10:50 ` Nikolay Borisov
@ 2020-06-09 12:07 ` kernel test robot
  1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2020-06-09 12:07 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5930 bytes --]

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on kdave/for-next]
[also build test WARNING on v5.7 next-20200608]
[cannot apply to btrfs/next]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/fdmanana-kernel-org/Btrfs-remove-the-start-argument-from-btrfs_free_reserved_data_space_noquota/20200609-182248
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
config: nios2-allyesconfig (attached as .config)
compiler: nios2-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=nios2 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>, old ones prefixed by <<):

In file included from fs/btrfs/relocation.c:13:
fs/btrfs/ctree.h:2216:8: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
2216 | size_t __const btrfs_get_num_csums(void);
|        ^~~~~~~
fs/btrfs/relocation.c: In function 'prealloc_file_extent_cluster':
>> fs/btrfs/relocation.c:2587:6: warning: variable 'cur_offset' set but not used [-Wunused-but-set-variable]
2587 |  u64 cur_offset;
|      ^~~~~~~~~~

vim +/cur_offset +2587 fs/btrfs/relocation.c

5d4f98a28c7d33 Yan Zheng      2009-06-10  2574  
efa56464562991 Yan, Zheng     2010-05-16  2575  static noinline_for_stack
efa56464562991 Yan, Zheng     2010-05-16  2576  int prealloc_file_extent_cluster(struct inode *inode,
efa56464562991 Yan, Zheng     2010-05-16  2577  				 struct file_extent_cluster *cluster)
efa56464562991 Yan, Zheng     2010-05-16  2578  {
efa56464562991 Yan, Zheng     2010-05-16  2579  	u64 alloc_hint = 0;
efa56464562991 Yan, Zheng     2010-05-16  2580  	u64 start;
efa56464562991 Yan, Zheng     2010-05-16  2581  	u64 end;
efa56464562991 Yan, Zheng     2010-05-16  2582  	u64 offset = BTRFS_I(inode)->index_cnt;
efa56464562991 Yan, Zheng     2010-05-16  2583  	u64 num_bytes;
efa56464562991 Yan, Zheng     2010-05-16  2584  	int nr = 0;
efa56464562991 Yan, Zheng     2010-05-16  2585  	int ret = 0;
dcb40c196fc85c Wang Xiaoguang 2016-07-25  2586  	u64 prealloc_start = cluster->start - offset;
18513091af9483 Wang Xiaoguang 2016-07-25 @2587  	u64 cur_offset;
eb4d9ef455539b Filipe Manana  2020-06-09  2588  	u64 allocated = 0;
efa56464562991 Yan, Zheng     2010-05-16  2589  
efa56464562991 Yan, Zheng     2010-05-16  2590  	BUG_ON(cluster->start != cluster->boundary[0]);
5955102c9984fa Al Viro        2016-01-22  2591  	inode_lock(inode);
efa56464562991 Yan, Zheng     2010-05-16  2592  
8fa95e39f0371b Filipe Manana  2020-06-09  2593  	ret = btrfs_alloc_data_chunk_ondemand(BTRFS_I(inode),
eb4d9ef455539b Filipe Manana  2020-06-09  2594  					      cluster->total_bytes);
efa56464562991 Yan, Zheng     2010-05-16  2595  	if (ret)
efa56464562991 Yan, Zheng     2010-05-16  2596  		goto out;
efa56464562991 Yan, Zheng     2010-05-16  2597  
18513091af9483 Wang Xiaoguang 2016-07-25  2598  	cur_offset = prealloc_start;
efa56464562991 Yan, Zheng     2010-05-16  2599  	while (nr < cluster->nr) {
efa56464562991 Yan, Zheng     2010-05-16  2600  		start = cluster->boundary[nr] - offset;
efa56464562991 Yan, Zheng     2010-05-16  2601  		if (nr + 1 < cluster->nr)
efa56464562991 Yan, Zheng     2010-05-16  2602  			end = cluster->boundary[nr + 1] - 1 - offset;
efa56464562991 Yan, Zheng     2010-05-16  2603  		else
efa56464562991 Yan, Zheng     2010-05-16  2604  			end = cluster->end - offset;
efa56464562991 Yan, Zheng     2010-05-16  2605  
d0082371cf086e Jeff Mahoney   2012-03-01  2606  		lock_extent(&BTRFS_I(inode)->io_tree, start, end);
efa56464562991 Yan, Zheng     2010-05-16  2607  		num_bytes = end + 1 - start;
efa56464562991 Yan, Zheng     2010-05-16  2608  		ret = btrfs_prealloc_file_range(inode, 0, start,
efa56464562991 Yan, Zheng     2010-05-16  2609  						num_bytes, num_bytes,
efa56464562991 Yan, Zheng     2010-05-16  2610  						end + 1, &alloc_hint);
18513091af9483 Wang Xiaoguang 2016-07-25  2611  		cur_offset = end + 1;
eb4d9ef455539b Filipe Manana  2020-06-09  2612  		allocated += num_bytes;
d0082371cf086e Jeff Mahoney   2012-03-01  2613  		unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
efa56464562991 Yan, Zheng     2010-05-16  2614  		if (ret)
efa56464562991 Yan, Zheng     2010-05-16  2615  			break;
efa56464562991 Yan, Zheng     2010-05-16  2616  		nr++;
efa56464562991 Yan, Zheng     2010-05-16  2617  	}
eb4d9ef455539b Filipe Manana  2020-06-09  2618  	if (allocated < cluster->total_bytes)
8fa95e39f0371b Filipe Manana  2020-06-09  2619  		btrfs_free_reserved_data_space_noquota(inode,
eb4d9ef455539b Filipe Manana  2020-06-09  2620  				       cluster->total_bytes - allocated);
efa56464562991 Yan, Zheng     2010-05-16  2621  out:
5955102c9984fa Al Viro        2016-01-22  2622  	inode_unlock(inode);
efa56464562991 Yan, Zheng     2010-05-16  2623  	return ret;
efa56464562991 Yan, Zheng     2010-05-16  2624  }
efa56464562991 Yan, Zheng     2010-05-16  2625  

:::::: The code at line 2587 was first introduced by commit
:::::: 18513091af9483ba84328d42092bd4d42a3c958f btrfs: update btrfs_space_info's bytes_may_use timely

:::::: TO: Wang Xiaoguang <wangxg.fnst@cn.fujitsu.com>
:::::: CC: Chris Mason <clm@fb.com>

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 55376 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-06-09 12:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-09 10:19 [PATCH 3/3] Btrfs: only allocate necessary space when relocating a data block group fdmanana
2020-06-09 10:50 ` Nikolay Borisov
2020-06-09 10:57   ` Filipe Manana
2020-06-09 11:28     ` Nikolay Borisov
2020-06-09 12:07 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.