From: Yongpeng Yang <[email protected]>

During fsync, the flow reaches f2fs_fsync_node_pages(), which scans all
dirty node folios of the node mapping. If there are no dirty node
folios, fsync will not write any node folio. The scenario is as follows:

create & write & fsync 'file A'                 writeback node folio
- f2fs_do_sync_file // inline inode
 - f2fs_write_inode // inode folio is dirty

                                                - f2fs_write_node_pages
                                                 - f2fs_sync_node_pages
 - f2fs_fsync_node_pages // no dirty node folios
 sudden poweroff and lost 'file A'

The root cause of the data loss is that although the inode folio is
written successfully, the corresponding node folio is not written with
the FSYNC_BIT_SHIFT mark. As a result, the recovery procedure ignores
this file.

This patch ensures that fsync writes at least one node folio with the
FSYNC_BIT_SHIFT mark for the inode, so that the recovery procedure can
properly detect and process it.

Signed-off-by: Yongpeng Yang <[email protected]>
---
v2:
- Use f2fs_folio_put instead of folio_put to dec folio ref count.
---
 fs/f2fs/node.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 2fbfecaf3f7b..e14e5db1e8e6 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1982,6 +1982,22 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, 
struct inode *inode,
                folio_batch_release(&fbatch);
                cond_resched();
        }
+       /*
+        * All dirty node folios may be written by other thread, but CP hasn't
+        * been written yet. So, we need to flush one of inode's dnode to
+        * recovery this inode when encounter sudden power off.
+        */
+       if (!atomic && nwritten == 0) {
+               struct folio *ifolio;
+
+               ifolio = f2fs_get_inode_folio(sbi, inode->i_ino);
+               if (IS_ERR(ifolio))
+                       return PTR_ERR(ifolio);
+               f2fs_folio_wait_writeback(ifolio, NODE, true, true);
+               folio_mark_dirty(ifolio);
+               f2fs_folio_put(ifolio, true);
+               goto retry;
+       }
        if (atomic && !marked) {
                f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
                           ino, last_folio->index);
-- 
2.43.0



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

Reply via email to