From: Chao Yu via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net>
To: Nanzhe Zhao <zhaonanzhe@xiaomi.com>,
linux-f2fs-devel@lists.sourceforge.net,
Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Barry Song <baohua@kernel.org>, Juan Yescas <jyescas@google.com>,
Daeho Jeong <daehojeong@google.com>, Dev Jain <Dev.Jain@arm.com>,
linux-kernel@vger.kernel.org,
David Hildenbrand <David.Hildenbrand@arm.com>,
Bo Zhang <zhangbo56@xiaomi.com>,
Kalesh Singh <kaleshsingh@google.com>,
Nanzhe Zhao <nzzhao@126.com>, Pengfei Li <lipengfei28@xiaomi.com>,
Ryan Roberts <Ryan.Roberts@arm.com>
Subject: Re: [f2fs-dev] [PATCH v3 12/17] f2fs: handle partial truncate of large folio dirty subpages
Date: Mon, 12 Oct 2026 15:27:27 +0800 [thread overview]
Message-ID: <1b2831dc-8d8a-4216-811e-22396fc9e35d@kernel.org> (raw)
In-Reply-To: <20261009162828.4188050-2-zhaonanzhe@xiaomi.com>
On 10/10/26 00:28, Nanzhe Zhao wrote:
> A large folio can be partial truncated and stays in folio mapping, we
> need to clear the subrange dirty bits and uptodate bits that the partial
> truncate covers. If this partial truncate happens to clear the last
> subrange dirty bits, then cancel the whole folio dirty state.
>
> Also add a guard in f2fs_write_single_data_folio() so a large folio
> subpage whose disk block was already truncated (NULL_ADDR) is skipped
>
> Signed-off-by: Nanzhe Zhao <zhaonanzhe@xiaomi.com>
> ---
> fs/f2fs/data.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 109 insertions(+), 6 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 21c43019167a..138a77044e95 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -329,6 +329,27 @@ static void f2fs_read_end_io(struct bio *bio)
> f2fs_verify_and_finish_bio(bio, intask);
> }
>
> +static bool f2fs_ffs_has_dirty_subpage(struct folio *folio)
> +{
> + struct f2fs_folio_state *ffs;
> + unsigned long flags;
> + unsigned int nr_subpages;
> + bool dirty;
> +
> + if (!f2fs_folio_has_ffs(folio))
> + return false;
> +
> + ffs = (struct f2fs_folio_state *)folio->private;
> + nr_subpages = folio_nr_pages(folio);
> +
> + spin_lock_irqsave(&ffs->state_lock, flags);
> + dirty = find_next_bit(ffs->state, 2 * nr_subpages,
> + nr_subpages) < 2 * nr_subpages;
> + spin_unlock_irqrestore(&ffs->state_lock, flags);
> +
> + return dirty;
> +}
> +
> static void f2fs_write_end_bio(struct bio *bio)
> {
> struct f2fs_sb_info *sbi = bio->bi_private;
> @@ -380,7 +401,8 @@ static void f2fs_write_end_bio(struct bio *bio)
> wake_up(&sbi->cp_wait);
>
> if (finished) {
> - folio_clear_f2fs_gcing(folio);
> + if (!f2fs_ffs_has_dirty_subpage(folio))
> + folio_clear_f2fs_gcing(folio);
> folio_end_writeback(folio);
> }
> }
> @@ -2893,6 +2915,29 @@ static void f2fs_ffs_mark_subrange_uptodate(struct folio *folio, size_t offset,
> folio_mark_uptodate(folio);
> }
>
> +static void ffs_clear_subrange_uptodate(struct folio *folio,
> + size_t offset, size_t len)
> +{
> + struct f2fs_folio_state *ffs;
> + unsigned int nr_subpages, start, end;
> + unsigned long flags;
> +
> + f2fs_bug_on(F2FS_F_SB(folio), offset + len > folio_size(folio));
> +
> + if (!f2fs_folio_has_ffs(folio))
> + return;
> +
> + ffs = (struct f2fs_folio_state *)folio->private;
> + nr_subpages = folio_nr_pages(folio);
> + start = offset >> PAGE_SHIFT;
> + end = (offset + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
> + end = min(end, nr_subpages);
> +
> + spin_lock_irqsave(&ffs->state_lock, flags);
> + bitmap_clear(ffs->state, start, end - start);
> + spin_unlock_irqrestore(&ffs->state_lock, flags);
> +}
> +
> bool f2fs_ffs_test_blk_dirty(const struct folio *folio, pgoff_t index)
> {
> struct f2fs_folio_state *ffs;
> @@ -3771,12 +3816,35 @@ static int f2fs_write_folio_dirty_range(struct folio *folio, int *submitted,
>
> err = f2fs_get_dnode_of_data(&dn, data_idx, LOOKUP_NODE);
>
> + /*
> + * If a subpage of folio for a cow file is dirtied but not
> + * reserve a cow block, fallback to original inode to lookup
> + * block address
writeback vs truncate on atomic file?
> + */
> + if (atomic_commit && (err == -ENOENT ||
> + (!err && dn.data_blkaddr == NULL_ADDR))) {
> + f2fs_put_dnode(&dn);
> + set_new_dnode(&dn, inode, NULL, NULL, 0);
> + err = f2fs_get_dnode_of_data(&dn, data_idx,
> + LOOKUP_NODE);
> + /* Original inode has no block, handled as truncated below */
> + if (err == -ENOENT)
> + err = 0;
> + }
> if (err)
> goto block_done;
> dn_held = true;
>
> fio.old_blkaddr = dn.data_blkaddr;
>
> + /* This page is already truncated */
> + if (fio.old_blkaddr == NULL_ADDR) {
> + ffs_clear_subrange_uptodate(folio,
> + (unsigned long long)i << PAGE_SHIFT,
(loff_t)i << PAGE_SHIFT,
Thanks,
> + PAGE_SIZE);
> + goto block_done;
> + }
> +
> got_it:
> if (__is_valid_data_blkaddr(fio.old_blkaddr) &&
> !f2fs_is_valid_blkaddr(sbi, fio.old_blkaddr,
> @@ -4325,6 +4393,7 @@ static int f2fs_write_cache_folios(struct address_space *mapping,
> bool verity_in_progress;
> int folio_submitted = 0;
> bool bias_added = false;
> + bool dirty;
>
> submitted = 0;
> next = true;
> @@ -4432,15 +4501,19 @@ static int f2fs_write_cache_folios(struct address_space *mapping,
> * partially written back), the folio must stay dirty so that
> * the remaining subranges are written back later.
> */
> - if (f2fs_ffs_clear_subrange_dirty_and_test(folio, 0,
> - (err ? pos : end_pos) - folio_pos(folio)))
> + dirty = f2fs_ffs_clear_subrange_dirty_and_test(folio, 0,
> + (err ? pos : end_pos) - folio_pos(folio));
> + if (dirty)
> folio_redirty_for_writepage(wbc, folio);
> else if (!f2fs_folio_has_ffs(folio))
> inode_dec_dirty_pages(inode);
>
> if (bias_added) {
> - if (atomic_dec_and_test(&ffs->write_pages_pending))
> + if (atomic_dec_and_test(&ffs->write_pages_pending)) {
> + if (!dirty)
> + folio_clear_f2fs_gcing(folio);
> folio_end_writeback(folio);
> + }
> } else if (!folio_submitted && folio_test_writeback(folio)) {
> folio_end_writeback(folio);
> }
> @@ -5243,10 +5316,40 @@ void f2fs_invalidate_folio(struct folio *folio, size_t offset, size_t length)
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
>
> if (inode->i_ino >= F2FS_ROOT_INO(sbi) &&
> - (offset || length != folio_size(folio)))
> + (offset || length != folio_size(folio))) {
> + size_t clear_start = round_up(offset, PAGE_SIZE);
> + size_t clear_end = round_down(offset + length, PAGE_SIZE);
> + size_t clear_length;
> + bool dirty;
> +
> + /*
> + * If the truncated range falls within a single subpage, no
> + * subpage state needs to be cleared.
> + */
> + if (clear_start >= clear_end || !f2fs_folio_has_ffs(folio))
> + return;
> +
> + clear_length = clear_end - clear_start;
> + dirty = f2fs_ffs_clear_subrange_dirty_and_test(folio,
> + clear_start, clear_length);
> + ffs_clear_subrange_uptodate(folio, clear_start, clear_length);
> +
> + /*
> + * If the truncated subrange happens to clear the remaining
> + * dirty bitmap of the whole folio, cancel the folio-level
> + * dirty state.
> + */
> + if (!dirty && folio_test_dirty(folio))
> + folio_cancel_dirty(folio);
> + if (!dirty && !folio_test_writeback(folio))
> + folio_clear_f2fs_gcing(folio);
> return;
> + }
>
> - if (folio_test_dirty(folio)) {
> + if (f2fs_folio_has_ffs(folio)) {
> + f2fs_ffs_clear_subrange_dirty_and_test(folio, 0,
> + folio_size(folio));
> + } else if (folio_test_dirty(folio)) {
> inode_dec_dirty_pages(inode);
> f2fs_remove_dirty_inode(inode);
> }
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2026-10-12 7:27 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 16:12 [f2fs-dev] [PATCH v3 00/17] f2fs: support & optimize large folios for writable files Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 01/17] f2fs: extend folio state for large folio write path Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 02/17] f2fs: carry subpage offset and count in write IO Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 03/17] f2fs: support regular file buffered writes on large folios Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 18:34 ` Daeho Jeong
2026-10-10 10:02 ` Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 3:01 ` Chao Yu via Linux-f2fs-devel
2026-10-12 13:06 ` Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 04/17] f2fs: support atomic file large folios buffered write Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 3:06 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 05/17] f2fs: support large folio writeback Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 4:36 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 06/17] f2fs: account large folio dirty data at block granularity Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 6:54 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 07/17] f2fs: remove mappedtodisk flag usage in mmap write path Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 08/17] f2fs: prepare mmap write faults for large folios Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 7:04 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 09/17] f2fs: make GC migration large-folio aware Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:12 ` [f2fs-dev] [PATCH v3 10/17] f2fs: optimize small block size large folio read Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 7:09 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 11/17] f2fs: support partial uptodate " Nanzhe Zhao via Linux-f2fs-devel
2026-10-12 7:18 ` Chao Yu via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 12/17] f2fs: handle partial truncate of large folio dirty subpages Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 18:14 ` Daeho Jeong
2026-10-12 7:27 ` Chao Yu via Linux-f2fs-devel [this message]
2026-10-13 12:01 ` Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 13/17] f2fs: wait for folio writeback before ffs_detach_free Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 14/17] f2fs: fix zeroing paths for large folios Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 15/17] f2fs: handle block cloning within the same large folio Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 16/17] f2fs: allow large folio support to writeable files Nanzhe Zhao via Linux-f2fs-devel
2026-10-09 16:28 ` [f2fs-dev] [PATCH v3 17/17] f2fs: make compressed files compatible with large folio Nanzhe Zhao via Linux-f2fs-devel
2026-10-13 22:30 ` [f2fs-dev] [PATCH v3 00/17] f2fs: support & optimize large folios for writable files patchwork-bot+f2fs--- via Linux-f2fs-devel
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=1b2831dc-8d8a-4216-811e-22396fc9e35d@kernel.org \
--to=linux-f2fs-devel@lists.sourceforge.net \
--cc=David.Hildenbrand@arm.com \
--cc=Dev.Jain@arm.com \
--cc=Ryan.Roberts@arm.com \
--cc=baohua@kernel.org \
--cc=chao@kernel.org \
--cc=daehojeong@google.com \
--cc=jaegeuk@kernel.org \
--cc=jyescas@google.com \
--cc=kaleshsingh@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lipengfei28@xiaomi.com \
--cc=nzzhao@126.com \
--cc=zhangbo56@xiaomi.com \
--cc=zhaonanzhe@xiaomi.com \
/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.