* [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page()
@ 2025-03-03 3:54 Chao Yu
2025-03-03 3:54 ` [PATCH 2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() Chao Yu
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Chao Yu @ 2025-03-03 3:54 UTC (permalink / raw)
To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu
This patch introduces a new wrapper f2fs_get_inode_page(), then, caller
can use it to load inode block to page cache, meanwhile it will do sanity
check on inode footer.
Signed-off-by: Chao Yu <chao@kernel.org>
---
fs/f2fs/data.c | 6 ++---
fs/f2fs/dir.c | 2 +-
fs/f2fs/f2fs.h | 3 ++-
fs/f2fs/file.c | 2 +-
fs/f2fs/inline.c | 22 +++++++++----------
fs/f2fs/inode.c | 4 ++--
fs/f2fs/node.c | 57 +++++++++++++++++++++++++++++++++---------------
fs/f2fs/node.h | 6 +++++
fs/f2fs/xattr.c | 4 ++--
9 files changed, 67 insertions(+), 39 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f1554a5a3d7a..e29d15d637ff 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -3402,7 +3402,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
restart:
/* check inline_data */
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto unlock_out;
@@ -3465,7 +3465,7 @@ static int __find_data_block(struct inode *inode, pgoff_t index,
struct page *ipage;
int err = 0;
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
@@ -3495,7 +3495,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index,
f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto unlock_out;
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 4c74f29a2c73..acd5b2e3e966 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -552,7 +552,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
goto put_error;
}
} else {
- page = f2fs_get_node_page(F2FS_I_SB(dir), inode->i_ino);
+ page = f2fs_get_inode_page(F2FS_I_SB(dir), inode->i_ino);
if (IS_ERR(page))
return page;
}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e45c204c36ec..74a80bb06f06 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3702,7 +3702,8 @@ struct page *f2fs_new_inode_page(struct inode *inode);
struct page *f2fs_new_node_page(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 folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid);
+struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino);
+struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino);
struct page *f2fs_get_node_page_ra(struct page *parent, int start);
int f2fs_move_node_page(struct page *node_page, int gc_type);
void f2fs_flush_inline_data(struct f2fs_sb_info *sbi);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index cd8d366b2fd7..d21fd2ef8bf8 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -761,7 +761,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
if (lock)
f2fs_lock_op(sbi);
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto out;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 3e3c35d4c98b..ad92e9008781 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -119,7 +119,7 @@ int f2fs_read_inline_data(struct inode *inode, struct folio *folio)
{
struct page *ipage;
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage)) {
folio_unlock(folio);
return PTR_ERR(ipage);
@@ -237,7 +237,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
f2fs_lock_op(sbi);
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto out;
@@ -265,7 +265,7 @@ int f2fs_write_inline_data(struct inode *inode, struct folio *folio)
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *ipage;
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
@@ -312,7 +312,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage)
if (f2fs_has_inline_data(inode) &&
ri && (ri->i_inline & F2FS_INLINE_DATA)) {
process_inline:
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
@@ -331,7 +331,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage)
}
if (f2fs_has_inline_data(inode)) {
- ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ ipage = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
f2fs_truncate_inline_inode(inode, ipage, 0);
@@ -361,7 +361,7 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
struct page *ipage;
void *inline_dentry;
- ipage = f2fs_get_node_page(sbi, dir->i_ino);
+ ipage = f2fs_get_inode_page(sbi, dir->i_ino);
if (IS_ERR(ipage)) {
*res_page = ipage;
return NULL;
@@ -609,7 +609,7 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
- ipage = f2fs_get_node_page(sbi, dir->i_ino);
+ ipage = f2fs_get_inode_page(sbi, dir->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto out_fname;
@@ -644,7 +644,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname,
struct page *page = NULL;
int err = 0;
- ipage = f2fs_get_node_page(sbi, dir->i_ino);
+ ipage = f2fs_get_inode_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
@@ -734,7 +734,7 @@ bool f2fs_empty_inline_dir(struct inode *dir)
void *inline_dentry;
struct f2fs_dentry_ptr d;
- ipage = f2fs_get_node_page(sbi, dir->i_ino);
+ ipage = f2fs_get_inode_page(sbi, dir->i_ino);
if (IS_ERR(ipage))
return false;
@@ -765,7 +765,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
if (ctx->pos == d.max)
return 0;
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
@@ -797,7 +797,7 @@ int f2fs_inline_data_fiemap(struct inode *inode,
struct page *ipage;
int err = 0;
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 6aec752ac098..aa2f41696a88 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -410,7 +410,7 @@ static int do_read_inode(struct inode *inode)
if (f2fs_check_nid_range(sbi, inode->i_ino))
return -EINVAL;
- node_page = f2fs_get_node_page(sbi, inode->i_ino);
+ node_page = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(node_page))
return PTR_ERR(node_page);
@@ -757,7 +757,7 @@ void f2fs_update_inode_page(struct inode *inode)
struct page *node_page;
int count = 0;
retry:
- node_page = f2fs_get_node_page(sbi, inode->i_ino);
+ node_page = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(node_page)) {
int err = PTR_ERR(node_page);
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 36614a1c2590..ee5daa6f7408 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -778,7 +778,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
npage[0] = dn->inode_page;
if (!npage[0]) {
- npage[0] = f2fs_get_node_page(sbi, nids[0]);
+ npage[0] = f2fs_get_inode_page(sbi, nids[0]);
if (IS_ERR(npage[0]))
return PTR_ERR(npage[0]);
}
@@ -1147,7 +1147,7 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from)
return level;
}
- folio = f2fs_get_node_folio(sbi, inode->i_ino);
+ folio = f2fs_get_inode_folio(sbi, inode->i_ino);
if (IS_ERR(folio)) {
trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(folio));
return PTR_ERR(folio);
@@ -1456,8 +1456,27 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
f2fs_put_page(apage, err ? 1 : 0);
}
+static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
+ struct page *page, pgoff_t nid,
+ enum node_type ntype)
+{
+ if (unlikely(nid != nid_of_node(page) ||
+ (ntype == NODE_TYPE_INODE && !IS_INODE(page)))) {
+ f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
+ "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
+ ntype, nid, nid_of_node(page), ino_of_node(page),
+ ofs_of_node(page), cpver_of_node(page),
+ next_blkaddr_of_node(page));
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
+ return -EFSCORRUPTED;
+ }
+ return 0;
+}
+
static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
- struct page *parent, int start)
+ struct page *parent, int start,
+ enum node_type ntype)
{
struct folio *folio;
int err;
@@ -1499,16 +1518,9 @@ static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
goto out_err;
}
page_hit:
- if (likely(nid == nid_of_node(&folio->page)))
+ err = sanity_check_node_footer(sbi, &folio->page, nid, ntype);
+ if (!err)
return folio;
-
- f2fs_warn(sbi, "inconsistent node block, nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
- nid, nid_of_node(&folio->page), ino_of_node(&folio->page),
- ofs_of_node(&folio->page), cpver_of_node(&folio->page),
- next_blkaddr_of_node(&folio->page));
- set_sbi_flag(sbi, SBI_NEED_FSCK);
- f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
- err = -EFSCORRUPTED;
out_err:
folio_clear_uptodate(folio);
out_put_err:
@@ -1519,14 +1531,22 @@ static struct folio *__get_node_folio(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)
+struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
+{
+ struct folio *folio = __get_node_folio(sbi, nid, NULL, 0,
+ NODE_TYPE_REGULAR);
+
+ return &folio->page;
+}
+
+struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino)
{
- return __get_node_folio(sbi, nid, NULL, 0);
+ return __get_node_folio(sbi, ino, NULL, 0, NODE_TYPE_REGULAR);
}
-struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
+struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino)
{
- struct folio *folio = __get_node_folio(sbi, nid, NULL, 0);
+ struct folio *folio = f2fs_get_inode_folio(sbi, ino);
return &folio->page;
}
@@ -1535,7 +1555,8 @@ struct page *f2fs_get_node_page_ra(struct page *parent, int start)
{
struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
nid_t nid = get_nid(parent, start, false);
- struct folio *folio = __get_node_folio(sbi, nid, parent, start);
+ struct folio *folio = __get_node_folio(sbi, nid, parent, start,
+ NODE_TYPE_REGULAR);
return &folio->page;
}
@@ -2727,7 +2748,7 @@ int f2fs_recover_inline_xattr(struct inode *inode, struct page *page)
struct page *ipage;
struct f2fs_inode *ri;
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage))
return PTR_ERR(ipage);
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 281d53c95c9a..5079c6a2298d 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -52,6 +52,12 @@ enum {
IS_PREALLOC, /* nat entry is preallocated */
};
+/* For node type in __get_node_folio() */
+enum node_type {
+ NODE_TYPE_REGULAR,
+ NODE_TYPE_INODE,
+};
+
/*
* For node information
*/
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 3f3874943679..d5b42e1005d8 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -282,7 +282,7 @@ static int read_inline_xattr(struct inode *inode, struct page *ipage,
if (ipage) {
inline_addr = inline_xattr_addr(inode, ipage);
} else {
- page = f2fs_get_node_page(sbi, inode->i_ino);
+ page = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(page))
return PTR_ERR(page);
@@ -449,7 +449,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
if (ipage) {
inline_addr = inline_xattr_addr(inode, ipage);
} else {
- in_page = f2fs_get_node_page(sbi, inode->i_ino);
+ in_page = f2fs_get_inode_page(sbi, inode->i_ino);
if (IS_ERR(in_page)) {
f2fs_alloc_nid_failed(sbi, new_nid);
return PTR_ERR(in_page);
--
2.48.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() 2025-03-03 3:54 [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() Chao Yu @ 2025-03-03 3:54 ` Chao Yu 2025-03-03 3:54 ` [PATCH 3/3] f2fs: introduce FAULT_INCONSISTENT_FOOTER Chao Yu ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Chao Yu @ 2025-03-03 3:54 UTC (permalink / raw) To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu This patch introduces a new wrapper f2fs_get_xnode_page(), then, caller can use it to load xattr block to page cache, meanwhile it will do sanity check on xattr node footer. Signed-off-by: Chao Yu <chao@kernel.org> --- fs/f2fs/f2fs.h | 1 + fs/f2fs/node.c | 14 ++++++++++++-- fs/f2fs/node.h | 1 + fs/f2fs/xattr.c | 4 ++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 74a80bb06f06..38016d24e59c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3704,6 +3704,7 @@ 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 folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino); struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino); +struct page *f2fs_get_xnode_page(struct f2fs_sb_info *sbi, pgoff_t xnid); struct page *f2fs_get_node_page_ra(struct page *parent, int start); int f2fs_move_node_page(struct page *node_page, int gc_type); void f2fs_flush_inline_data(struct f2fs_sb_info *sbi); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index ee5daa6f7408..5be8badc6261 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1245,7 +1245,7 @@ int f2fs_truncate_xattr_node(struct inode *inode) if (!nid) return 0; - npage = f2fs_get_node_page(sbi, nid); + npage = f2fs_get_xnode_page(sbi, nid); if (IS_ERR(npage)) return PTR_ERR(npage); @@ -1461,7 +1461,9 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi, enum node_type ntype) { if (unlikely(nid != nid_of_node(page) || - (ntype == NODE_TYPE_INODE && !IS_INODE(page)))) { + (ntype == NODE_TYPE_INODE && !IS_INODE(page)) || + (ntype == NODE_TYPE_XATTR && + !f2fs_has_xattr_block(ofs_of_node(page))))) { f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", ntype, nid, nid_of_node(page), ino_of_node(page), @@ -1551,6 +1553,14 @@ struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino) return &folio->page; } +struct page *f2fs_get_xnode_page(struct f2fs_sb_info *sbi, pgoff_t xnid) +{ + struct folio *folio = __get_node_folio(sbi, xnid, NULL, 0, + NODE_TYPE_XATTR); + + return &folio->page; +} + struct page *f2fs_get_node_page_ra(struct page *parent, int start) { struct f2fs_sb_info *sbi = F2FS_P_SB(parent); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 5079c6a2298d..103a437e6425 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -56,6 +56,7 @@ enum { enum node_type { NODE_TYPE_REGULAR, NODE_TYPE_INODE, + NODE_TYPE_XATTR, }; /* diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index d5b42e1005d8..c691b35618ad 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -303,7 +303,7 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr) void *xattr_addr; /* The inode already has an extended attribute block. */ - xpage = f2fs_get_node_page(sbi, xnid); + xpage = f2fs_get_xnode_page(sbi, xnid); if (IS_ERR(xpage)) return PTR_ERR(xpage); @@ -475,7 +475,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, /* write to xattr node block */ if (F2FS_I(inode)->i_xattr_nid) { - xpage = f2fs_get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); + xpage = f2fs_get_xnode_page(sbi, F2FS_I(inode)->i_xattr_nid); if (IS_ERR(xpage)) { err = PTR_ERR(xpage); f2fs_alloc_nid_failed(sbi, new_nid); -- 2.48.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] f2fs: introduce FAULT_INCONSISTENT_FOOTER 2025-03-03 3:54 [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() Chao Yu 2025-03-03 3:54 ` [PATCH 2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() Chao Yu @ 2025-03-03 3:54 ` Chao Yu 2025-03-04 17:10 ` [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() patchwork-bot+f2fs 2025-03-05 6:39 ` Zhiguo Niu 3 siblings, 0 replies; 6+ messages in thread From: Chao Yu @ 2025-03-03 3:54 UTC (permalink / raw) To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu To simulate inconsistent node footer error. Signed-off-by: Chao Yu <chao@kernel.org> --- Documentation/ABI/testing/sysfs-fs-f2fs | 1 + Documentation/filesystems/f2fs.rst | 1 + fs/f2fs/f2fs.h | 1 + fs/f2fs/node.c | 3 ++- fs/f2fs/super.c | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 81deae2af84d..b9a000e5098a 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -734,6 +734,7 @@ Description: Support configuring fault injection type, should be FAULT_BLKADDR_VALIDITY 0x000040000 FAULT_BLKADDR_CONSISTENCE 0x000080000 FAULT_NO_SEGMENT 0x000100000 + FAULT_INCONSISTENT_FOOTER 0x000200000 =========================== =========== What: /sys/fs/f2fs/<disk>/discard_io_aware_gran diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index fb7d2ee022bc..42f28dbf2410 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -206,6 +206,7 @@ fault_type=%d Support configuring fault injection type, should be FAULT_BLKADDR_VALIDITY 0x000040000 FAULT_BLKADDR_CONSISTENCE 0x000080000 FAULT_NO_SEGMENT 0x000100000 + FAULT_INCONSISTENT_FOOTER 0x000200000 =========================== =========== mode=%s Control block allocation mode which supports "adaptive" and "lfs". In "lfs" mode, there should be no random diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 38016d24e59c..99cc933faf8c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -62,6 +62,7 @@ enum { FAULT_BLKADDR_VALIDITY, FAULT_BLKADDR_CONSISTENCE, FAULT_NO_SEGMENT, + FAULT_INCONSISTENT_FOOTER, FAULT_MAX, }; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 5be8badc6261..58803cab2235 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1463,7 +1463,8 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi, if (unlikely(nid != nid_of_node(page) || (ntype == NODE_TYPE_INODE && !IS_INODE(page)) || (ntype == NODE_TYPE_XATTR && - !f2fs_has_xattr_block(ofs_of_node(page))))) { + !f2fs_has_xattr_block(ofs_of_node(page))) || + time_to_inject(sbi, FAULT_INCONSISTENT_FOOTER))) { f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", ntype, nid, nid_of_node(page), ino_of_node(page), diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 7a8fcc1e278c..3a7e4e8ab010 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -63,6 +63,7 @@ const char *f2fs_fault_name[FAULT_MAX] = { [FAULT_BLKADDR_VALIDITY] = "invalid blkaddr", [FAULT_BLKADDR_CONSISTENCE] = "inconsistent blkaddr", [FAULT_NO_SEGMENT] = "no free segment", + [FAULT_INCONSISTENT_FOOTER] = "inconsistent footer", }; int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate, -- 2.48.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() 2025-03-03 3:54 [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() Chao Yu 2025-03-03 3:54 ` [PATCH 2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() Chao Yu 2025-03-03 3:54 ` [PATCH 3/3] f2fs: introduce FAULT_INCONSISTENT_FOOTER Chao Yu @ 2025-03-04 17:10 ` patchwork-bot+f2fs 2025-03-05 6:39 ` Zhiguo Niu 3 siblings, 0 replies; 6+ messages in thread From: patchwork-bot+f2fs @ 2025-03-04 17:10 UTC (permalink / raw) To: Chao Yu; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel Hello: This series was applied to jaegeuk/f2fs.git (dev) by Jaegeuk Kim <jaegeuk@kernel.org>: On Mon, 3 Mar 2025 11:54:21 +0800 you wrote: > This patch introduces a new wrapper f2fs_get_inode_page(), then, caller > can use it to load inode block to page cache, meanwhile it will do sanity > check on inode footer. > > Signed-off-by: Chao Yu <chao@kernel.org> > --- > fs/f2fs/data.c | 6 ++--- > fs/f2fs/dir.c | 2 +- > fs/f2fs/f2fs.h | 3 ++- > fs/f2fs/file.c | 2 +- > fs/f2fs/inline.c | 22 +++++++++---------- > fs/f2fs/inode.c | 4 ++-- > fs/f2fs/node.c | 57 +++++++++++++++++++++++++++++++++--------------- > fs/f2fs/node.h | 6 +++++ > fs/f2fs/xattr.c | 4 ++-- > 9 files changed, 67 insertions(+), 39 deletions(-) Here is the summary with links: - [f2fs-dev,1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() https://git.kernel.org/jaegeuk/f2fs/c/770648dd6abc - [f2fs-dev,2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() https://git.kernel.org/jaegeuk/f2fs/c/1078ec609e0a - [f2fs-dev,3/3] f2fs: introduce FAULT_INCONSISTENT_FOOTER https://git.kernel.org/jaegeuk/f2fs/c/4116a6f1172c You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() 2025-03-03 3:54 [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() Chao Yu ` (2 preceding siblings ...) 2025-03-04 17:10 ` [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() patchwork-bot+f2fs @ 2025-03-05 6:39 ` Zhiguo Niu 2025-03-05 8:27 ` Chao Yu 3 siblings, 1 reply; 6+ messages in thread From: Zhiguo Niu @ 2025-03-05 6:39 UTC (permalink / raw) To: Chao Yu; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel Chao Yu via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net> 于2025年3月3日周一 11:57写道: > > This patch introduces a new wrapper f2fs_get_inode_page(), then, caller > can use it to load inode block to page cache, meanwhile it will do sanity > check on inode footer. > > Signed-off-by: Chao Yu <chao@kernel.org> > --- > fs/f2fs/data.c | 6 ++--- > fs/f2fs/dir.c | 2 +- > fs/f2fs/f2fs.h | 3 ++- > fs/f2fs/file.c | 2 +- > fs/f2fs/inline.c | 22 +++++++++---------- > fs/f2fs/inode.c | 4 ++-- > fs/f2fs/node.c | 57 +++++++++++++++++++++++++++++++++--------------- > fs/f2fs/node.h | 6 +++++ > fs/f2fs/xattr.c | 4 ++-- > 9 files changed, 67 insertions(+), 39 deletions(-) > > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c > index f1554a5a3d7a..e29d15d637ff 100644 > --- a/fs/f2fs/data.c > +++ b/fs/f2fs/data.c > @@ -3402,7 +3402,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, > > restart: > /* check inline_data */ > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) { > err = PTR_ERR(ipage); > goto unlock_out; > @@ -3465,7 +3465,7 @@ static int __find_data_block(struct inode *inode, pgoff_t index, > struct page *ipage; > int err = 0; > > - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); > + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > @@ -3495,7 +3495,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index, > > f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); > > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) { > err = PTR_ERR(ipage); > goto unlock_out; > diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c > index 4c74f29a2c73..acd5b2e3e966 100644 > --- a/fs/f2fs/dir.c > +++ b/fs/f2fs/dir.c > @@ -552,7 +552,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir, > goto put_error; > } > } else { > - page = f2fs_get_node_page(F2FS_I_SB(dir), inode->i_ino); > + page = f2fs_get_inode_page(F2FS_I_SB(dir), inode->i_ino); > if (IS_ERR(page)) > return page; > } > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index e45c204c36ec..74a80bb06f06 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -3702,7 +3702,8 @@ struct page *f2fs_new_inode_page(struct inode *inode); > struct page *f2fs_new_node_page(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 folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid); > +struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino); > +struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino); > struct page *f2fs_get_node_page_ra(struct page *parent, int start); > int f2fs_move_node_page(struct page *node_page, int gc_type); > void f2fs_flush_inline_data(struct f2fs_sb_info *sbi); > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > index cd8d366b2fd7..d21fd2ef8bf8 100644 > --- a/fs/f2fs/file.c > +++ b/fs/f2fs/file.c > @@ -761,7 +761,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock) > if (lock) > f2fs_lock_op(sbi); > > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) { > err = PTR_ERR(ipage); > goto out; > diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c > index 3e3c35d4c98b..ad92e9008781 100644 > --- a/fs/f2fs/inline.c > +++ b/fs/f2fs/inline.c > @@ -119,7 +119,7 @@ int f2fs_read_inline_data(struct inode *inode, struct folio *folio) > { > struct page *ipage; > > - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); > + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); > if (IS_ERR(ipage)) { > folio_unlock(folio); > return PTR_ERR(ipage); > @@ -237,7 +237,7 @@ int f2fs_convert_inline_inode(struct inode *inode) > > f2fs_lock_op(sbi); > > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) { > err = PTR_ERR(ipage); > goto out; > @@ -265,7 +265,7 @@ int f2fs_write_inline_data(struct inode *inode, struct folio *folio) > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > struct page *ipage; > > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > @@ -312,7 +312,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage) > if (f2fs_has_inline_data(inode) && > ri && (ri->i_inline & F2FS_INLINE_DATA)) { > process_inline: > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > @@ -331,7 +331,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage) > } > > if (f2fs_has_inline_data(inode)) { > - ipage = f2fs_get_node_page(sbi, inode->i_ino); > + ipage = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > f2fs_truncate_inline_inode(inode, ipage, 0); > @@ -361,7 +361,7 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, > struct page *ipage; > void *inline_dentry; > > - ipage = f2fs_get_node_page(sbi, dir->i_ino); > + ipage = f2fs_get_inode_page(sbi, dir->i_ino); > if (IS_ERR(ipage)) { > *res_page = ipage; > return NULL; > @@ -609,7 +609,7 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry) > if (err) > goto out; > > - ipage = f2fs_get_node_page(sbi, dir->i_ino); > + ipage = f2fs_get_inode_page(sbi, dir->i_ino); > if (IS_ERR(ipage)) { > err = PTR_ERR(ipage); > goto out_fname; > @@ -644,7 +644,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname, > struct page *page = NULL; > int err = 0; > > - ipage = f2fs_get_node_page(sbi, dir->i_ino); > + ipage = f2fs_get_inode_page(sbi, dir->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > @@ -734,7 +734,7 @@ bool f2fs_empty_inline_dir(struct inode *dir) > void *inline_dentry; > struct f2fs_dentry_ptr d; > > - ipage = f2fs_get_node_page(sbi, dir->i_ino); > + ipage = f2fs_get_inode_page(sbi, dir->i_ino); > if (IS_ERR(ipage)) > return false; > > @@ -765,7 +765,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, > if (ctx->pos == d.max) > return 0; > > - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); > + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > @@ -797,7 +797,7 @@ int f2fs_inline_data_fiemap(struct inode *inode, > struct page *ipage; > int err = 0; > > - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); > + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c > index 6aec752ac098..aa2f41696a88 100644 > --- a/fs/f2fs/inode.c > +++ b/fs/f2fs/inode.c > @@ -410,7 +410,7 @@ static int do_read_inode(struct inode *inode) > if (f2fs_check_nid_range(sbi, inode->i_ino)) > return -EINVAL; > > - node_page = f2fs_get_node_page(sbi, inode->i_ino); > + node_page = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(node_page)) > return PTR_ERR(node_page); > > @@ -757,7 +757,7 @@ void f2fs_update_inode_page(struct inode *inode) > struct page *node_page; > int count = 0; > retry: > - node_page = f2fs_get_node_page(sbi, inode->i_ino); > + node_page = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(node_page)) { > int err = PTR_ERR(node_page); > > diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c > index 36614a1c2590..ee5daa6f7408 100644 > --- a/fs/f2fs/node.c > +++ b/fs/f2fs/node.c > @@ -778,7 +778,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) > npage[0] = dn->inode_page; > > if (!npage[0]) { > - npage[0] = f2fs_get_node_page(sbi, nids[0]); > + npage[0] = f2fs_get_inode_page(sbi, nids[0]); > if (IS_ERR(npage[0])) > return PTR_ERR(npage[0]); > } > @@ -1147,7 +1147,7 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from) > return level; > } > > - folio = f2fs_get_node_folio(sbi, inode->i_ino); > + folio = f2fs_get_inode_folio(sbi, inode->i_ino); > if (IS_ERR(folio)) { > trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(folio)); > return PTR_ERR(folio); > @@ -1456,8 +1456,27 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) > f2fs_put_page(apage, err ? 1 : 0); > } > > +static int sanity_check_node_footer(struct f2fs_sb_info *sbi, > + struct page *page, pgoff_t nid, > + enum node_type ntype) > +{ > + if (unlikely(nid != nid_of_node(page) || > + (ntype == NODE_TYPE_INODE && !IS_INODE(page)))) { > + f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " > + "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", > + ntype, nid, nid_of_node(page), ino_of_node(page), > + ofs_of_node(page), cpver_of_node(page), > + next_blkaddr_of_node(page)); > + set_sbi_flag(sbi, SBI_NEED_FSCK); > + f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); > + return -EFSCORRUPTED; > + } > + return 0; > +} > + > static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid, > - struct page *parent, int start) > + struct page *parent, int start, > + enum node_type ntype) > { > struct folio *folio; > int err; > @@ -1499,16 +1518,9 @@ static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid, > goto out_err; > } > page_hit: > - if (likely(nid == nid_of_node(&folio->page))) > + err = sanity_check_node_footer(sbi, &folio->page, nid, ntype); > + if (!err) > return folio; > - > - f2fs_warn(sbi, "inconsistent node block, nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", > - nid, nid_of_node(&folio->page), ino_of_node(&folio->page), > - ofs_of_node(&folio->page), cpver_of_node(&folio->page), > - next_blkaddr_of_node(&folio->page)); > - set_sbi_flag(sbi, SBI_NEED_FSCK); > - f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); > - err = -EFSCORRUPTED; > out_err: > folio_clear_uptodate(folio); > out_put_err: > @@ -1519,14 +1531,22 @@ static struct folio *__get_node_folio(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) > +struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) > +{ > + struct folio *folio = __get_node_folio(sbi, nid, NULL, 0, > + NODE_TYPE_REGULAR); > + > + return &folio->page; > +} > + > +struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino) > { > - return __get_node_folio(sbi, nid, NULL, 0); > + return __get_node_folio(sbi, ino, NULL, 0, NODE_TYPE_REGULAR); Hi Chao, here should return __get_node_folio(sbi, ino, NULL, 0, NODE_TYPE_INODE); ? thanks! > } > > -struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) > +struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino) > { > - struct folio *folio = __get_node_folio(sbi, nid, NULL, 0); > + struct folio *folio = f2fs_get_inode_folio(sbi, ino); > > return &folio->page; > } > @@ -1535,7 +1555,8 @@ struct page *f2fs_get_node_page_ra(struct page *parent, int start) > { > struct f2fs_sb_info *sbi = F2FS_P_SB(parent); > nid_t nid = get_nid(parent, start, false); > - struct folio *folio = __get_node_folio(sbi, nid, parent, start); > + struct folio *folio = __get_node_folio(sbi, nid, parent, start, > + NODE_TYPE_REGULAR); > > return &folio->page; > } > @@ -2727,7 +2748,7 @@ int f2fs_recover_inline_xattr(struct inode *inode, struct page *page) > struct page *ipage; > struct f2fs_inode *ri; > > - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); > + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); > if (IS_ERR(ipage)) > return PTR_ERR(ipage); > > diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h > index 281d53c95c9a..5079c6a2298d 100644 > --- a/fs/f2fs/node.h > +++ b/fs/f2fs/node.h > @@ -52,6 +52,12 @@ enum { > IS_PREALLOC, /* nat entry is preallocated */ > }; > > +/* For node type in __get_node_folio() */ > +enum node_type { > + NODE_TYPE_REGULAR, > + NODE_TYPE_INODE, > +}; > + > /* > * For node information > */ > diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c > index 3f3874943679..d5b42e1005d8 100644 > --- a/fs/f2fs/xattr.c > +++ b/fs/f2fs/xattr.c > @@ -282,7 +282,7 @@ static int read_inline_xattr(struct inode *inode, struct page *ipage, > if (ipage) { > inline_addr = inline_xattr_addr(inode, ipage); > } else { > - page = f2fs_get_node_page(sbi, inode->i_ino); > + page = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(page)) > return PTR_ERR(page); > > @@ -449,7 +449,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, > if (ipage) { > inline_addr = inline_xattr_addr(inode, ipage); > } else { > - in_page = f2fs_get_node_page(sbi, inode->i_ino); > + in_page = f2fs_get_inode_page(sbi, inode->i_ino); > if (IS_ERR(in_page)) { > f2fs_alloc_nid_failed(sbi, new_nid); > return PTR_ERR(in_page); > -- > 2.48.1 > > > > _______________________________________________ > Linux-f2fs-devel mailing list > Linux-f2fs-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() 2025-03-05 6:39 ` Zhiguo Niu @ 2025-03-05 8:27 ` Chao Yu 0 siblings, 0 replies; 6+ messages in thread From: Chao Yu @ 2025-03-05 8:27 UTC (permalink / raw) To: Zhiguo Niu; +Cc: chao, jaegeuk, linux-kernel, linux-f2fs-devel On 3/5/25 14:39, Zhiguo Niu wrote: > Chao Yu via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net> > 于2025年3月3日周一 11:57写道: >> >> This patch introduces a new wrapper f2fs_get_inode_page(), then, caller >> can use it to load inode block to page cache, meanwhile it will do sanity >> check on inode footer. >> >> Signed-off-by: Chao Yu <chao@kernel.org> >> --- >> fs/f2fs/data.c | 6 ++--- >> fs/f2fs/dir.c | 2 +- >> fs/f2fs/f2fs.h | 3 ++- >> fs/f2fs/file.c | 2 +- >> fs/f2fs/inline.c | 22 +++++++++---------- >> fs/f2fs/inode.c | 4 ++-- >> fs/f2fs/node.c | 57 +++++++++++++++++++++++++++++++++--------------- >> fs/f2fs/node.h | 6 +++++ >> fs/f2fs/xattr.c | 4 ++-- >> 9 files changed, 67 insertions(+), 39 deletions(-) >> >> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c >> index f1554a5a3d7a..e29d15d637ff 100644 >> --- a/fs/f2fs/data.c >> +++ b/fs/f2fs/data.c >> @@ -3402,7 +3402,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, >> >> restart: >> /* check inline_data */ >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) { >> err = PTR_ERR(ipage); >> goto unlock_out; >> @@ -3465,7 +3465,7 @@ static int __find_data_block(struct inode *inode, pgoff_t index, >> struct page *ipage; >> int err = 0; >> >> - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); >> + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> @@ -3495,7 +3495,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index, >> >> f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); >> >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) { >> err = PTR_ERR(ipage); >> goto unlock_out; >> diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c >> index 4c74f29a2c73..acd5b2e3e966 100644 >> --- a/fs/f2fs/dir.c >> +++ b/fs/f2fs/dir.c >> @@ -552,7 +552,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir, >> goto put_error; >> } >> } else { >> - page = f2fs_get_node_page(F2FS_I_SB(dir), inode->i_ino); >> + page = f2fs_get_inode_page(F2FS_I_SB(dir), inode->i_ino); >> if (IS_ERR(page)) >> return page; >> } >> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >> index e45c204c36ec..74a80bb06f06 100644 >> --- a/fs/f2fs/f2fs.h >> +++ b/fs/f2fs/f2fs.h >> @@ -3702,7 +3702,8 @@ struct page *f2fs_new_inode_page(struct inode *inode); >> struct page *f2fs_new_node_page(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 folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid); >> +struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino); >> +struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino); >> struct page *f2fs_get_node_page_ra(struct page *parent, int start); >> int f2fs_move_node_page(struct page *node_page, int gc_type); >> void f2fs_flush_inline_data(struct f2fs_sb_info *sbi); >> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >> index cd8d366b2fd7..d21fd2ef8bf8 100644 >> --- a/fs/f2fs/file.c >> +++ b/fs/f2fs/file.c >> @@ -761,7 +761,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock) >> if (lock) >> f2fs_lock_op(sbi); >> >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) { >> err = PTR_ERR(ipage); >> goto out; >> diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c >> index 3e3c35d4c98b..ad92e9008781 100644 >> --- a/fs/f2fs/inline.c >> +++ b/fs/f2fs/inline.c >> @@ -119,7 +119,7 @@ int f2fs_read_inline_data(struct inode *inode, struct folio *folio) >> { >> struct page *ipage; >> >> - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); >> + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); >> if (IS_ERR(ipage)) { >> folio_unlock(folio); >> return PTR_ERR(ipage); >> @@ -237,7 +237,7 @@ int f2fs_convert_inline_inode(struct inode *inode) >> >> f2fs_lock_op(sbi); >> >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) { >> err = PTR_ERR(ipage); >> goto out; >> @@ -265,7 +265,7 @@ int f2fs_write_inline_data(struct inode *inode, struct folio *folio) >> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >> struct page *ipage; >> >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> @@ -312,7 +312,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage) >> if (f2fs_has_inline_data(inode) && >> ri && (ri->i_inline & F2FS_INLINE_DATA)) { >> process_inline: >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> @@ -331,7 +331,7 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage) >> } >> >> if (f2fs_has_inline_data(inode)) { >> - ipage = f2fs_get_node_page(sbi, inode->i_ino); >> + ipage = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> f2fs_truncate_inline_inode(inode, ipage, 0); >> @@ -361,7 +361,7 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, >> struct page *ipage; >> void *inline_dentry; >> >> - ipage = f2fs_get_node_page(sbi, dir->i_ino); >> + ipage = f2fs_get_inode_page(sbi, dir->i_ino); >> if (IS_ERR(ipage)) { >> *res_page = ipage; >> return NULL; >> @@ -609,7 +609,7 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry) >> if (err) >> goto out; >> >> - ipage = f2fs_get_node_page(sbi, dir->i_ino); >> + ipage = f2fs_get_inode_page(sbi, dir->i_ino); >> if (IS_ERR(ipage)) { >> err = PTR_ERR(ipage); >> goto out_fname; >> @@ -644,7 +644,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname, >> struct page *page = NULL; >> int err = 0; >> >> - ipage = f2fs_get_node_page(sbi, dir->i_ino); >> + ipage = f2fs_get_inode_page(sbi, dir->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> @@ -734,7 +734,7 @@ bool f2fs_empty_inline_dir(struct inode *dir) >> void *inline_dentry; >> struct f2fs_dentry_ptr d; >> >> - ipage = f2fs_get_node_page(sbi, dir->i_ino); >> + ipage = f2fs_get_inode_page(sbi, dir->i_ino); >> if (IS_ERR(ipage)) >> return false; >> >> @@ -765,7 +765,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, >> if (ctx->pos == d.max) >> return 0; >> >> - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); >> + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> @@ -797,7 +797,7 @@ int f2fs_inline_data_fiemap(struct inode *inode, >> struct page *ipage; >> int err = 0; >> >> - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); >> + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c >> index 6aec752ac098..aa2f41696a88 100644 >> --- a/fs/f2fs/inode.c >> +++ b/fs/f2fs/inode.c >> @@ -410,7 +410,7 @@ static int do_read_inode(struct inode *inode) >> if (f2fs_check_nid_range(sbi, inode->i_ino)) >> return -EINVAL; >> >> - node_page = f2fs_get_node_page(sbi, inode->i_ino); >> + node_page = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(node_page)) >> return PTR_ERR(node_page); >> >> @@ -757,7 +757,7 @@ void f2fs_update_inode_page(struct inode *inode) >> struct page *node_page; >> int count = 0; >> retry: >> - node_page = f2fs_get_node_page(sbi, inode->i_ino); >> + node_page = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(node_page)) { >> int err = PTR_ERR(node_page); >> >> diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c >> index 36614a1c2590..ee5daa6f7408 100644 >> --- a/fs/f2fs/node.c >> +++ b/fs/f2fs/node.c >> @@ -778,7 +778,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) >> npage[0] = dn->inode_page; >> >> if (!npage[0]) { >> - npage[0] = f2fs_get_node_page(sbi, nids[0]); >> + npage[0] = f2fs_get_inode_page(sbi, nids[0]); >> if (IS_ERR(npage[0])) >> return PTR_ERR(npage[0]); >> } >> @@ -1147,7 +1147,7 @@ int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from) >> return level; >> } >> >> - folio = f2fs_get_node_folio(sbi, inode->i_ino); >> + folio = f2fs_get_inode_folio(sbi, inode->i_ino); >> if (IS_ERR(folio)) { >> trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(folio)); >> return PTR_ERR(folio); >> @@ -1456,8 +1456,27 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) >> f2fs_put_page(apage, err ? 1 : 0); >> } >> >> +static int sanity_check_node_footer(struct f2fs_sb_info *sbi, >> + struct page *page, pgoff_t nid, >> + enum node_type ntype) >> +{ >> + if (unlikely(nid != nid_of_node(page) || >> + (ntype == NODE_TYPE_INODE && !IS_INODE(page)))) { >> + f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " >> + "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", >> + ntype, nid, nid_of_node(page), ino_of_node(page), >> + ofs_of_node(page), cpver_of_node(page), >> + next_blkaddr_of_node(page)); >> + set_sbi_flag(sbi, SBI_NEED_FSCK); >> + f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); >> + return -EFSCORRUPTED; >> + } >> + return 0; >> +} >> + >> static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid, >> - struct page *parent, int start) >> + struct page *parent, int start, >> + enum node_type ntype) >> { >> struct folio *folio; >> int err; >> @@ -1499,16 +1518,9 @@ static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid, >> goto out_err; >> } >> page_hit: >> - if (likely(nid == nid_of_node(&folio->page))) >> + err = sanity_check_node_footer(sbi, &folio->page, nid, ntype); >> + if (!err) >> return folio; >> - >> - f2fs_warn(sbi, "inconsistent node block, nid:%lu, node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", >> - nid, nid_of_node(&folio->page), ino_of_node(&folio->page), >> - ofs_of_node(&folio->page), cpver_of_node(&folio->page), >> - next_blkaddr_of_node(&folio->page)); >> - set_sbi_flag(sbi, SBI_NEED_FSCK); >> - f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); >> - err = -EFSCORRUPTED; >> out_err: >> folio_clear_uptodate(folio); >> out_put_err: >> @@ -1519,14 +1531,22 @@ static struct folio *__get_node_folio(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) >> +struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) >> +{ >> + struct folio *folio = __get_node_folio(sbi, nid, NULL, 0, >> + NODE_TYPE_REGULAR); >> + >> + return &folio->page; >> +} >> + >> +struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino) >> { >> - return __get_node_folio(sbi, nid, NULL, 0); >> + return __get_node_folio(sbi, ino, NULL, 0, NODE_TYPE_REGULAR); > Hi Chao, > here should return __get_node_folio(sbi, ino, NULL, 0, NODE_TYPE_INODE); ? Zhiguo, correct, let me fix this, thank you. Thanks. > thanks! >> } >> >> -struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) >> +struct page *f2fs_get_inode_page(struct f2fs_sb_info *sbi, pgoff_t ino) >> { >> - struct folio *folio = __get_node_folio(sbi, nid, NULL, 0); >> + struct folio *folio = f2fs_get_inode_folio(sbi, ino); >> >> return &folio->page; >> } >> @@ -1535,7 +1555,8 @@ struct page *f2fs_get_node_page_ra(struct page *parent, int start) >> { >> struct f2fs_sb_info *sbi = F2FS_P_SB(parent); >> nid_t nid = get_nid(parent, start, false); >> - struct folio *folio = __get_node_folio(sbi, nid, parent, start); >> + struct folio *folio = __get_node_folio(sbi, nid, parent, start, >> + NODE_TYPE_REGULAR); >> >> return &folio->page; >> } >> @@ -2727,7 +2748,7 @@ int f2fs_recover_inline_xattr(struct inode *inode, struct page *page) >> struct page *ipage; >> struct f2fs_inode *ri; >> >> - ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); >> + ipage = f2fs_get_inode_page(F2FS_I_SB(inode), inode->i_ino); >> if (IS_ERR(ipage)) >> return PTR_ERR(ipage); >> >> diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h >> index 281d53c95c9a..5079c6a2298d 100644 >> --- a/fs/f2fs/node.h >> +++ b/fs/f2fs/node.h >> @@ -52,6 +52,12 @@ enum { >> IS_PREALLOC, /* nat entry is preallocated */ >> }; >> >> +/* For node type in __get_node_folio() */ >> +enum node_type { >> + NODE_TYPE_REGULAR, >> + NODE_TYPE_INODE, >> +}; >> + >> /* >> * For node information >> */ >> diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c >> index 3f3874943679..d5b42e1005d8 100644 >> --- a/fs/f2fs/xattr.c >> +++ b/fs/f2fs/xattr.c >> @@ -282,7 +282,7 @@ static int read_inline_xattr(struct inode *inode, struct page *ipage, >> if (ipage) { >> inline_addr = inline_xattr_addr(inode, ipage); >> } else { >> - page = f2fs_get_node_page(sbi, inode->i_ino); >> + page = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(page)) >> return PTR_ERR(page); >> >> @@ -449,7 +449,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, >> if (ipage) { >> inline_addr = inline_xattr_addr(inode, ipage); >> } else { >> - in_page = f2fs_get_node_page(sbi, inode->i_ino); >> + in_page = f2fs_get_inode_page(sbi, inode->i_ino); >> if (IS_ERR(in_page)) { >> f2fs_alloc_nid_failed(sbi, new_nid); >> return PTR_ERR(in_page); >> -- >> 2.48.1 >> >> >> >> _______________________________________________ >> Linux-f2fs-devel mailing list >> Linux-f2fs-devel@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-03-05 8:27 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-03-03 3:54 [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() Chao Yu 2025-03-03 3:54 ` [PATCH 2/3] f2fs: do sanity check on xattr node footer in f2fs_get_xnode_page() Chao Yu 2025-03-03 3:54 ` [PATCH 3/3] f2fs: introduce FAULT_INCONSISTENT_FOOTER Chao Yu 2025-03-04 17:10 ` [f2fs-dev] [PATCH 1/3] f2fs: do sanity check on inode footer in f2fs_get_inode_page() patchwork-bot+f2fs 2025-03-05 6:39 ` Zhiguo Niu 2025-03-05 8:27 ` Chao Yu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox