FAILED: patch "[PATCH] f2fs: fix to avoid potential deadloop in" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe 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 <[email protected]>.
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 '<[email protected]>' --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 <[email protected]>
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
fs/f2fs/node.c +5 -0
@@ -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);
Sasha Levin
maintainerPATCH 1/7 f2fs: Use a folio in move_data_block()
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ 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.
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
--- fs/f2fs/gc.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-)
fs/f2fs/gc.c +17 -16
@@ -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);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/7 f2fs: Add f2fs_new_node_folio()
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ 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().
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
--- fs/f2fs/f2fs.h | 8 +++++++- fs/f2fs/node.c | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 15 deletions(-)
fs/f2fs/f2fs.h +7 -1
@@ -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 */
fs/f2fs/node.c +14 -14
@@ -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); }
Signature · 1 line
2.53.0
Re: [PATCH 6.12.y 2/7] f2fs: Add f2fs_new_node_folio()
Quoted 109 lines · Sasha Levin
From: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit
cfa809146f8223c2953e7553f830c0877921f9de]Convert
f2fs_new_node_page()tof2fs_new_node_folio()and add a compatibility wrapper. Removes five hidden calls tocompound_head().Signed-off-by Matthew Wilcox (Oracle) <[email protected]>Reviewed-by Chao Yu <[email protected]>Signed-off-by Jaegeuk Kim <[email protected]>Stable-dep-of:
ce366bfa821e("f2fs: fix to avoid potential deadloop inf2fs_fsync_node_pages()")Signed-off-by Sasha Levin <[email protected]>--- fs/f2fs/f2fs.h | 8 +++++++- fs/f2fs/node.c | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 15 deletions(-)fs/f2fs/f2fs.h +7
-1@@ -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 */ fs/f2fs/node.c +14
-14@@ -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); }Signature · 1 line
2.53.0
Did not apply
Sasha Levin
maintainerPATCH 3/7 f2fs: Add f2fs_get_node_folio()
In reply to Sasha LevinFrom: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit aa220cede54ed671f7be413d8dacb91263a9d218 ]
The folio equivalent of f2fs_get_node_page().
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
--- fs/f2fs/f2fs.h | 1 + fs/f2fs/node.c | 5 +++++ 2 files changed, 6 insertions(+)
fs/f2fs/f2fs.h +1 -0
@@ -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);
fs/f2fs/node.c +5 -0
@@ -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 );
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/7 f2fs: Use a folio in truncate_nodes()
In reply to Sasha LevinFrom: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit 878a05b09c0c578b679956431cd2be5cc3689403 ]
Remove two calls to compound_head().
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
--- fs/f2fs/node.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
fs/f2fs/node.c +12 -12
@@ -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; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/7 f2fs: Use folios in truncate_partial_nodes()
In reply to Sasha LevinFrom: "Matthew Wilcox (Oracle)" <[email protected]>
[ Upstream commit d68833a0b74e46edc678340cdff5ad22782c6609 ]
Removes two calls to compound_head().
Stable-dep-of: ce366bfa821e ("f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()")
--- fs/f2fs/node.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
fs/f2fs/node.c +11 -11
@@ -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);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 6/7 f2fs: introduce is_{meta,node}_folio
In reply to Sasha LevinFrom: Chao Yu <[email protected]>
[ Upstream commit 019a8912425e231511042a4eae48b7a9e459453c ]
Just cleanup, no changes.
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()")
--- 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(-)
fs/f2fs/checkpoint.c +2 -2
@@ -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 ;
fs/f2fs/data.c +1 -1
@@ -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);
fs/f2fs/f2fs.h +26 -0
@@ -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);
fs/f2fs/gc.c +1 -1
@@ -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);
fs/f2fs/node.c +19 -13
@@ -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 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 7/7 f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()
In reply to Sasha LevinFrom: Chao Yu <[email protected]>
[ 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
--- fs/f2fs/node.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/f2fs/node.c +5 -0
@@ -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);
Signature · 1 line
2.53.0