]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
f2fs: fix incorrect file address mapping when inline inode is unwritten
authorYongpeng Yang <yangyongpeng@xiaomi.com>
Tue, 3 Feb 2026 13:36:35 +0000 (21:36 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 24 Mar 2026 17:20:59 +0000 (17:20 +0000)
When `fileinfo->fi_flags` does not have the `FIEMAP_FLAG_SYNC` bit set
and inline data has not been persisted yet, the physical address of the
extent is calculated incorrectly for unwritten inline inodes.

root@vm:/mnt/f2fs# dd if=/dev/zero of=data.3k bs=3k count=1
root@vm:/mnt/f2fs# f2fs_io fiemap 0 100 data.3k
Fiemap: offset = 0 len = 100
logical addr.    physical addr.   length           flags
0 0000000000000000 00000ffffffff16c 0000000000000c00 00000301

This patch fixes the issue by checking if the inode's address is valid.
If the inline inode is unwritten, set the physical address to 0 and
mark the extent with `FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC`
flags.

Cc: stable@kernel.org
Fixes: 67f8cf3cee6f ("f2fs: support fiemap for inline_data")
Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/inline.c

index 0a1052d5ee624e68ba27200b100a567a5d216f2a..86d2abbb40ff740678ba80bb9e9baa036f2d1cf7 100644 (file)
@@ -792,7 +792,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
 int f2fs_inline_data_fiemap(struct inode *inode,
                struct fiemap_extent_info *fieinfo, __u64 start, __u64 len)
 {
-       __u64 byteaddr, ilen;
+       __u64 byteaddr = 0, ilen;
        __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED |
                FIEMAP_EXTENT_LAST;
        struct node_info ni;
@@ -825,9 +825,14 @@ int f2fs_inline_data_fiemap(struct inode *inode,
        if (err)
                goto out;
 
-       byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
-       byteaddr += (char *)inline_data_addr(inode, ifolio) -
-                                       (char *)F2FS_INODE(ifolio);
+       if (__is_valid_data_blkaddr(ni.blk_addr)) {
+               byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
+               byteaddr += (char *)inline_data_addr(inode, ifolio) -
+                                               (char *)F2FS_INODE(ifolio);
+       } else {
+               f2fs_bug_on(F2FS_I_SB(inode), ni.blk_addr != NEW_ADDR);
+               flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
+       }
        err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags);
        trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err);
 out: