[PATCH] f2fs: fix i_size when pinned fallocate partially fails

Zhan Xusheng posted 1 patch 1 month, 1 week ago
There is a newer version of this series
fs/f2fs/file.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
[PATCH] f2fs: fix i_size when pinned fallocate partially fails
Posted by Zhan Xusheng 1 month, 1 week ago
From: Zhan Xusheng <zhanxusheng1024@gmail.com>

From: Zhan Xusheng <zhanxusheng@xiaomi.com>

Commit 4275b59673eb ("f2fs: fix to round down start offset of fallocate
for pin file") moved the allocation loop's start down to a section
boundary, but the error path still converts @expanded against @pg_start,
which holds the unrounded start.

@pg_start exists for that conversion: commit 88f2cfc5fa90 ("f2fs: fix to
update last i_size if fallocate partially succeeds") added it as an
immutable base because map.m_lblk moves every round.  Each round now maps
exactly sec_blks blocks starting from rounddown(pg_start, sec_blks), so
pg_start + expanded overshoots the last allocated block by
pg_start % sec_blks, and a partial failure leaves i_size covering a tail
that was never allocated.  Nothing corrects that afterwards either, since
file_dont_truncate() has already cleared FADVISE_TRUNC_BIT.

Keep @pg_start pointing at where allocation actually begins.

Fixes: 4275b59673eb ("f2fs: fix to round down start offset of fallocate for pin file")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
---
 fs/f2fs/file.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 4b52c56d71f0..cc0d2b8c4684 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1919,8 +1919,9 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
 		block_t sec_len;
 
 		if (map.m_lblk % sec_blks) {
-			map.m_lblk = rounddown(map.m_lblk, sec_blks);
-			map.m_len = pg_end - map.m_lblk;
+			pg_start = rounddown(map.m_lblk, sec_blks);
+			map.m_lblk = pg_start;
+			map.m_len = pg_end - pg_start;
 			if (off_end)
 				map.m_len++;
 		}
-- 
2.43.0
Re: [PATCH] f2fs: fix i_size when pinned fallocate partially fails
Posted by Chao Yu 1 month, 1 week ago
On 8/17/26 10:27, Zhan Xusheng wrote:
> From: Zhan Xusheng <zhanxusheng1024@gmail.com>
> 
> From: Zhan Xusheng <zhanxusheng@xiaomi.com>
> 
> Commit 4275b59673eb ("f2fs: fix to round down start offset of fallocate
> for pin file") moved the allocation loop's start down to a section
> boundary, but the error path still converts @expanded against @pg_start,
> which holds the unrounded start.
> 
> @pg_start exists for that conversion: commit 88f2cfc5fa90 ("f2fs: fix to
> update last i_size if fallocate partially succeeds") added it as an
> immutable base because map.m_lblk moves every round.  Each round now maps
> exactly sec_blks blocks starting from rounddown(pg_start, sec_blks), so
> pg_start + expanded overshoots the last allocated block by
> pg_start % sec_blks, and a partial failure leaves i_size covering a tail
> that was never allocated.  Nothing corrects that afterwards either, since
> file_dont_truncate() has already cleared FADVISE_TRUNC_BIT.
> 
> Keep @pg_start pointing at where allocation actually begins.

Hi Xuesheng,

Can you please provide a reproducer?

Thanks,

> 
> Fixes: 4275b59673eb ("f2fs: fix to round down start offset of fallocate for pin file")
> Cc: stable@vger.kernel.org
> Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
> ---
>   fs/f2fs/file.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 4b52c56d71f0..cc0d2b8c4684 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -1919,8 +1919,9 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
>   		block_t sec_len;
>   
>   		if (map.m_lblk % sec_blks) {
> -			map.m_lblk = rounddown(map.m_lblk, sec_blks);
> -			map.m_len = pg_end - map.m_lblk;
> +			pg_start = rounddown(map.m_lblk, sec_blks);
> +			map.m_lblk = pg_start;
> +			map.m_len = pg_end - pg_start;
>   			if (off_end)
>   				map.m_len++;
>   		}
Re: [PATCH] f2fs: fix i_size when pinned fallocate partially fails
Posted by Zhan Xusheng 1 month, 1 week ago
On 8/17/26 11:12, Chao Yu wrote:
> Can you please provide a reproducer?

It needs a start offset that is not section aligned, plus a fallocate that
hits ENOSPC partway so the error path runs with expanded > 0.

  truncate -s 80M img
  mkfs.f2fs -s 1 -f img              # 2 MiB sections, sec_blks = 512
  mount -o loop img /mnt
  touch /mnt/pinned
  f2fs_io pinfile set /mnt/pinned
  # 2093056 = block 511, so pg_start % sec_blks = 511
  f2fs_io fallocate 0 2093056 536870912 /mnt/pinned
  stat -c %s /mnt/pinned
  filefrag -v /mnt/pinned

7.2, last extent and i_size:

  ext:  logical_offset:  length:  flags:
    2:  5120..   10737:    5618:  last,merged
  i_size=46075904

  i_size block 11249, allocated through 10738, overshoot 511

With this patch:

  ext:  logical_offset:  length:  flags:
    2:  5120..   10737:    5618:  last,merged,eof
  i_size=43982848

  i_size block 10738, allocated through 10738, overshoot 0

filefrag prints eof only once the last extent reaches i_size, so its
absence in the first run shows the mismatch on its own.

7.0, before 4275b59673eb, also gives overshoot 0.  Absolute block numbers
differ there because the start rounding changes how much fits before
ENOSPC, so only the overshoot compares across the three.

I will add this to the changelog in v2.

Thanks,
Zhan Xusheng