* FAILED: patch "[PATCH] f2fs: fix to avoid potential deadloop in" failed to apply to 6.12-stable tree
@ 2026-09-09 11:26 gregkh
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
0 siblings, 1 reply; 8+ messages in thread
From: gregkh @ 2026-09-09 11:26 UTC (permalink / raw)
To: chao, jaegeuk; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x ce366bfa821ec81dd45bde547ee31e659306cc61
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090957-stoke-condense-f9b1@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ce366bfa821ec81dd45bde547ee31e659306cc61 Mon Sep 17 00:00:00 2001
From: Chao Yu <chao@kernel.org>
Date: Mon, 24 Aug 2026 21:17:29 +0800
Subject: [PATCH] f2fs: fix to avoid potential deadloop in
f2fs_fsync_node_pages()
There is potential deadloop in race condition:
Thread A Thread B
- fsync
- f2fs_do_sync_file
- f2fs_fsync_node_pages
- last_fsync_dnode
- folio_get(last_folio)
- f2fs_setattr
- f2fs_truncate
- f2fs_truncate_blocks
- f2fs_do_truncate_blocks
- f2fs_truncate_inode_blocks
- truncate_dnode
- truncate_node
- invalidate_mapping_pages
- folio->mapping = NULL
- is_node_folio alwasy return false
- atomic && !marked is always true,
then goto retry
Cc: stable@kernel.org
Fixes: 608514deba38 ("f2fs: set fsync mark only for the last dnode")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 968e5ed38816..86c2e67e43b6 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -2016,6 +2016,11 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
ino, last_folio->index);
folio_lock(last_folio);
+ if (unlikely(!is_node_folio(last_folio))) {
+ f2fs_folio_put(last_folio, true);
+ ret = -EAGAIN;
+ goto out;
+ }
f2fs_folio_wait_writeback(last_folio, NODE, true, true);
folio_mark_dirty(last_folio);
folio_unlock(last_folio);
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block()
2026-09-09 11:26 FAILED: patch "[PATCH] f2fs: fix to avoid potential deadloop in" failed to apply to 6.12-stable tree gregkh
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio() Sasha Levin
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox (Oracle), Chao Yu, Jaegeuk Kim, Sasha Levin
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
[ Upstream commit c14b4562bc9bd7cb57dbb95eae73fc3f24cdfadc ]
Fetch a folio from the pagecache instead of a page and operate on it
throughout. Removes eight calls to compound_head() and an access to
page->mapping.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/gc.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index b8a9412ca1dc8..fbd246b3e550a 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -1336,7 +1336,8 @@ static int move_data_block(struct inode *inode, block_t bidx,
struct dnode_of_data dn;
struct f2fs_summary sum;
struct node_info ni;
- struct page *page, *mpage;
+ struct page *page;
+ struct folio *mfolio;
block_t newaddr;
int err = 0;
bool lfs_mode = f2fs_lfs_mode(fio.sbi);
@@ -1401,20 +1402,20 @@ static int move_data_block(struct inode *inode, block_t bidx,
if (lfs_mode)
f2fs_down_write(&fio.sbi->io_order_lock);
- mpage = f2fs_grab_cache_page(META_MAPPING(fio.sbi),
+ mfolio = f2fs_grab_cache_folio(META_MAPPING(fio.sbi),
fio.old_blkaddr, false);
- if (!mpage) {
- err = -ENOMEM;
+ if (IS_ERR(mfolio)) {
+ err = PTR_ERR(mfolio);
goto up_out;
}
- fio.encrypted_page = mpage;
+ fio.encrypted_page = folio_file_page(mfolio, fio.old_blkaddr);
- /* read source block in mpage */
- if (!PageUptodate(mpage)) {
+ /* read source block in mfolio */
+ if (!folio_test_uptodate(mfolio)) {
err = f2fs_submit_page_bio(&fio);
if (err) {
- f2fs_put_page(mpage, 1);
+ f2fs_folio_put(mfolio, true);
goto up_out;
}
@@ -1423,11 +1424,11 @@ static int move_data_block(struct inode *inode, block_t bidx,
f2fs_update_iostat(fio.sbi, NULL, FS_GDATA_READ_IO,
F2FS_BLKSIZE);
- lock_page(mpage);
- if (unlikely(mpage->mapping != META_MAPPING(fio.sbi) ||
- !PageUptodate(mpage))) {
+ folio_lock(mfolio);
+ if (unlikely(mfolio->mapping != META_MAPPING(fio.sbi) ||
+ !folio_test_uptodate(mfolio))) {
err = -EIO;
- f2fs_put_page(mpage, 1);
+ f2fs_folio_put(mfolio, true);
goto up_out;
}
}
@@ -1438,7 +1439,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
err = f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
&sum, type, NULL);
if (err) {
- f2fs_put_page(mpage, 1);
+ f2fs_folio_put(mfolio, true);
/* filesystem should shutdown, no need to recovery block */
goto up_out;
}
@@ -1447,15 +1448,15 @@ static int move_data_block(struct inode *inode, block_t bidx,
newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
if (!fio.encrypted_page) {
err = -ENOMEM;
- f2fs_put_page(mpage, 1);
+ f2fs_folio_put(mfolio, true);
goto recover_block;
}
/* write target block */
f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true, true);
memcpy(page_address(fio.encrypted_page),
- page_address(mpage), PAGE_SIZE);
- f2fs_put_page(mpage, 1);
+ folio_address(mfolio), PAGE_SIZE);
+ f2fs_folio_put(mfolio, true);
f2fs_invalidate_internal_cache(fio.sbi, fio.old_blkaddr);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio()
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 3/7] f2fs: Add f2fs_get_node_folio() Sasha Levin
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox (Oracle), Chao Yu, Jaegeuk Kim, Sasha Levin
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
[ Upstream commit cfa809146f8223c2953e7553f830c0877921f9de ]
Convert f2fs_new_node_page() to f2fs_new_node_folio() and add
a compatibility wrapper. Removes five hidden calls to compound_head().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/f2fs.h | 8 +++++++-
fs/f2fs/node.c | 28 ++++++++++++++--------------
2 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e1cbd3917b9d9..713d8907859a8 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3740,7 +3740,7 @@ int f2fs_wait_on_node_pages_writeback(struct f2fs_sb_info *sbi,
unsigned int seq_id);
int f2fs_remove_inode_page(struct inode *inode);
struct page *f2fs_new_inode_page(struct inode *inode);
-struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs);
+struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs);
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid);
struct page *f2fs_get_node_page_ra(struct page *parent, int start);
@@ -3768,6 +3768,12 @@ void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi);
int __init f2fs_create_node_manager_caches(void);
void f2fs_destroy_node_manager_caches(void);
+static inline
+struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
+{
+ return &f2fs_new_node_folio(dn, ofs)->page;
+}
+
/*
* segment.c
*/
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 1f4f68e56d432..6989e5afea551 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1336,19 +1336,19 @@ struct page *f2fs_new_inode_page(struct inode *inode)
return f2fs_new_node_page(&dn, 0);
}
-struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
+struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
struct node_info new_ni;
- struct page *page;
+ struct folio *folio;
int err;
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
return ERR_PTR(-EPERM);
- page = f2fs_grab_cache_page(NODE_MAPPING(sbi), dn->nid, false);
- if (!page)
- return ERR_PTR(-ENOMEM);
+ folio = f2fs_grab_cache_folio(NODE_MAPPING(sbi), dn->nid, false);
+ if (IS_ERR(folio))
+ return folio;
if (unlikely((err = inc_valid_node_count(sbi, dn->inode, !ofs))))
goto fail;
@@ -1379,12 +1379,12 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
new_ni.version = 0;
set_node_addr(sbi, &new_ni, NEW_ADDR, false);
- f2fs_wait_on_page_writeback(page, NODE, true, true);
- fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
- set_cold_node(page, S_ISDIR(dn->inode->i_mode));
- if (!PageUptodate(page))
- SetPageUptodate(page);
- if (set_page_dirty(page))
+ f2fs_folio_wait_writeback(folio, NODE, true, true);
+ fill_node_footer(&folio->page, dn->nid, dn->inode->i_ino, ofs, true);
+ set_cold_node(&folio->page, S_ISDIR(dn->inode->i_mode));
+ if (!folio_test_uptodate(folio))
+ folio_mark_uptodate(folio);
+ if (folio_mark_dirty(folio))
dn->node_changed = true;
if (f2fs_has_xattr_block(ofs))
@@ -1392,10 +1392,10 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
if (ofs == 0)
inc_valid_inode_count(sbi);
- return page;
+ return folio;
fail:
- clear_node_page_dirty(page);
- f2fs_put_page(page, 1);
+ clear_node_page_dirty(&folio->page);
+ f2fs_folio_put(folio, true);
return ERR_PTR(err);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 3/7] f2fs: Add f2fs_get_node_folio()
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio() Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 4/7] f2fs: Use a folio in truncate_nodes() Sasha Levin
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox (Oracle), Chao Yu, Jaegeuk Kim, Sasha Levin
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
[ Upstream commit aa220cede54ed671f7be413d8dacb91263a9d218 ]
The folio equivalent of f2fs_get_node_page().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/f2fs.h | 1 +
fs/f2fs/node.c | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 713d8907859a8..67c5b9cb90ee6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3742,6 +3742,7 @@ int f2fs_remove_inode_page(struct inode *inode);
struct page *f2fs_new_inode_page(struct inode *inode);
struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs);
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
+struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid);
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid);
struct page *f2fs_get_node_page_ra(struct page *parent, int start);
int f2fs_move_node_page(struct page *node_page, int gc_type);
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 6989e5afea551..cce67bfbac59d 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1535,6 +1535,11 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
return ERR_PTR(err);
}
+struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid)
+{
+ return __get_node_folio(sbi, nid, NULL, 0, NODE_TYPE_REGULAR);
+}
+
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
{
return __get_node_page(sbi, nid, NULL, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 4/7] f2fs: Use a folio in truncate_nodes()
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 3/7] f2fs: Add f2fs_get_node_folio() Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 5/7] f2fs: Use folios in truncate_partial_nodes() Sasha Levin
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox (Oracle), Chao Yu, Jaegeuk Kim, Sasha Levin
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
[ Upstream commit 878a05b09c0c578b679956431cd2be5cc3689403 ]
Remove two calls to compound_head().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index cce67bfbac59d..5fe77be55998d 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -998,7 +998,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
int ofs, int depth)
{
struct dnode_of_data rdn = *dn;
- struct page *page;
+ struct folio *folio;
struct f2fs_node *rn;
nid_t child_nid;
unsigned int child_nofs;
@@ -1010,15 +1010,15 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
trace_f2fs_truncate_nodes_enter(dn->inode, dn->nid, dn->data_blkaddr);
- page = f2fs_get_node_page(F2FS_I_SB(dn->inode), dn->nid);
- if (IS_ERR(page)) {
- trace_f2fs_truncate_nodes_exit(dn->inode, PTR_ERR(page));
- return PTR_ERR(page);
+ folio = f2fs_get_node_folio(F2FS_I_SB(dn->inode), dn->nid);
+ if (IS_ERR(folio)) {
+ trace_f2fs_truncate_nodes_exit(dn->inode, PTR_ERR(folio));
+ return PTR_ERR(folio);
}
- f2fs_ra_node_pages(page, ofs, NIDS_PER_BLOCK);
+ f2fs_ra_node_pages(&folio->page, ofs, NIDS_PER_BLOCK);
- rn = F2FS_NODE(page);
+ rn = F2FS_NODE(&folio->page);
if (depth < 3) {
for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) {
child_nid = le32_to_cpu(rn->in.nid[i]);
@@ -1028,7 +1028,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
ret = truncate_dnode(&rdn);
if (ret < 0)
goto out_err;
- if (set_nid(page, i, 0, false))
+ if (set_nid(&folio->page, i, 0, false))
dn->node_changed = true;
}
} else {
@@ -1042,7 +1042,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
rdn.nid = child_nid;
ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1);
if (ret == (NIDS_PER_BLOCK + 1)) {
- if (set_nid(page, i, 0, false))
+ if (set_nid(&folio->page, i, 0, false))
dn->node_changed = true;
child_nofs += ret;
} else if (ret < 0 && ret != -ENOENT) {
@@ -1054,19 +1054,19 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
if (!ofs) {
/* remove current indirect node */
- dn->node_page = page;
+ dn->node_page = &folio->page;
ret = truncate_node(dn);
if (ret)
goto out_err;
freed++;
} else {
- f2fs_put_page(page, 1);
+ f2fs_folio_put(folio, true);
}
trace_f2fs_truncate_nodes_exit(dn->inode, freed);
return freed;
out_err:
- f2fs_put_page(page, 1);
+ f2fs_folio_put(folio, true);
trace_f2fs_truncate_nodes_exit(dn->inode, ret);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 5/7] f2fs: Use folios in truncate_partial_nodes()
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
` (2 preceding siblings ...)
2026-09-12 1:32 ` [PATCH 6.12.y 4/7] f2fs: Use a folio in truncate_nodes() Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 6/7] f2fs: introduce is_{meta,node}_folio Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 7/7] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Sasha Levin
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox (Oracle), Chao Yu, Jaegeuk Kim, Sasha Levin
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
[ Upstream commit d68833a0b74e46edc678340cdff5ad22782c6609 ]
Removes two calls to compound_head().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 5fe77be55998d..1463488fcd832 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1074,7 +1074,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
static int truncate_partial_nodes(struct dnode_of_data *dn,
struct f2fs_inode *ri, int *offset, int depth)
{
- struct page *pages[2];
+ struct folio *folios[2];
nid_t nid[3];
nid_t child_nid;
int err = 0;
@@ -1088,45 +1088,45 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
/* get indirect nodes in the path */
for (i = 0; i < idx + 1; i++) {
/* reference count'll be increased */
- pages[i] = f2fs_get_node_page(F2FS_I_SB(dn->inode), nid[i]);
- if (IS_ERR(pages[i])) {
- err = PTR_ERR(pages[i]);
+ folios[i] = f2fs_get_node_folio(F2FS_I_SB(dn->inode), nid[i]);
+ if (IS_ERR(folios[i])) {
+ err = PTR_ERR(folios[i]);
idx = i - 1;
goto fail;
}
- nid[i + 1] = get_nid(pages[i], offset[i + 1], false);
+ nid[i + 1] = get_nid(&folios[i]->page, offset[i + 1], false);
}
- f2fs_ra_node_pages(pages[idx], offset[idx + 1], NIDS_PER_BLOCK);
+ f2fs_ra_node_pages(&folios[idx]->page, offset[idx + 1], NIDS_PER_BLOCK);
/* free direct nodes linked to a partial indirect node */
for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) {
- child_nid = get_nid(pages[idx], i, false);
+ child_nid = get_nid(&folios[idx]->page, i, false);
if (!child_nid)
continue;
dn->nid = child_nid;
err = truncate_dnode(dn);
if (err < 0)
goto fail;
- if (set_nid(pages[idx], i, 0, false))
+ if (set_nid(&folios[idx]->page, i, 0, false))
dn->node_changed = true;
}
if (offset[idx + 1] == 0) {
- dn->node_page = pages[idx];
+ dn->node_page = &folios[idx]->page;
dn->nid = nid[idx];
err = truncate_node(dn);
if (err)
goto fail;
} else {
- f2fs_put_page(pages[idx], 1);
+ f2fs_folio_put(folios[idx], true);
}
offset[idx]++;
offset[idx + 1] = 0;
idx--;
fail:
for (i = idx; i >= 0; i--)
- f2fs_put_page(pages[i], 1);
+ f2fs_folio_put(folios[i], true);
trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 6/7] f2fs: introduce is_{meta,node}_folio
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
` (3 preceding siblings ...)
2026-09-12 1:32 ` [PATCH 6.12.y 5/7] f2fs: Use folios in truncate_partial_nodes() Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 7/7] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Sasha Levin
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Chao Yu, Jaegeuk Kim, Sasha Levin
From: Chao Yu <chao@kernel.org>
[ Upstream commit 019a8912425e231511042a4eae48b7a9e459453c ]
Just cleanup, no changes.
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Adapt this dependency to the page-based 6.12 tree:
- Use single-evaluation macros for the folio mapping predicates, with a
NULL mapping check so that a truncated folio is rejected safely. Keep
the existing page interfaces and pass page_folio() at their call sites.
- Supply folio allocation, release and writeback adapters using the
existing page helpers. Earlier dependencies already use these missing
interfaces. Preserve allocation failures as ERR_PTR(-ENOMEM).
- Repair the existing f2fs_get_node_folio() wrapper to use __get_node_page()
and preserve error pointers; __get_node_folio() and NODE_TYPE_REGULAR
are not present in this stable tree.
- Use a local last_folio in the fsync retry block, matching the context
needed for ce366bfa821ec81dd45bde547ee31e659306cc61 to apply unchanged.
No new functions are introduced. The target's retry escape remains in
its own patch.
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/checkpoint.c | 4 ++--
fs/f2fs/data.c | 2 +-
fs/f2fs/f2fs.h | 26 ++++++++++++++++++++++++++
fs/f2fs/gc.c | 2 +-
fs/f2fs/node.c | 32 +++++++++++++++++++-------------
5 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 6322bf2e16228..03f2623a822fe 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -93,7 +93,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
f2fs_update_iostat(sbi, NULL, FS_META_READ_IO, F2FS_BLKSIZE);
lock_page(page);
- if (unlikely(page->mapping != mapping)) {
+ if (unlikely(!is_meta_folio(page_folio(page)))) {
f2fs_put_page(page, 1);
goto repeat;
}
@@ -453,7 +453,7 @@ long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
folio_lock(folio);
- if (unlikely(folio->mapping != mapping)) {
+ if (unlikely(!is_meta_folio(folio))) {
continue_unlock:
folio_unlock(folio);
continue;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index ec816df4887cc..a57dd4dc5fd2b 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -353,7 +353,7 @@ static void f2fs_write_end_io(struct bio *bio)
STOP_CP_REASON_WRITE_FAIL);
}
- f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
+ f2fs_bug_on(sbi, is_node_folio(page_folio(page)) &&
page_folio(page)->index != nid_of_node(page));
if (f2fs_in_warm_node_list(sbi, page))
f2fs_del_fsync_node_entry(sbi, page);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 67c5b9cb90ee6..a055673524f3c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2100,6 +2100,17 @@ static inline struct address_space *NODE_MAPPING(struct f2fs_sb_info *sbi)
return sbi->node_inode->i_mapping;
}
+/* The caller holds the folio lock or otherwise stabilizes its mapping. */
+#define is_meta_folio(folio) ({ \
+ struct address_space *__mapping = (folio)->mapping; \
+ __mapping && __mapping == META_MAPPING(F2FS_M_SB(__mapping)); \
+})
+
+#define is_node_folio(folio) ({ \
+ struct address_space *__mapping = (folio)->mapping; \
+ __mapping && __mapping == NODE_MAPPING(F2FS_M_SB(__mapping)); \
+})
+
static inline bool is_sbi_flag_set(struct f2fs_sb_info *sbi, unsigned int type)
{
return test_bit(type, &sbi->s_flag);
@@ -2868,6 +2879,13 @@ static inline struct page *f2fs_grab_cache_page(struct address_space *mapping,
return page;
}
+/* Folio adapters for the page-based stable-tree helpers. */
+#define f2fs_grab_cache_folio(mapping, index, for_write) ({ \
+ struct page *__page = f2fs_grab_cache_page(mapping, index, \
+ for_write); \
+ __page ? page_folio(__page) : ERR_PTR(-ENOMEM); \
+})
+
static inline struct page *f2fs_pagecache_get_page(
struct address_space *mapping, pgoff_t index,
fgf_t fgp_flags, gfp_t gfp_mask)
@@ -2890,6 +2908,12 @@ static inline void f2fs_put_page(struct page *page, int unlock)
put_page(page);
}
+#define f2fs_folio_put(_folio, unlock) do { \
+ struct folio *__folio = (_folio); \
+ if (!IS_ERR_OR_NULL(__folio)) \
+ f2fs_put_page(&__folio->page, unlock); \
+} while (0)
+
static inline void f2fs_put_dnode(struct dnode_of_data *dn)
{
if (dn->node_page)
@@ -3839,6 +3863,8 @@ void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
block_t blkaddr, unsigned int blkcnt);
void f2fs_wait_on_page_writeback(struct page *page,
enum page_type type, bool ordered, bool locked);
+#define f2fs_folio_wait_writeback(folio, type, ordered, locked) \
+ f2fs_wait_on_page_writeback(&(folio)->page, type, ordered, locked)
void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr);
void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
block_t len);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index fbd246b3e550a..f29d461bdb1ef 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -1425,7 +1425,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
F2FS_BLKSIZE);
folio_lock(mfolio);
- if (unlikely(mfolio->mapping != META_MAPPING(fio.sbi) ||
+ if (unlikely(!is_meta_folio(mfolio) ||
!folio_test_uptodate(mfolio))) {
err = -EIO;
f2fs_folio_put(mfolio, true);
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 1463488fcd832..ce75669332efc 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -317,7 +317,7 @@ static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
bool f2fs_in_warm_node_list(struct f2fs_sb_info *sbi, struct page *page)
{
- return NODE_MAPPING(sbi) == page->mapping &&
+ return is_node_folio(page_folio(page)) &&
IS_DNODE(page) && is_cold_node(page);
}
@@ -1234,7 +1234,7 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from)
if (offset[1] == 0 &&
ri->i_nid[offset[0] - NODE_DIR1_BLOCK]) {
lock_page(page);
- BUG_ON(page->mapping != NODE_MAPPING(sbi));
+ BUG_ON(!is_node_folio(page_folio(page)));
f2fs_wait_on_page_writeback(page, NODE, true, true);
ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
set_page_dirty(page);
@@ -1500,7 +1500,7 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
lock_page(page);
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+ if (unlikely(!is_node_folio(page_folio(page)))) {
f2fs_put_page(page, 1);
goto repeat;
}
@@ -1537,7 +1537,11 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid)
{
- return __get_node_folio(sbi, nid, NULL, 0, NODE_TYPE_REGULAR);
+ struct page *page = __get_node_page(sbi, nid, NULL, 0);
+
+ if (IS_ERR(page))
+ return ERR_CAST(page);
+ return page_folio(page);
}
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
@@ -1620,7 +1624,7 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
lock_page(page);
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+ if (unlikely(!is_node_folio(page_folio(page)))) {
continue_unlock:
unlock_page(page);
continue;
@@ -1854,7 +1858,7 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
lock_page(page);
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+ if (unlikely(!is_node_folio(page_folio(page)))) {
continue_unlock:
unlock_page(page);
continue;
@@ -1916,12 +1920,14 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
break;
}
if (!ret && atomic && !marked) {
+ struct folio *last_folio = page_folio(last_page);
+
f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
- ino, page_folio(last_page)->index);
- lock_page(last_page);
- f2fs_wait_on_page_writeback(last_page, NODE, true, true);
- set_page_dirty(last_page);
- unlock_page(last_page);
+ ino, last_folio->index);
+ folio_lock(last_folio);
+ f2fs_folio_wait_writeback(last_folio, NODE, true, true);
+ folio_mark_dirty(last_folio);
+ folio_unlock(last_folio);
goto retry;
}
out:
@@ -1992,7 +1998,7 @@ void f2fs_flush_inline_data(struct f2fs_sb_info *sbi)
lock_page(page);
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+ if (unlikely(!is_node_folio(page_folio(page)))) {
continue_unlock:
unlock_page(page);
continue;
@@ -2069,7 +2075,7 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
else if (!trylock_page(page))
continue;
- if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+ if (unlikely(!is_node_folio(page_folio(page)))) {
continue_unlock:
unlock_page(page);
continue;
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6.12.y 7/7] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
` (4 preceding siblings ...)
2026-09-12 1:32 ` [PATCH 6.12.y 6/7] f2fs: introduce is_{meta,node}_folio Sasha Levin
@ 2026-09-12 1:32 ` Sasha Levin
5 siblings, 0 replies; 8+ messages in thread
From: Sasha Levin @ 2026-09-12 1:32 UTC (permalink / raw)
To: stable; +Cc: Chao Yu, stable, Jaegeuk Kim, Sasha Levin
From: Chao Yu <chao@kernel.org>
[ Upstream commit ce366bfa821ec81dd45bde547ee31e659306cc61 ]
There is potential deadloop in race condition:
Thread A Thread B
- fsync
- f2fs_do_sync_file
- f2fs_fsync_node_pages
- last_fsync_dnode
- folio_get(last_folio)
- f2fs_setattr
- f2fs_truncate
- f2fs_truncate_blocks
- f2fs_do_truncate_blocks
- f2fs_truncate_inode_blocks
- truncate_dnode
- truncate_node
- invalidate_mapping_pages
- folio->mapping = NULL
- is_node_folio alwasy return false
- atomic && !marked is always true,
then goto retry
Cc: stable@kernel.org
Fixes: 608514deba38 ("f2fs: set fsync mark only for the last dnode")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index ce75669332efc..c04caeccefa98 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1925,6 +1925,11 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
ino, last_folio->index);
folio_lock(last_folio);
+ if (unlikely(!is_node_folio(last_folio))) {
+ f2fs_folio_put(last_folio, true);
+ ret = -EAGAIN;
+ goto out;
+ }
f2fs_folio_wait_writeback(last_folio, NODE, true, true);
folio_mark_dirty(last_folio);
folio_unlock(last_folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-12 1:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 11:26 FAILED: patch "[PATCH] f2fs: fix to avoid potential deadloop in" failed to apply to 6.12-stable tree gregkh
2026-09-12 1:32 ` [PATCH 6.12.y 1/7] f2fs: Use a folio in move_data_block() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 3/7] f2fs: Add f2fs_get_node_folio() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 4/7] f2fs: Use a folio in truncate_nodes() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 5/7] f2fs: Use folios in truncate_partial_nodes() Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 6/7] f2fs: introduce is_{meta,node}_folio Sasha Levin
2026-09-12 1:32 ` [PATCH 6.12.y 7/7] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).