[v3,3/6] f2fs: compress: fix to check unreleased compressed cluster

Message ID 20231228143152.1543509-3-chao@kernel.org
State New
Headers
Series [v3,1/6] f2fs: compress: fix to guarantee persisting compressed blocks by CP |

Commit Message

Chao Yu Dec. 28, 2023, 2:31 p.m. UTC
  From: Sheng Yong <shengyong@oppo.com>

Compressed cluster may not be released due to we can fail in
release_compress_blocks(), fix to handle reserved compressed
cluster correctly in reserve_compress_blocks().

Fixes: 4c8ff7095bef ("f2fs: support data compression")
Signed-off-by: Sheng Yong <shengyong@oppo.com>
Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/file.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
  

Comments

Daeho Jeong Jan. 11, 2024, 1:18 a.m. UTC | #1
On Thu, Dec 28, 2023 at 6:33 AM Chao Yu <chao@kernel.org> wrote:
>
> From: Sheng Yong <shengyong@oppo.com>
>
> Compressed cluster may not be released due to we can fail in
> release_compress_blocks(), fix to handle reserved compressed
> cluster correctly in reserve_compress_blocks().
>
> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> Signed-off-by: Sheng Yong <shengyong@oppo.com>
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
>  fs/f2fs/file.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 026d05a7edd8..782ae3be48f6 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -3624,6 +3624,15 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>                                 goto next;
>                         }
>
> +                       /*
> +                        * compressed cluster was not released due to
> +                        * it fails in release_compress_blocks().
> +                        */
> +                       if (blkaddr == NEW_ADDR) {
> +                               compr_blocks++;
> +                               continue;
> +                       }
> +
>                         if (__is_valid_data_blkaddr(blkaddr)) {
>                                 compr_blocks++;
>                                 continue;

How about merging two conditions like "blkaddr == NEW_ADDR ||
__is_valid_data_blkaddr(blkaddr)"?

> @@ -3633,6 +3642,9 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>                 }
>
>                 reserved = cluster_size - compr_blocks;
> +               if (!reserved)
> +                       goto next;
> +

How can the reserved variable be zero?

>                 ret = inc_valid_block_count(sbi, dn->inode, &reserved);
>                 if (ret)
>                         return ret;
> --
> 2.40.1
>
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
  
Chao Yu Jan. 11, 2024, 1:33 a.m. UTC | #2
On 2024/1/11 9:18, Daeho Jeong wrote:
> On Thu, Dec 28, 2023 at 6:33 AM Chao Yu <chao@kernel.org> wrote:
>>
>> From: Sheng Yong <shengyong@oppo.com>
>>
>> Compressed cluster may not be released due to we can fail in
>> release_compress_blocks(), fix to handle reserved compressed
>> cluster correctly in reserve_compress_blocks().
>>
>> Fixes: 4c8ff7095bef ("f2fs: support data compression")
>> Signed-off-by: Sheng Yong <shengyong@oppo.com>
>> Signed-off-by: Chao Yu <chao@kernel.org>
>> ---
>>   fs/f2fs/file.c | 12 ++++++++++++
>>   1 file changed, 12 insertions(+)
>>
>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>> index 026d05a7edd8..782ae3be48f6 100644
>> --- a/fs/f2fs/file.c
>> +++ b/fs/f2fs/file.c
>> @@ -3624,6 +3624,15 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>>                                  goto next;
>>                          }
>>
>> +                       /*
>> +                        * compressed cluster was not released due to
>> +                        * it fails in release_compress_blocks().
>> +                        */
>> +                       if (blkaddr == NEW_ADDR) {
>> +                               compr_blocks++;
>> +                               continue;
>> +                       }
>> +
>>                          if (__is_valid_data_blkaddr(blkaddr)) {
>>                                  compr_blocks++;
>>                                  continue;
> 
> How about merging two conditions like "blkaddr == NEW_ADDR ||
> __is_valid_data_blkaddr(blkaddr)"?

Oh, sure.

> 
>> @@ -3633,6 +3642,9 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>>                  }
>>
>>                  reserved = cluster_size - compr_blocks;
>> +               if (!reserved)
>> +                       goto next;
>> +
> 
> How can the reserved variable be zero?

I guess it can happen if a cluster was not released during
release_compress_blocks(), then all blocks in the cluster should
has been reserved, so, in this round of reserving, it needs to skip
reserve blocks, right?

Thanks,

> 
>>                  ret = inc_valid_block_count(sbi, dn->inode, &reserved);
>>                  if (ret)
>>                          return ret;
>> --
>> 2.40.1
>>
>>
>>
>> _______________________________________________
>> Linux-f2fs-devel mailing list
>> Linux-f2fs-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
  
Daeho Jeong Jan. 11, 2024, 5:15 p.m. UTC | #3
On Wed, Jan 10, 2024 at 5:33 PM Chao Yu <chao@kernel.org> wrote:
>
> On 2024/1/11 9:18, Daeho Jeong wrote:
> > On Thu, Dec 28, 2023 at 6:33 AM Chao Yu <chao@kernel.org> wrote:
> >>
> >> From: Sheng Yong <shengyong@oppo.com>
> >>
> >> Compressed cluster may not be released due to we can fail in
> >> release_compress_blocks(), fix to handle reserved compressed
> >> cluster correctly in reserve_compress_blocks().
> >>
> >> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> >> Signed-off-by: Sheng Yong <shengyong@oppo.com>
> >> Signed-off-by: Chao Yu <chao@kernel.org>
> >> ---
> >>   fs/f2fs/file.c | 12 ++++++++++++
> >>   1 file changed, 12 insertions(+)
> >>
> >> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> >> index 026d05a7edd8..782ae3be48f6 100644
> >> --- a/fs/f2fs/file.c
> >> +++ b/fs/f2fs/file.c
> >> @@ -3624,6 +3624,15 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> >>                                  goto next;
> >>                          }
> >>
> >> +                       /*
> >> +                        * compressed cluster was not released due to
> >> +                        * it fails in release_compress_blocks().
> >> +                        */
> >> +                       if (blkaddr == NEW_ADDR) {
> >> +                               compr_blocks++;
> >> +                               continue;
> >> +                       }
> >> +
> >>                          if (__is_valid_data_blkaddr(blkaddr)) {
> >>                                  compr_blocks++;
> >>                                  continue;
> >
> > How about merging two conditions like "blkaddr == NEW_ADDR ||
> > __is_valid_data_blkaddr(blkaddr)"?
>
> Oh, sure.
>
> >
> >> @@ -3633,6 +3642,9 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> >>                  }
> >>
> >>                  reserved = cluster_size - compr_blocks;
> >> +               if (!reserved)
> >> +                       goto next;
> >> +
> >
> > How can the reserved variable be zero?
>
> I guess it can happen if a cluster was not released during
> release_compress_blocks(), then all blocks in the cluster should
> has been reserved, so, in this round of reserving, it needs to skip
> reserve blocks, right?

Let's assume cluster_size is 4. How can compr_blocks be 4?

                        if (i == 0) {
                                if (blkaddr == COMPRESS_ADDR)
                                        continue;
                                dn->ofs_in_node += cluster_size;
                                goto next;
                        }

We skip the block having COMPRESS_ADDR when counting compr_blocks.
So, the maximum value of compr_blocks should be 3, right?

>
> Thanks,
>
> >
> >>                  ret = inc_valid_block_count(sbi, dn->inode, &reserved);
> >>                  if (ret)
> >>                          return ret;
> >> --
> >> 2.40.1
> >>
> >>
> >>
> >> _______________________________________________
> >> Linux-f2fs-devel mailing list
> >> Linux-f2fs-devel@lists.sourceforge.net
> >> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
  
Chao Yu Jan. 12, 2024, 1:06 a.m. UTC | #4
On 2024/1/12 1:15, Daeho Jeong wrote:
> On Wed, Jan 10, 2024 at 5:33 PM Chao Yu <chao@kernel.org> wrote:
>>
>> On 2024/1/11 9:18, Daeho Jeong wrote:
>>> On Thu, Dec 28, 2023 at 6:33 AM Chao Yu <chao@kernel.org> wrote:
>>>>
>>>> From: Sheng Yong <shengyong@oppo.com>
>>>>
>>>> Compressed cluster may not be released due to we can fail in
>>>> release_compress_blocks(), fix to handle reserved compressed
>>>> cluster correctly in reserve_compress_blocks().
>>>>
>>>> Fixes: 4c8ff7095bef ("f2fs: support data compression")
>>>> Signed-off-by: Sheng Yong <shengyong@oppo.com>
>>>> Signed-off-by: Chao Yu <chao@kernel.org>
>>>> ---
>>>>    fs/f2fs/file.c | 12 ++++++++++++
>>>>    1 file changed, 12 insertions(+)
>>>>
>>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>>>> index 026d05a7edd8..782ae3be48f6 100644
>>>> --- a/fs/f2fs/file.c
>>>> +++ b/fs/f2fs/file.c
>>>> @@ -3624,6 +3624,15 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>>>>                                   goto next;
>>>>                           }
>>>>
>>>> +                       /*
>>>> +                        * compressed cluster was not released due to
>>>> +                        * it fails in release_compress_blocks().
>>>> +                        */
>>>> +                       if (blkaddr == NEW_ADDR) {
>>>> +                               compr_blocks++;
>>>> +                               continue;
>>>> +                       }
>>>> +
>>>>                           if (__is_valid_data_blkaddr(blkaddr)) {
>>>>                                   compr_blocks++;
>>>>                                   continue;
>>>
>>> How about merging two conditions like "blkaddr == NEW_ADDR ||
>>> __is_valid_data_blkaddr(blkaddr)"?
>>
>> Oh, sure.
>>
>>>
>>>> @@ -3633,6 +3642,9 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
>>>>                   }
>>>>
>>>>                   reserved = cluster_size - compr_blocks;
>>>> +               if (!reserved)
>>>> +                       goto next;
>>>> +
>>>
>>> How can the reserved variable be zero?
>>
>> I guess it can happen if a cluster was not released during
>> release_compress_blocks(), then all blocks in the cluster should
>> has been reserved, so, in this round of reserving, it needs to skip
>> reserve blocks, right?
> 
> Let's assume cluster_size is 4. How can compr_blocks be 4?
> 
>                          if (i == 0) {
>                                  if (blkaddr == COMPRESS_ADDR)
>                                          continue;
>                                  dn->ofs_in_node += cluster_size;
>                                  goto next;
>                          }
> 
> We skip the block having COMPRESS_ADDR when counting compr_blocks.
> So, the maximum value of compr_blocks should be 3, right?

Ah, got it, and I think you're right.

Should fix the condition as below?

		/* for the case all blocks in cluster were reserved */
		if (reserved == 1)
			goto next;

Thanks,

> 
>>
>> Thanks,
>>
>>>
>>>>                   ret = inc_valid_block_count(sbi, dn->inode, &reserved);
>>>>                   if (ret)
>>>>                           return ret;
>>>> --
>>>> 2.40.1
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> Linux-f2fs-devel mailing list
>>>> Linux-f2fs-devel@lists.sourceforge.net
>>>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
  
Daeho Jeong Jan. 12, 2024, 10:19 p.m. UTC | #5
On Thu, Jan 11, 2024 at 5:06 PM Chao Yu <chao@kernel.org> wrote:
>
> On 2024/1/12 1:15, Daeho Jeong wrote:
> > On Wed, Jan 10, 2024 at 5:33 PM Chao Yu <chao@kernel.org> wrote:
> >>
> >> On 2024/1/11 9:18, Daeho Jeong wrote:
> >>> On Thu, Dec 28, 2023 at 6:33 AM Chao Yu <chao@kernel.org> wrote:
> >>>>
> >>>> From: Sheng Yong <shengyong@oppo.com>
> >>>>
> >>>> Compressed cluster may not be released due to we can fail in
> >>>> release_compress_blocks(), fix to handle reserved compressed
> >>>> cluster correctly in reserve_compress_blocks().
> >>>>
> >>>> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> >>>> Signed-off-by: Sheng Yong <shengyong@oppo.com>
> >>>> Signed-off-by: Chao Yu <chao@kernel.org>
> >>>> ---
> >>>>    fs/f2fs/file.c | 12 ++++++++++++
> >>>>    1 file changed, 12 insertions(+)
> >>>>
> >>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> >>>> index 026d05a7edd8..782ae3be48f6 100644
> >>>> --- a/fs/f2fs/file.c
> >>>> +++ b/fs/f2fs/file.c
> >>>> @@ -3624,6 +3624,15 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> >>>>                                   goto next;
> >>>>                           }
> >>>>
> >>>> +                       /*
> >>>> +                        * compressed cluster was not released due to
> >>>> +                        * it fails in release_compress_blocks().
> >>>> +                        */
> >>>> +                       if (blkaddr == NEW_ADDR) {
> >>>> +                               compr_blocks++;
> >>>> +                               continue;
> >>>> +                       }
> >>>> +
> >>>>                           if (__is_valid_data_blkaddr(blkaddr)) {
> >>>>                                   compr_blocks++;
> >>>>                                   continue;
> >>>
> >>> How about merging two conditions like "blkaddr == NEW_ADDR ||
> >>> __is_valid_data_blkaddr(blkaddr)"?
> >>
> >> Oh, sure.
> >>
> >>>
> >>>> @@ -3633,6 +3642,9 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
> >>>>                   }
> >>>>
> >>>>                   reserved = cluster_size - compr_blocks;
> >>>> +               if (!reserved)
> >>>> +                       goto next;
> >>>> +
> >>>
> >>> How can the reserved variable be zero?
> >>
> >> I guess it can happen if a cluster was not released during
> >> release_compress_blocks(), then all blocks in the cluster should
> >> has been reserved, so, in this round of reserving, it needs to skip
> >> reserve blocks, right?
> >
> > Let's assume cluster_size is 4. How can compr_blocks be 4?
> >
> >                          if (i == 0) {
> >                                  if (blkaddr == COMPRESS_ADDR)
> >                                          continue;
> >                                  dn->ofs_in_node += cluster_size;
> >                                  goto next;
> >                          }
> >
> > We skip the block having COMPRESS_ADDR when counting compr_blocks.
> > So, the maximum value of compr_blocks should be 3, right?
>
> Ah, got it, and I think you're right.
>
> Should fix the condition as below?
>
>                 /* for the case all blocks in cluster were reserved */
>                 if (reserved == 1)
>                         goto next;

It looks good to me.

>
> Thanks,
>
> >
> >>
> >> Thanks,
> >>
> >>>
> >>>>                   ret = inc_valid_block_count(sbi, dn->inode, &reserved);
> >>>>                   if (ret)
> >>>>                           return ret;
> >>>> --
> >>>> 2.40.1
> >>>>
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> Linux-f2fs-devel mailing list
> >>>> Linux-f2fs-devel@lists.sourceforge.net
> >>>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
  

Patch

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 026d05a7edd8..782ae3be48f6 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3624,6 +3624,15 @@  static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
 				goto next;
 			}
 
+			/*
+			 * compressed cluster was not released due to
+			 * it fails in release_compress_blocks().
+			 */
+			if (blkaddr == NEW_ADDR) {
+				compr_blocks++;
+				continue;
+			}
+
 			if (__is_valid_data_blkaddr(blkaddr)) {
 				compr_blocks++;
 				continue;
@@ -3633,6 +3642,9 @@  static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
 		}
 
 		reserved = cluster_size - compr_blocks;
+		if (!reserved)
+			goto next;
+
 		ret = inc_valid_block_count(sbi, dn->inode, &reserved);
 		if (ret)
 			return ret;