From: Yongpeng Yang <[email protected]>

When f2fs_fiemap() is called with `fileinfo->fi_flags` containing the
FIEMAP_FLAG_SYNC flag, it attempts to write data to disk before
retrieving file mappings via filemap_write_and_wait(). However, there is
an issue where the file does not get mapped as expected. The following
scenario can occur:

root@vm:/mnt/f2fs# dd if=/dev/zero of=data.3k bs=3k count=1
root@vm:/mnt/f2fs# xfs_io data.3k -c "fiemap -v 0 4096"
data.3k:
 EXT: FILE-OFFSET      BLOCK-RANGE      TOTAL FLAGS
   0: [0..5]:          0..5                 6 0x307

The root cause of this issue is that f2fs_write_single_data_page() only
calls f2fs_write_inline_data() to copy data from the data folio to the
inode folio, and it clears the dirty flag on the data folio. However, it
does not mark the data folio as writeback. When
__filemap_fdatawait_range() checks for folios with the writeback flag,
it returns early, causing f2fs_fiemap() to report that the file has no
mapping.

To fix this issue, the solution is to call f2fs_sync_node_pages() after
f2fs_write_inline_data() successfully returns, which will write back the
inode folio and wait for the writeback to complete.

Fixes: 9ffe0fb5f3bb ("f2fs: handle inline data operations")
Signed-off-by: Yongpeng Yang <[email protected]>
---
 fs/f2fs/checkpoint.c |  1 +
 fs/f2fs/data.c       | 19 ++++++++++++++++++-
 fs/f2fs/node.c       | 21 ++++++++++++++++-----
 3 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 5172396c0b01..d0bca57854da 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1347,6 +1347,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,
                .nr_to_write = LONG_MAX,
+               .range_cyclic = 1,
        };
        int err = 0, cnt = 0;
 
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index eedadccf86bb..ccc5e4ddf547 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -3126,8 +3126,25 @@ int f2fs_write_single_data_page(struct folio *folio, int 
*submitted,
        err = -EAGAIN;
        if (f2fs_has_inline_data(inode)) {
                err = f2fs_write_inline_data(inode, folio);
-               if (!err)
+               if (!err) {
+                       struct folio *ifolio;
+                       struct writeback_control iwbc = {
+                               .sync_mode = WB_SYNC_ALL,
+                               .range_start = inode->i_ino << PAGE_SHIFT,
+                               .range_end = inode->i_ino << PAGE_SHIFT,
+                               .nr_to_write = 1,
+                               .range_cyclic = 0,
+                       };
+
+                       if (!f2fs_sync_node_pages(sbi, &iwbc, true, 
FS_NODE_IO)) {
+                               ifolio = f2fs_get_inode_folio(sbi, 
inode->i_ino);
+                               if (!IS_ERR(ifolio)) {
+                                       f2fs_folio_wait_writeback(ifolio, NODE, 
true, true);
+                                       f2fs_folio_put(ifolio, true);
+                               }
+                       }
                        goto out;
+               }
        }
 
        if (err == -EAGAIN) {
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 74992fd9c9b6..47bff89bafe6 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -2083,7 +2083,8 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
                                struct writeback_control *wbc,
                                bool do_balance, enum iostat_type io_type)
 {
-       pgoff_t index;
+       pgoff_t index, wbc_index;
+       pgoff_t end, wbc_end;
        struct folio_batch fbatch;
        int step = 0;
        int nwritten = 0;
@@ -2092,14 +2093,24 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
 
        folio_batch_init(&fbatch);
 
+       wbc_index = 0;
+       wbc_end = LONG_MAX;
+       if (!wbc->range_cyclic) {
+               wbc_index = wbc->range_start >> PAGE_SHIFT;
+               wbc_end = wbc->range_end >> PAGE_SHIFT;
+       }
 next_step:
-       index = 0;
+       index = wbc_index;
+       end = wbc_end;
 
-       while (!done && (nr_folios = filemap_get_folios_tag(NODE_MAPPING(sbi),
-                               &index, (pgoff_t)-1, PAGECACHE_TAG_DIRTY,
-                               &fbatch))) {
+       while (!done && (index <= end)) {
                int i;
 
+               nr_folios = filemap_get_folios_tag(NODE_MAPPING(sbi),
+                               &index, end, PAGECACHE_TAG_DIRTY,
+                               &fbatch);
+               if (nr_folios == 0)
+                       break;
                for (i = 0; i < nr_folios; i++) {
                        struct folio *folio = fbatch.folios[i];
                        bool submitted = false;
-- 
2.43.0



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

Reply via email to