[f2fs-dev] [RFC PATCH v3 1/2] fsck.f2fs: adapt to inline extent inode layout

Yongpeng Yang <[email protected]> Fri, 24 Jul 2026 20:59:58 +0800
Newsgroups net.sourceforge.lists.linux-f2fs-devel
Message-ID <[email protected]>
From: Yongpeng Yang <[email protected]>

The kernel inline extent feature has been designed to place the inline
extent area after struct f2fs_inode->i_extra_end, inside the
i_extra_isize region. f2fs-tools only needs to track the inode layout
change and keep the inline extent consistent with the largest cached
extent.

Adapt to the new on-disk inode layout:

- Split struct f2fs_inode->i_compr_blocks (was __le64) into
  __le32 i_compr_blocks + __le32 i_inline_ext_capacity, matching the
  kernel change. i_inline_ext_capacity records the number of inline
  extent entries reserved in the inode.
- Add struct f2fs_iext_header, the header of the inline extent area
  located right after i_extra_end[].
- Update all i_compr_blocks accesses (fsck.c, inject.c, mount.c,
  segment.c) to use le32 helpers.

Keep the inline extent consistent with the largest extent:

- Add f2fs_invalidate_inline_extent(), which resets the inline extent
  entry count to 0.
- The inline extent shares its lifetime with the largest extent cache:
  whenever i_ext is dropped or truncated (in fsck_chk_inode_blk() and
  update_data_blkaddr()), invalidate the inline extent as well so a
  stale mapping is never left behind.

Signed-off-by: Yongpeng Yang <[email protected]>
---
 fsck/fsck.c       |  9 ++++++---
 fsck/inject.c     |  6 +++---
 fsck/mount.c      |  3 ++-
 fsck/segment.c    |  2 +-
 include/f2fs_fs.h | 22 +++++++++++++++++++++-
 5 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/fsck/fsck.c b/fsck/fsck.c
index 497cca0..9b8f34c 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -919,7 +919,7 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
 	u32 i_flags = le32_to_cpu(node_blk->i.i_flags);
 	bool compressed = i_flags & F2FS_COMPR_FL;
 	bool compr_rel = node_blk->i.i_inline & F2FS_COMPRESS_RELEASED;
-	u64 i_compr_blocks = le64_to_cpu(node_blk->i.i_compr_blocks);
+	u64 i_compr_blocks = le32_to_cpu(node_blk->i.i_compr_blocks);
 	nid_t i_xattr_nid = le32_to_cpu(node_blk->i.i_xattr_nid);
 	int ofs;
 	char *en;
@@ -1204,6 +1204,7 @@ check_next:
 					qf_last_blkofs[cur_qtype] = child.pgofs;
 			} else if (c.fix_on) {
 				node_blk->i.i_ext.len = cpu_to_le32(idx);
+				f2fs_invalidate_inline_extent(&node_blk->i);
 				need_fix = 1;
 				break;
 			}
@@ -1332,7 +1333,7 @@ check:
 
 	if (compressed && i_compr_blocks != cbc->cnt) {
 		if (c.fix_on) {
-			node_blk->i.i_compr_blocks = cpu_to_le64(cbc->cnt);
+			node_blk->i.i_compr_blocks = cpu_to_le32(cbc->cnt);
 			need_fix = 1;
 			FIX_MSG("[0x%x] i_compr_blocks=0x%08"PRIx64" -> 0x%x",
 					nid, i_compr_blocks, cbc->cnt);
@@ -1476,8 +1477,10 @@ skip_dot_fix:
 	}
 
 	/* drop extent information to avoid potential wrong access */
-	if (need_fix && f2fs_dev_is_writable() && !is_aliasing)
+	if (need_fix && f2fs_dev_is_writable() && !is_aliasing) {
 		node_blk->i.i_ext.len = 0;
+		f2fs_invalidate_inline_extent(&node_blk->i);
+	}
 
 	if ((c.feature & F2FS_FEATURE_INODE_CHKSUM) &&
 				f2fs_has_extra_isize(&node_blk->i)) {
diff --git a/fsck/inject.c b/fsck/inject.c
index 60a2d20..fa09f1e 100644
--- a/fsck/inject.c
+++ b/fsck/inject.c
@@ -1088,9 +1088,9 @@ static int inject_inode(struct f2fs_sb_info *sbi, struct f2fs_node *node,
 		inode->i_inode_checksum = cpu_to_le32((u32)opt->val);
 	} else if (!strcmp(opt->mb, "i_compr_blocks")) {
 		MSG(0, "Info: inject inode i_compr_blocks of nid %u: "
-		    "%"PRIu64" -> %"PRIu64"\n", opt->nid,
-		    le64_to_cpu(inode->i_compr_blocks), (u64)opt->val);
-		inode->i_compr_blocks = cpu_to_le64((u64)opt->val);
+		    "%u -> %u\n", opt->nid,
+		    le32_to_cpu(inode->i_compr_blocks), (u32)opt->val);
+		inode->i_compr_blocks = cpu_to_le32((u32)opt->val);
 	} else if (!strcmp(opt->mb, "i_addr")) {
 		/* do not care if it is inline data */
 		if (opt->idx >= DEF_ADDRS_PER_INODE) {
diff --git a/fsck/mount.c b/fsck/mount.c
index f7985dc..8c14c97 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -344,7 +344,7 @@ void print_inode_info(struct f2fs_sb_info *sbi,
 			DISP_u32(inode, i_crtime_nsec);
 		}
 		if (c.feature & F2FS_FEATURE_COMPRESSION) {
-			DISP_u64(inode, i_compr_blocks);
+			DISP_u32(inode, i_compr_blocks);
 			DISP_u8(inode, i_compress_algorithm);
 			DISP_u8(inode, i_log_cluster_size);
 			DISP_u16(inode, i_compress_flag);
@@ -2574,6 +2574,7 @@ void update_data_blkaddr(struct f2fs_sb_info *sbi, nid_t nid,
 	endaddr = startaddr + le32_to_cpu(node_blk->i.i_ext.len);
 	if (oldaddr >= startaddr && oldaddr < endaddr) {
 		node_blk->i.i_ext.len = 0;
+		f2fs_invalidate_inline_extent(&node_blk->i);
 
 		/* update inode block */
 		if (node_blk_alloced)
diff --git a/fsck/segment.c b/fsck/segment.c
index 96de22a..2222b6e 100644
--- a/fsck/segment.c
+++ b/fsck/segment.c
@@ -725,7 +725,7 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
 		/* update inode meta */
 		node_blk->i.i_size = cpu_to_le64(off);
 		if (!c.compress.readonly) {
-			node_blk->i.i_compr_blocks = cpu_to_le64(cblocks);
+			node_blk->i.i_compr_blocks = cpu_to_le32(cblocks);
 			node_blk->i.i_blocks += cpu_to_le64(cblocks);
 		}
 		ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 1b24a3c..a06defb 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -929,6 +929,15 @@ struct f2fs_extent {
 
 static_assert(sizeof(struct f2fs_extent) == 12, "");
 
+/*
+ * f2fs_iext_header: header for inline extent area in i_extra_attr region.
+ * Placed right after i_extra_end[0], before the extent array.
+ */
+struct f2fs_iext_header {
+	__le32 cnt;		/* current # of valid extents */
+	struct f2fs_extent exts[];
+} __attribute__((packed));
+
 #define F2FS_NAME_LEN		255
 
 /* max output length of pretty_print_filename() including null terminator */
@@ -1079,7 +1088,8 @@ struct f2fs_inode {
 			__le32 i_inode_checksum;/* inode meta checksum */
 			__le64 i_crtime;	/* creation time */
 			__le32 i_crtime_nsec;	/* creation time in nano scale */
-			__le64 i_compr_blocks;	/* # of compressed blocks */
+			__le32 i_compr_blocks;	/* # of compressed blocks */
+			__le32 i_inline_ext_capacity;	/* # of inline extent entries */
 			__u8 i_compress_algorithm;	/* compress algorithm */
 			__u8 i_log_cluster_size;	/* log of cluster size */
 			__le16 i_compress_flag;		/* compress flag */
@@ -1730,6 +1740,16 @@ static inline bool f2fs_has_extra_isize(struct f2fs_inode *inode)
 	return (inode->i_inline & F2FS_EXTRA_ATTR);
 }
 
+static inline void f2fs_invalidate_inline_extent(struct f2fs_inode *inode)
+{
+	if (f2fs_has_extra_isize(inode) &&
+	    le32_to_cpu(inode->i_inline_ext_capacity) > 0) {
+		struct f2fs_iext_header *eh =
+			(struct f2fs_iext_header *)inode->i_extra_end;
+		eh->cnt = 0;
+	}
+}
+
 static inline int __get_extra_isize(struct f2fs_inode *inode)
 {
 	if (f2fs_has_extra_isize(inode))
-- 
2.43.0



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel