On 1/12/2026 5:19 PM, Wu Bo wrote:
ADDRS_PER_INODE and ADDRS_PER_BLOCK are macros of a function, and if the
compiler does not optimize the code (-O0 for example), they would be
called in every single loop, which could cause significant performance
drops in some cases.

This scenario has been found before, refer to:
Commit: 1bb669e ("fsck.f2fs: avoid unnecessary recalculation")

To avoid this performance drop as much as possible, I changed the
function to 'inline' definition, which could mitigate such cases in
the future.

Signed-off-by: Wu Bo <[email protected]>
---
  fsck/dump.c       |  5 +++--
  fsck/fsck.c       | 15 ++++++++++-----
  fsck/mount.c      |  4 +++-
  include/f2fs_fs.h | 12 +++++++++++-
  lib/libf2fs.c     | 11 -----------
  5 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/fsck/dump.c b/fsck/dump.c
index f5c95de..a5f344b 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -495,7 +495,7 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
  {
        u32 i = 0;
        u64 ofs = 0;
-       u32 addr_per_block;
+       u32 addr_per_block, addr_per_inode;
        u16 type = le16_to_cpu(node_blk->i.i_mode);
        int ret = 0;
@@ -543,9 +543,10 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
        }
addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
+       addr_per_inode = ADDRS_PER_INODE(&node_blk->i);
/* check data blocks in inode */
-       for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
+       for (i = 0; i < addr_per_inode; i++, ofs++)
                dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
                        node_blk->i.i_addr[get_extra_isize(node_blk) + i]), 
type);
diff --git a/fsck/fsck.c b/fsck/fsck.c
index db44f9d..1627bd0 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1516,8 +1516,9 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct 
f2fs_inode *inode,
        bool compressed = i_flags & F2FS_COMPR_FL;
        bool compr_rel = inode->i_inline & F2FS_COMPRESS_RELEASED;
        u32 cluster_size = 1 << inode->i_log_cluster_size;
+       u32 addrs = ADDRS_PER_BLOCK(inode);
- for (idx = 0; idx < ADDRS_PER_BLOCK(inode); idx++, child->pgofs++) {
+       for (idx = 0; idx < addrs; idx++, child->pgofs++) {
                block_t blkaddr = le32_to_cpu(node_blk->dn.addr[idx]);
check_extent_info(child, blkaddr, 0);
@@ -1617,6 +1618,7 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct 
f2fs_inode *inode,
  {
        int i = 0;
        int need_fix = 0, ret = 0;
+       u32 addrs = ADDRS_PER_BLOCK(inode);
fsck_reada_all_direct_node_blocks(sbi, node_blk); @@ -1637,7 +1639,7 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
                                FIX_MSG("Set double indirect node 0x%x -> 0", 
i);
                        }
  skip:
-                       child->pgofs += ADDRS_PER_BLOCK(inode) * NIDS_PER_BLOCK;
+                       child->pgofs += addrs * NIDS_PER_BLOCK;

I'm worried about that ADDRS_PER_BLOCK(inode) will change after we fixed
some fields of inode block in fsck_chk_node_blk().

Thanks,

                }
        }
@@ -3173,7 +3175,7 @@ static void fsck_disconnect_file_dnode(struct f2fs_sb_info *sbi,
  {
        struct f2fs_node *node;
        struct node_info ni;
-       u32 addr;
+       u32 addr, addr_per_block;
        int i, err;
node = calloc(F2FS_BLKSIZE, 1);
@@ -3187,7 +3189,8 @@ static void fsck_disconnect_file_dnode(struct 
f2fs_sb_info *sbi,
        release_block_cnt(sbi, dealloc);
        release_block(sbi, ni.blk_addr, dealloc);
- for (i = 0; i < ADDRS_PER_BLOCK(inode); i++) {
+       addr_per_block = ADDRS_PER_BLOCK(inode);
+       for (i = 0; i < addr_per_block; i++) {
                addr = le32_to_cpu(node->dn.addr[i]);
                if (!addr)
                        continue;
@@ -3302,8 +3305,10 @@ static void fsck_disconnect_file(struct f2fs_sb_info 
*sbi, nid_t ino,
/* clear data counters */
        if (!(node->i.i_inline & (F2FS_INLINE_DATA | F2FS_INLINE_DENTRY))) {
+               u32 addrs = ADDRS_PER_INODE(&node->i);
+
                ofs = get_extra_isize(node);
-               for (i = 0; i < ADDRS_PER_INODE(&node->i); i++) {
+               for (i = 0; i < addrs; i++) {
                        block_t addr = le32_to_cpu(node->i.i_addr[ofs + i]);
                        if (!addr)
                                continue;
diff --git a/fsck/mount.c b/fsck/mount.c
index 6f640a0..990f1e0 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -281,6 +281,7 @@ void print_inode_info(struct f2fs_sb_info *sbi,
        u32 namelen = le32_to_cpu(inode->i_namelen);
        int enc_name = file_enc_name(inode);
        int ofs = get_extra_isize(node);
+       u32 addrs;
pretty_print_filename(inode->i_name, namelen, en, enc_name);
        if (name && en[0]) {
@@ -350,7 +351,8 @@ void print_inode_info(struct f2fs_sb_info *sbi,
                }
        }
- for (i = 0; i < ADDRS_PER_INODE(inode); i++) {
+       addrs = ADDRS_PER_INODE(inode);
+       for (i = 0; i < addrs; i++) {
                block_t blkaddr;
                char *flag = "";
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 3095b59..d0877b9 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -1660,7 +1660,6 @@ struct f2fs_configuration {
  extern int utf8_to_utf16(char *, const char *, size_t, size_t);
  extern int utf16_to_utf8(char *, const char *, size_t, size_t);
  extern int log_base_2(uint32_t);
-extern unsigned int addrs_per_page(struct f2fs_inode *, bool);
  extern u64 f2fs_max_file_offset(struct f2fs_inode *);
  extern __u32 f2fs_inode_chksum(struct f2fs_node *);
  extern __u32 f2fs_checkpoint_chksum(struct f2fs_checkpoint *);
@@ -2212,4 +2211,15 @@ static inline bool __time_to_inject(int type, const char 
*func,
        return false;
  }
+static inline unsigned int addrs_per_page(struct f2fs_inode *i, bool is_inode)
+{
+       unsigned int addrs = is_inode ? CUR_ADDRS_PER_INODE(i) -
+               get_inline_xattr_addrs(i) : DEF_ADDRS_PER_BLOCK;
+
+       if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) ||
+                       !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL))
+               return addrs;
+       return ALIGN_DOWN(addrs, 1 << i->i_log_cluster_size);
+}
+
  #endif        /*__F2FS_FS_H */
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 1a496b7..13e4d0d 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -516,17 +516,6 @@ opaque_seq:
        return __f2fs_dentry_hash(name, len);
  }
-unsigned int addrs_per_page(struct f2fs_inode *i, bool is_inode)
-{
-       unsigned int addrs = is_inode ? CUR_ADDRS_PER_INODE(i) -
-               get_inline_xattr_addrs(i) : DEF_ADDRS_PER_BLOCK;
-
-       if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) ||
-                       !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL))
-               return addrs;
-       return ALIGN_DOWN(addrs, 1 << i->i_log_cluster_size);
-}
-
  u64 f2fs_max_file_offset(struct f2fs_inode *i)
  {
        if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) ||



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

Reply via email to