All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
@ 2018-03-08  7:02 Qu Wenruo
  2018-03-08 14:05 ` Nikolay Borisov
  2018-03-09 15:49 ` David Sterba
  0 siblings, 2 replies; 6+ messages in thread
From: Qu Wenruo @ 2018-03-08  7:02 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

When we found free space difference between free space cache and block
group item, we just discard this free space cache.

Normally such difference is caused by btrfs_reserve_extent() called by
delalloc which is out of a transaction.
And since all btrfs_release_extent() is called with a transaction, under
heavy race free space cache can have less free space than block group
item.

Normally kernel will detect such difference and just discard that cache.

However we must be more careful if free space cache has more free space
cache, and if that happens, paried with above race one invalid free
space cache can be loaded into kernel.

So if we find any free space cache who has more free space then block
group item, we report it as an error other than ignoring it.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
v2:
  Fix the timming of free space output.
---
 check/main.c       |  4 +++-
 free-space-cache.c | 32 ++++++++++++++++++++++++--------
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/check/main.c b/check/main.c
index 97baae583f04..bc31f7e32061 100644
--- a/check/main.c
+++ b/check/main.c
@@ -5339,7 +5339,9 @@ static int check_space_cache(struct btrfs_root *root)
 			error += ret;
 		} else {
 			ret = load_free_space_cache(root->fs_info, cache);
-			if (!ret)
+			if (ret < 0)
+				error++;
+			if (ret <= 0)
 				continue;
 		}
 
diff --git a/free-space-cache.c b/free-space-cache.c
index f933f9f1cf3f..9b83a71ca59a 100644
--- a/free-space-cache.c
+++ b/free-space-cache.c
@@ -438,7 +438,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
 	struct btrfs_path *path;
 	u64 used = btrfs_block_group_used(&block_group->item);
 	int ret = 0;
-	int matched;
+	u64 bg_free;
+	s64 diff;
 
 	path = btrfs_alloc_path();
 	if (!path)
@@ -448,18 +449,33 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
 				      block_group->key.objectid);
 	btrfs_free_path(path);
 
-	matched = (ctl->free_space == (block_group->key.offset - used -
-				       block_group->bytes_super));
-	if (ret == 1 && !matched) {
-		__btrfs_remove_free_space_cache(ctl);
+	bg_free = block_group->key.offset - used - block_group->bytes_super;
+	diff = ctl->free_space - bg_free;
+	if (ret == 1 && diff) {
 		fprintf(stderr,
-		       "block group %llu has wrong amount of free space\n",
-		       block_group->key.objectid);
+		       "block group %llu has wrong amount of free space, free space cache has %llu block group has %llu\n",
+		       block_group->key.objectid, ctl->free_space, bg_free);
+		__btrfs_remove_free_space_cache(ctl);
+		/*
+		 * Due to btrfs_reserve_extent() can happen out of a
+		 * transaction, but all btrfs_release_extent() happens inside
+		 * a transaction, so under heavy race it's possible that free
+		 * space cache has less free space, and both kernel just discard
+		 * such cache. But if we find some case where free space cache
+		 * has more free space, this means under certain case such
+		 * cache can be loaded and cause double allocate.
+		 *
+		 * Detect such possibility here.
+		 */
+		if (diff > 0)
+			error(
+"free space cache has more free space than block group item, this could leads to serious corruption, please contact btrfs developers");
 		ret = -1;
 	}
 
 	if (ret < 0) {
-		ret = 0;
+		if (diff <= 0)
+			ret = 0;
 
 		fprintf(stderr,
 		       "failed to load free space cache for block group %llu\n",
-- 
2.16.2


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

* Re: [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
  2018-03-08  7:02 [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check Qu Wenruo
@ 2018-03-08 14:05 ` Nikolay Borisov
  2018-03-08 23:27   ` Qu Wenruo
  2018-03-09 15:49 ` David Sterba
  1 sibling, 1 reply; 6+ messages in thread
From: Nikolay Borisov @ 2018-03-08 14:05 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs; +Cc: dsterba



On  8.03.2018 09:02, Qu Wenruo wrote:
> When we found free space difference between free space cache and block
> group item, we just discard this free space cache.
> 
> Normally such difference is caused by btrfs_reserve_extent() called by
> delalloc which is out of a transaction.
> And since all btrfs_release_extent() is called with a transaction, under
> heavy race free space cache can have less free space than block group
> item.
> 
> Normally kernel will detect such difference and just discard that cache.
> 
> However we must be more careful if free space cache has more free space
> cache, and if that happens, paried with above race one invalid free
> space cache can be loaded into kernel.
> 
> So if we find any free space cache who has more free space then block
> group item, we report it as an error other than ignoring it.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> v2:
>   Fix the timming of free space output.
> ---
>  check/main.c       |  4 +++-
>  free-space-cache.c | 32 ++++++++++++++++++++++++--------
>  2 files changed, 27 insertions(+), 9 deletions(-)
> 
> diff --git a/check/main.c b/check/main.c
> index 97baae583f04..bc31f7e32061 100644
> --- a/check/main.c
> +++ b/check/main.c
> @@ -5339,7 +5339,9 @@ static int check_space_cache(struct btrfs_root *root)
>  			error += ret;
>  		} else {
>  			ret = load_free_space_cache(root->fs_info, cache);
> -			if (!ret)
> +			if (ret < 0)
> +				error++;
> +			if (ret <= 0)
>  				continue;
>  		}
>  
> diff --git a/free-space-cache.c b/free-space-cache.c
> index f933f9f1cf3f..9b83a71ca59a 100644
> --- a/free-space-cache.c
> +++ b/free-space-cache.c
> @@ -438,7 +438,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>  	struct btrfs_path *path;
>  	u64 used = btrfs_block_group_used(&block_group->item);
>  	int ret = 0;
> -	int matched;
> +	u64 bg_free;
> +	s64 diff;
>  
>  	path = btrfs_alloc_path();
>  	if (!path)
> @@ -448,18 +449,33 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>  				      block_group->key.objectid);
>  	btrfs_free_path(path);
>  
> -	matched = (ctl->free_space == (block_group->key.offset - used -
> -				       block_group->bytes_super));
> -	if (ret == 1 && !matched) {
> -		__btrfs_remove_free_space_cache(ctl);
> +	bg_free = block_group->key.offset - used - block_group->bytes_super;
> +	diff = ctl->free_space - bg_free;
> +	if (ret == 1 && diff) {
>  		fprintf(stderr,
> -		       "block group %llu has wrong amount of free space\n",
> -		       block_group->key.objectid);
> +		       "block group %llu has wrong amount of free space, free space cache has %llu block group has %llu\n",nit: Always put units when printing numbers. In this case we are talking
about bytes.
> +		       block_group->key.objectid, ctl->free_space, bg_free);
> +		__btrfs_remove_free_space_cache(ctl);
> +		/*
> +		 * Due to btrfs_reserve_extent() can happen out of > +		 * transaction, but all btrfs_release_extent() happens inside
> +		 * a transaction, so under heavy race it's possible that free
> +		 * space cache has less free space, and both kernel just discard
> +		 * such cache. But if we find some case where free space cache
> +		 * has more free space, this means under certain case such
> +		 * cache can be loaded and cause double allocate.
> +		 *
> +		 * Detect such possibility here.
> +		 */
> +		if (diff > 0)
> +			error(
> +"free space cache has more free space than block group item, this could leads to serious corruption, please contact btrfs developers");

I'm not entirely happy with this message. So they will post to the
mailing list saying something along the lines of "I got this message
what do I do no, please help".  Better to output actionable data so that
the user can post it immediately.

>  		ret = -1;
>  	}
>  
>  	if (ret < 0) {
> -		ret = 0;
> +		if (diff <= 0)
> +			ret = 0;
>  
>  		fprintf(stderr,
>  		       "failed to load free space cache for block group %llu\n",
> 

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

* Re: [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
  2018-03-08 14:05 ` Nikolay Borisov
@ 2018-03-08 23:27   ` Qu Wenruo
  2018-03-09  8:06     ` Nikolay Borisov
  0 siblings, 1 reply; 6+ messages in thread
From: Qu Wenruo @ 2018-03-08 23:27 UTC (permalink / raw)
  To: Nikolay Borisov, linux-btrfs; +Cc: dsterba


[-- Attachment #1.1: Type: text/plain, Size: 4457 bytes --]



On 2018年03月08日 22:05, Nikolay Borisov wrote:
> 
> 
> On  8.03.2018 09:02, Qu Wenruo wrote:
>> When we found free space difference between free space cache and block
>> group item, we just discard this free space cache.
>>
>> Normally such difference is caused by btrfs_reserve_extent() called by
>> delalloc which is out of a transaction.
>> And since all btrfs_release_extent() is called with a transaction, under
>> heavy race free space cache can have less free space than block group
>> item.
>>
>> Normally kernel will detect such difference and just discard that cache.
>>
>> However we must be more careful if free space cache has more free space
>> cache, and if that happens, paried with above race one invalid free
>> space cache can be loaded into kernel.
>>
>> So if we find any free space cache who has more free space then block
>> group item, we report it as an error other than ignoring it.
>>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>> v2:
>>   Fix the timming of free space output.
>> ---
>>  check/main.c       |  4 +++-
>>  free-space-cache.c | 32 ++++++++++++++++++++++++--------
>>  2 files changed, 27 insertions(+), 9 deletions(-)
>>
>> diff --git a/check/main.c b/check/main.c
>> index 97baae583f04..bc31f7e32061 100644
>> --- a/check/main.c
>> +++ b/check/main.c
>> @@ -5339,7 +5339,9 @@ static int check_space_cache(struct btrfs_root *root)
>>  			error += ret;
>>  		} else {
>>  			ret = load_free_space_cache(root->fs_info, cache);
>> -			if (!ret)
>> +			if (ret < 0)
>> +				error++;
>> +			if (ret <= 0)
>>  				continue;
>>  		}
>>  
>> diff --git a/free-space-cache.c b/free-space-cache.c
>> index f933f9f1cf3f..9b83a71ca59a 100644
>> --- a/free-space-cache.c
>> +++ b/free-space-cache.c
>> @@ -438,7 +438,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>>  	struct btrfs_path *path;
>>  	u64 used = btrfs_block_group_used(&block_group->item);
>>  	int ret = 0;
>> -	int matched;
>> +	u64 bg_free;
>> +	s64 diff;
>>  
>>  	path = btrfs_alloc_path();
>>  	if (!path)
>> @@ -448,18 +449,33 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>>  				      block_group->key.objectid);
>>  	btrfs_free_path(path);
>>  
>> -	matched = (ctl->free_space == (block_group->key.offset - used -
>> -				       block_group->bytes_super));
>> -	if (ret == 1 && !matched) {
>> -		__btrfs_remove_free_space_cache(ctl);
>> +	bg_free = block_group->key.offset - used - block_group->bytes_super;
>> +	diff = ctl->free_space - bg_free;
>> +	if (ret == 1 && diff) {
>>  		fprintf(stderr,
>> -		       "block group %llu has wrong amount of free space\n",
>> -		       block_group->key.objectid);
>> +		       "block group %llu has wrong amount of free space, free space cache has %llu block group has %llu\n",nit: Always put units when printing numbers. In this case we are talking
> about bytes.
>> +		       block_group->key.objectid, ctl->free_space, bg_free);
>> +		__btrfs_remove_free_space_cache(ctl);
>> +		/*
>> +		 * Due to btrfs_reserve_extent() can happen out of > +		 * transaction, but all btrfs_release_extent() happens inside
>> +		 * a transaction, so under heavy race it's possible that free
>> +		 * space cache has less free space, and both kernel just discard
>> +		 * such cache. But if we find some case where free space cache
>> +		 * has more free space, this means under certain case such
>> +		 * cache can be loaded and cause double allocate.
>> +		 *
>> +		 * Detect such possibility here.
>> +		 */
>> +		if (diff > 0)
>> +			error(
>> +"free space cache has more free space than block group item, this could leads to serious corruption, please contact btrfs developers");
> 
> I'm not entirely happy with this message. So they will post to the
> mailing list saying something along the lines of "I got this message
> what do I do no, please help".  Better to output actionable data so that
> the user can post it immediately.

Unfortunately, this is already the situation we don't expect to see.

What we really need is to know this could happen, and if possible some
info about the situation.
There is not much actionable data here.

Thanks,
Qu

> 
>>  		ret = -1;
>>  	}
>>  
>>  	if (ret < 0) {
>> -		ret = 0;
>> +		if (diff <= 0)
>> +			ret = 0;
>>  
>>  		fprintf(stderr,
>>  		       "failed to load free space cache for block group %llu\n",
>>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 504 bytes --]

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

* Re: [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
  2018-03-08 23:27   ` Qu Wenruo
@ 2018-03-09  8:06     ` Nikolay Borisov
  2018-03-09 15:48       ` David Sterba
  0 siblings, 1 reply; 6+ messages in thread
From: Nikolay Borisov @ 2018-03-09  8:06 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs; +Cc: dsterba



On  9.03.2018 01:27, Qu Wenruo wrote:
> 
> 
> On 2018年03月08日 22:05, Nikolay Borisov wrote:
>>
>>
>> On  8.03.2018 09:02, Qu Wenruo wrote:
>>> When we found free space difference between free space cache and block
>>> group item, we just discard this free space cache.
>>>
>>> Normally such difference is caused by btrfs_reserve_extent() called by
>>> delalloc which is out of a transaction.
>>> And since all btrfs_release_extent() is called with a transaction, under
>>> heavy race free space cache can have less free space than block group
>>> item.
>>>
>>> Normally kernel will detect such difference and just discard that cache.
>>>
>>> However we must be more careful if free space cache has more free space
>>> cache, and if that happens, paried with above race one invalid free
>>> space cache can be loaded into kernel.
>>>
>>> So if we find any free space cache who has more free space then block
>>> group item, we report it as an error other than ignoring it.
>>>
>>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>>> ---
>>> v2:
>>>   Fix the timming of free space output.
>>> ---
>>>  check/main.c       |  4 +++-
>>>  free-space-cache.c | 32 ++++++++++++++++++++++++--------
>>>  2 files changed, 27 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/check/main.c b/check/main.c
>>> index 97baae583f04..bc31f7e32061 100644
>>> --- a/check/main.c
>>> +++ b/check/main.c
>>> @@ -5339,7 +5339,9 @@ static int check_space_cache(struct btrfs_root *root)
>>>  			error += ret;
>>>  		} else {
>>>  			ret = load_free_space_cache(root->fs_info, cache);
>>> -			if (!ret)
>>> +			if (ret < 0)
>>> +				error++;
>>> +			if (ret <= 0)
>>>  				continue;
>>>  		}
>>>  
>>> diff --git a/free-space-cache.c b/free-space-cache.c
>>> index f933f9f1cf3f..9b83a71ca59a 100644
>>> --- a/free-space-cache.c
>>> +++ b/free-space-cache.c
>>> @@ -438,7 +438,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>>>  	struct btrfs_path *path;
>>>  	u64 used = btrfs_block_group_used(&block_group->item);
>>>  	int ret = 0;
>>> -	int matched;
>>> +	u64 bg_free;
>>> +	s64 diff;
>>>  
>>>  	path = btrfs_alloc_path();
>>>  	if (!path)
>>> @@ -448,18 +449,33 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
>>>  				      block_group->key.objectid);
>>>  	btrfs_free_path(path);
>>>  
>>> -	matched = (ctl->free_space == (block_group->key.offset - used -
>>> -				       block_group->bytes_super));
>>> -	if (ret == 1 && !matched) {
>>> -		__btrfs_remove_free_space_cache(ctl);
>>> +	bg_free = block_group->key.offset - used - block_group->bytes_super;
>>> +	diff = ctl->free_space - bg_free;
>>> +	if (ret == 1 && diff) {
>>>  		fprintf(stderr,
>>> -		       "block group %llu has wrong amount of free space\n",
>>> -		       block_group->key.objectid);
>>> +		       "block group %llu has wrong amount of free space, free space cache has %llu block group has %llu\n",nit: Always put units when printing numbers. In this case we are talking
>> about bytes.
>>> +		       block_group->key.objectid, ctl->free_space, bg_free);
>>> +		__btrfs_remove_free_space_cache(ctl);
>>> +		/*
>>> +		 * Due to btrfs_reserve_extent() can happen out of > +		 * transaction, but all btrfs_release_extent() happens inside
>>> +		 * a transaction, so under heavy race it's possible that free
>>> +		 * space cache has less free space, and both kernel just discard
>>> +		 * such cache. But if we find some case where free space cache
>>> +		 * has more free space, this means under certain case such
>>> +		 * cache can be loaded and cause double allocate.
>>> +		 *
>>> +		 * Detect such possibility here.
>>> +		 */
>>> +		if (diff > 0)
>>> +			error(
>>> +"free space cache has more free space than block group item, this could leads to serious corruption, please contact btrfs developers");
>>
>> I'm not entirely happy with this message. So they will post to the
>> mailing list saying something along the lines of "I got this message
>> what do I do no, please help".  Better to output actionable data so that
>> the user can post it immediately.
> 
> Unfortunately, this is already the situation we don't expect to see.
> 
> What we really need is to know this could happen, and if possible some
> info about the situation.
> There is not much actionable data here.

Fair enough, at the very least I think we should put information how to
contact btrfs developers. So put the address of the mailing list, I
don't think it's safe to assume people will be aware of it .

> 
> Thanks,
> Qu
> 
>>
>>>  		ret = -1;
>>>  	}
>>>  
>>>  	if (ret < 0) {
>>> -		ret = 0;
>>> +		if (diff <= 0)
>>> +			ret = 0;
>>>  
>>>  		fprintf(stderr,
>>>  		       "failed to load free space cache for block group %llu\n",
>>>
> 

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

* Re: [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
  2018-03-09  8:06     ` Nikolay Borisov
@ 2018-03-09 15:48       ` David Sterba
  0 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2018-03-09 15:48 UTC (permalink / raw)
  To: Nikolay Borisov; +Cc: Qu Wenruo, linux-btrfs, dsterba

On Fri, Mar 09, 2018 at 10:06:02AM +0200, Nikolay Borisov wrote:
> >>> +		 * space cache has less free space, and both kernel just discard
> >>> +		 * such cache. But if we find some case where free space cache
> >>> +		 * has more free space, this means under certain case such
> >>> +		 * cache can be loaded and cause double allocate.
> >>> +		 *
> >>> +		 * Detect such possibility here.
> >>> +		 */
> >>> +		if (diff > 0)
> >>> +			error(
> >>> +"free space cache has more free space than block group item, this could leads to serious corruption, please contact btrfs developers");
> >>
> >> I'm not entirely happy with this message. So they will post to the
> >> mailing list saying something along the lines of "I got this message
> >> what do I do no, please help".  Better to output actionable data so that
> >> the user can post it immediately.
> > 
> > Unfortunately, this is already the situation we don't expect to see.
> > 
> > What we really need is to know this could happen, and if possible some
> > info about the situation.
> > There is not much actionable data here.
> 
> Fair enough, at the very least I think we should put information how to
> contact btrfs developers. So put the address of the mailing list, I
> don't think it's safe to assume people will be aware of it .

This should go to the manual page or help string, and reference it from
here.

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

* Re: [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check
  2018-03-08  7:02 [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check Qu Wenruo
  2018-03-08 14:05 ` Nikolay Borisov
@ 2018-03-09 15:49 ` David Sterba
  1 sibling, 0 replies; 6+ messages in thread
From: David Sterba @ 2018-03-09 15:49 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs, dsterba

On Thu, Mar 08, 2018 at 03:02:31PM +0800, Qu Wenruo wrote:
> When we found free space difference between free space cache and block
> group item, we just discard this free space cache.
> 
> Normally such difference is caused by btrfs_reserve_extent() called by
> delalloc which is out of a transaction.
> And since all btrfs_release_extent() is called with a transaction, under
> heavy race free space cache can have less free space than block group
> item.
> 
> Normally kernel will detect such difference and just discard that cache.
> 
> However we must be more careful if free space cache has more free space
> cache, and if that happens, paried with above race one invalid free
> space cache can be loaded into kernel.
> 
> So if we find any free space cache who has more free space then block
> group item, we report it as an error other than ignoring it.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> v2:
>   Fix the timming of free space output.

I'll apply the v2 patch, thanks. The message can be updated with manual
page together.

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

end of thread, other threads:[~2018-03-09 15:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-08  7:02 [PATCH v2] btrfs-progs: free-space-cache: Enhance free space cache free space check Qu Wenruo
2018-03-08 14:05 ` Nikolay Borisov
2018-03-08 23:27   ` Qu Wenruo
2018-03-09  8:06     ` Nikolay Borisov
2018-03-09 15:48       ` David Sterba
2018-03-09 15:49 ` David Sterba

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.