All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jaegeuk Kim via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net>
To: Chao Yu <chao@kernel.org>
Cc: linux-f2fs-devel@lists.sourceforge.net, stable@kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [f2fs-dev] [PATCH] f2fs: fix to zero post-EOF data when extending file size
Date: Wed, 15 Jul 2026 18:05:17 +0000	[thread overview]
Message-ID: <alfL3c5Br1wQhvfb@google.com> (raw)
In-Reply-To: <20260706072606.3709384-1-chao@kernel.org>

This causes sysmtem hang during xfstests.

On 07/06, Chao Yu via Linux-f2fs-devel wrote:
> generic/794  4s ... - output mismatch (see /share/git/fstests/results//generic/794.out.bad)
>     --- tests/generic/794.out   2026-06-12 08:46:32.766426241 +0800
>     +++ /share/git/fstests/results//generic/794.out.bad 2026-07-05 18:32:55.000000000 +0800
>     @@ -1,4 +1,16 @@
>      QA output created by 794
>      append_write
>     +FAIL: non-zero data in gap [4080,4096) after shutdown+remount
>     +000000 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a  >ZZZZZZZZZZZZZZZZ<
>     +*
>     +001000
>      truncate_up
>     ...
>     (Run 'diff -u /share/git/fstests/tests/generic/794.out /share/git/fstests/results//generic/794.out.bad'  to see the entire diff)
> Ran: generic/794
> Failures: generic/794
> Failed 1 of 1 tests
> 
> Steps of generic/794:
> 1. write 4096 bytes to file w/ 0x5a
> 2. use fiemap to get PBA of first block in file
> 3. truncate file to 4080
> 4. umount; write 4096 bytes to file w/ 0x5a directly via PBA; mount
> 5. extend filesize via
>    a) append 4096 from offset 4096, or
>    b) truncate 8192, or
>    c) fallocate 4096 from offset 4096
> 6. verify the gap is zeroed in memory [4080,4096)
> 7. sync range 4096 from offset 4096; shutdown -f (flush meta before shutdown)
> 8. umount; mount; verify [4080,4096) is zeroed or not.
> 
> When extending file size (e.g. via truncate, fallocate, or write) across an
> unaligned EOF boundary, we need to ensure that post-EOF data in the partial
> page is zeroed out in pagecache and marked dirty, meanwhile, tagging the inode
> with FI_ZERO_POST_EOF, so that following checkpoint() and fsync() can persist
> the page contain zeroed data before committing inode w/ updated i_size.
> 
> This help to prevent stale disk data beyond the previous EOF from being exposed
> after remounting or crash recovery.
> 
> Since f2fs is a LFS filesystem, we only support direct write via PBA in pinfile,
> and pinfile has section-aligned filesize, so in Android, there should no problem,
> but for other usage in different environment, let's fix this w/ fsync_mode=strict
> mount option.
> 
> Cc: stable@kernel.org
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
>  fs/f2fs/checkpoint.c |  4 ++++
>  fs/f2fs/f2fs.h       |  1 +
>  fs/f2fs/file.c       | 35 ++++++++++++++++++++++++++++++++---
>  3 files changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index 064f5b537423..6f486d3a94c7 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -1359,6 +1359,10 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
>  		inode = igrab(&fi->vfs_inode);
>  		spin_unlock(&sbi->inode_lock[DIRTY_META]);
>  		if (inode) {
> +			if (is_inode_flag_set(inode, FI_ZERO_POST_EOF)) {
> +				filemap_write_and_wait(inode->i_mapping);
> +				clear_inode_flag(inode, FI_ZERO_POST_EOF);
> +			}
>  			sync_inode_metadata(inode, 0);
>  
>  			/* it's on eviction */
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 8e2fb0bda467..41be09dad43c 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -939,6 +939,7 @@ enum {
>  	FI_ATOMIC_REPLACE,	/* indicate atomic replace */
>  	FI_OPENED_FILE,		/* indicate file has been opened */
>  	FI_DONATE_FINISHED,	/* indicate page donation of file has been finished */
> +	FI_ZERO_POST_EOF,	/* indicate unaligned EOF gap was zeroed in pagecache */
>  	FI_MAX,			/* max flag, never be used */
>  };
>  
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 11cc8d79c235..2e9d585073ec 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -36,21 +36,43 @@
>  #include <trace/events/f2fs.h>
>  #include <uapi/linux/f2fs.h>
>  
> +static int fill_zero(struct inode *inode, pgoff_t index,
> +					loff_t start, loff_t len);
> +
>  static void f2fs_zero_post_eof_page(struct inode *inode,
>  					loff_t new_size, bool lock)
>  {
>  	loff_t old_size = i_size_read(inode);
> +	unsigned int offset;
>  
>  	if (old_size >= new_size)
>  		return;
>  
> -	if (mapping_empty(inode->i_mapping))
> -		return;
> -
>  	if (lock)
>  		filemap_invalidate_lock(inode->i_mapping);
> +
>  	/* zero or drop pages only in range of [old_size, new_size] */
>  	truncate_inode_pages_range(inode->i_mapping, old_size, new_size);
> +
> +	/*
> +	 * When expanding an unaligned EOF size, zero post-EOF data in
> +	 * pagecache and set FI_ZERO_POST_EOF, so following checkpointing
> +	 * or fsync can persist correct data to disk before committing
> +	 * inode w/ updated i_size.
> +	 */
> +	if (F2FS_OPTION(F2FS_I_SB(inode)).fsync_mode != FSYNC_MODE_STRICT)
> +		goto out_unlock;
> +
> +	offset = old_size & (PAGE_SIZE - 1);
> +	if (offset) {
> +		unsigned int len = min_t(loff_t, PAGE_SIZE - offset,
> +							new_size - old_size);
> +		pgoff_t index = old_size >> PAGE_SHIFT;
> +
> +		fill_zero(inode, index, offset, len);
> +		set_inode_flag(inode, FI_ZERO_POST_EOF);
> +	}
> +out_unlock:
>  	if (lock)
>  		filemap_invalidate_unlock(inode->i_mapping);
>  }
> @@ -304,6 +326,13 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
>  	if (S_ISDIR(inode->i_mode))
>  		goto go_write;
>  
> +	if (is_inode_flag_set(inode, FI_ZERO_POST_EOF)) {
> +		ret = filemap_write_and_wait(inode->i_mapping);
> +		if (ret)
> +			return ret;
> +		clear_inode_flag(inode, FI_ZERO_POST_EOF);
> +	}
> +
>  	/* if fdatasync is triggered, let's do in-place-update */
>  	if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
>  		set_inode_flag(inode, FI_NEED_IPU);
> -- 
> 2.49.0
> 
> 
> 
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

WARNING: multiple messages have this Message-ID (diff)
From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Chao Yu <chao@kernel.org>
Cc: stable@kernel.org, linux-kernel@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH] f2fs: fix to zero post-EOF data when extending file size
Date: Wed, 15 Jul 2026 18:05:17 +0000	[thread overview]
Message-ID: <alfL3c5Br1wQhvfb@google.com> (raw)
In-Reply-To: <20260706072606.3709384-1-chao@kernel.org>

This causes sysmtem hang during xfstests.

On 07/06, Chao Yu via Linux-f2fs-devel wrote:
> generic/794  4s ... - output mismatch (see /share/git/fstests/results//generic/794.out.bad)
>     --- tests/generic/794.out   2026-06-12 08:46:32.766426241 +0800
>     +++ /share/git/fstests/results//generic/794.out.bad 2026-07-05 18:32:55.000000000 +0800
>     @@ -1,4 +1,16 @@
>      QA output created by 794
>      append_write
>     +FAIL: non-zero data in gap [4080,4096) after shutdown+remount
>     +000000 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a  >ZZZZZZZZZZZZZZZZ<
>     +*
>     +001000
>      truncate_up
>     ...
>     (Run 'diff -u /share/git/fstests/tests/generic/794.out /share/git/fstests/results//generic/794.out.bad'  to see the entire diff)
> Ran: generic/794
> Failures: generic/794
> Failed 1 of 1 tests
> 
> Steps of generic/794:
> 1. write 4096 bytes to file w/ 0x5a
> 2. use fiemap to get PBA of first block in file
> 3. truncate file to 4080
> 4. umount; write 4096 bytes to file w/ 0x5a directly via PBA; mount
> 5. extend filesize via
>    a) append 4096 from offset 4096, or
>    b) truncate 8192, or
>    c) fallocate 4096 from offset 4096
> 6. verify the gap is zeroed in memory [4080,4096)
> 7. sync range 4096 from offset 4096; shutdown -f (flush meta before shutdown)
> 8. umount; mount; verify [4080,4096) is zeroed or not.
> 
> When extending file size (e.g. via truncate, fallocate, or write) across an
> unaligned EOF boundary, we need to ensure that post-EOF data in the partial
> page is zeroed out in pagecache and marked dirty, meanwhile, tagging the inode
> with FI_ZERO_POST_EOF, so that following checkpoint() and fsync() can persist
> the page contain zeroed data before committing inode w/ updated i_size.
> 
> This help to prevent stale disk data beyond the previous EOF from being exposed
> after remounting or crash recovery.
> 
> Since f2fs is a LFS filesystem, we only support direct write via PBA in pinfile,
> and pinfile has section-aligned filesize, so in Android, there should no problem,
> but for other usage in different environment, let's fix this w/ fsync_mode=strict
> mount option.
> 
> Cc: stable@kernel.org
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
>  fs/f2fs/checkpoint.c |  4 ++++
>  fs/f2fs/f2fs.h       |  1 +
>  fs/f2fs/file.c       | 35 ++++++++++++++++++++++++++++++++---
>  3 files changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index 064f5b537423..6f486d3a94c7 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -1359,6 +1359,10 @@ static int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
>  		inode = igrab(&fi->vfs_inode);
>  		spin_unlock(&sbi->inode_lock[DIRTY_META]);
>  		if (inode) {
> +			if (is_inode_flag_set(inode, FI_ZERO_POST_EOF)) {
> +				filemap_write_and_wait(inode->i_mapping);
> +				clear_inode_flag(inode, FI_ZERO_POST_EOF);
> +			}
>  			sync_inode_metadata(inode, 0);
>  
>  			/* it's on eviction */
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 8e2fb0bda467..41be09dad43c 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -939,6 +939,7 @@ enum {
>  	FI_ATOMIC_REPLACE,	/* indicate atomic replace */
>  	FI_OPENED_FILE,		/* indicate file has been opened */
>  	FI_DONATE_FINISHED,	/* indicate page donation of file has been finished */
> +	FI_ZERO_POST_EOF,	/* indicate unaligned EOF gap was zeroed in pagecache */
>  	FI_MAX,			/* max flag, never be used */
>  };
>  
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 11cc8d79c235..2e9d585073ec 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -36,21 +36,43 @@
>  #include <trace/events/f2fs.h>
>  #include <uapi/linux/f2fs.h>
>  
> +static int fill_zero(struct inode *inode, pgoff_t index,
> +					loff_t start, loff_t len);
> +
>  static void f2fs_zero_post_eof_page(struct inode *inode,
>  					loff_t new_size, bool lock)
>  {
>  	loff_t old_size = i_size_read(inode);
> +	unsigned int offset;
>  
>  	if (old_size >= new_size)
>  		return;
>  
> -	if (mapping_empty(inode->i_mapping))
> -		return;
> -
>  	if (lock)
>  		filemap_invalidate_lock(inode->i_mapping);
> +
>  	/* zero or drop pages only in range of [old_size, new_size] */
>  	truncate_inode_pages_range(inode->i_mapping, old_size, new_size);
> +
> +	/*
> +	 * When expanding an unaligned EOF size, zero post-EOF data in
> +	 * pagecache and set FI_ZERO_POST_EOF, so following checkpointing
> +	 * or fsync can persist correct data to disk before committing
> +	 * inode w/ updated i_size.
> +	 */
> +	if (F2FS_OPTION(F2FS_I_SB(inode)).fsync_mode != FSYNC_MODE_STRICT)
> +		goto out_unlock;
> +
> +	offset = old_size & (PAGE_SIZE - 1);
> +	if (offset) {
> +		unsigned int len = min_t(loff_t, PAGE_SIZE - offset,
> +							new_size - old_size);
> +		pgoff_t index = old_size >> PAGE_SHIFT;
> +
> +		fill_zero(inode, index, offset, len);
> +		set_inode_flag(inode, FI_ZERO_POST_EOF);
> +	}
> +out_unlock:
>  	if (lock)
>  		filemap_invalidate_unlock(inode->i_mapping);
>  }
> @@ -304,6 +326,13 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
>  	if (S_ISDIR(inode->i_mode))
>  		goto go_write;
>  
> +	if (is_inode_flag_set(inode, FI_ZERO_POST_EOF)) {
> +		ret = filemap_write_and_wait(inode->i_mapping);
> +		if (ret)
> +			return ret;
> +		clear_inode_flag(inode, FI_ZERO_POST_EOF);
> +	}
> +
>  	/* if fdatasync is triggered, let's do in-place-update */
>  	if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
>  		set_inode_flag(inode, FI_NEED_IPU);
> -- 
> 2.49.0
> 
> 
> 
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

  parent reply	other threads:[~2026-07-15 18:05 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-06  7:26 [f2fs-dev] [PATCH] f2fs: fix to zero post-EOF data when extending file size Chao Yu via Linux-f2fs-devel
2026-07-06  7:26 ` Chao Yu
2026-07-14  3:00 ` [f2fs-dev] " patchwork-bot+f2fs--- via Linux-f2fs-devel
2026-07-14  3:00   ` patchwork-bot+f2fs
2026-07-15 18:05 ` Jaegeuk Kim via Linux-f2fs-devel [this message]
2026-07-15 18:05   ` Jaegeuk Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alfL3c5Br1wQhvfb@google.com \
    --to=linux-f2fs-devel@lists.sourceforge.net \
    --cc=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.