Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

f2fs: fix fsck inconsistency caused by FGGC of node block

During FGGC node block migration, fsck may incorrectly treat the
migrated node block as fsync-written data.

The reproduction scenario:
root@vm:/mnt/f2fs# seq 1 2048 | xargs -n 1 ./test_sync // write inline inode and sync
root@vm:/mnt/f2fs# rm -f 1
root@vm:/mnt/f2fs# sync
root@vm:/mnt/f2fs# f2fs_io gc_range // move data block in sync mode and not write CP
SPO, "fsck --dry-run" find inode has already checkpointed but still
with DENT_BIT_SHIFT set

The root cause is that GC does not clear the dentry mark and fsync mark
during node block migration, leading fsck to misinterpret them as
user-issued fsync writes.

In BGGC mode, node block migration is handled by f2fs_sync_node_pages(),
which guarantees the dentry and fsync marks are cleared before writing.

This patch move the set/clear of the fsync|dentry marks into
__write_node_folio to make the logic clearer, and ensures the
fsync|dentry mark is cleared in FGGC.

Cc: stable@kernel.org
Fixes: da011cc0da8c ("f2fs: move node pages only in victim section during GC")
Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Yongpeng Yang and committed by
Jaegeuk Kim
c3e238bd 019f9dda

+13 -14
+13 -14
fs/f2fs/node.c
··· 1727 1727 return last_folio; 1728 1728 } 1729 1729 1730 - static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted, 1731 - struct writeback_control *wbc, bool do_balance, 1732 - enum iostat_type io_type, unsigned int *seq_id) 1730 + static bool __write_node_folio(struct folio *folio, bool atomic, bool do_fsync, 1731 + bool *submitted, struct writeback_control *wbc, 1732 + bool do_balance, enum iostat_type io_type, 1733 + unsigned int *seq_id) 1733 1734 { 1734 1735 struct f2fs_sb_info *sbi = F2FS_F_SB(folio); 1735 1736 nid_t nid; ··· 1803 1802 if (atomic && !test_opt(sbi, NOBARRIER)) 1804 1803 fio.op_flags |= REQ_PREFLUSH | REQ_FUA; 1805 1804 1805 + set_dentry_mark(folio, false); 1806 + set_fsync_mark(folio, do_fsync); 1806 1807 if (IS_INODE(folio) && (atomic || is_fsync_dnode(folio))) 1807 1808 set_dentry_mark(folio, 1808 1809 f2fs_need_dentry_mark(sbi, ino_of_node(folio))); ··· 1871 1868 goto out_folio; 1872 1869 } 1873 1870 1874 - if (!__write_node_folio(node_folio, false, NULL, 1871 + if (!__write_node_folio(node_folio, false, false, NULL, 1875 1872 &wbc, false, FS_GC_NODE_IO, NULL)) 1876 1873 err = -EAGAIN; 1877 1874 goto release_folio; ··· 1918 1915 for (i = 0; i < nr_folios; i++) { 1919 1916 struct folio *folio = fbatch.folios[i]; 1920 1917 bool submitted = false; 1918 + bool do_fsync = false; 1921 1919 1922 1920 if (unlikely(f2fs_cp_error(sbi))) { 1923 1921 f2fs_folio_put(last_folio, false); ··· 1949 1945 1950 1946 f2fs_folio_wait_writeback(folio, NODE, true, true); 1951 1947 1952 - set_fsync_mark(folio, 0); 1953 - set_dentry_mark(folio, 0); 1954 - 1955 1948 if (!atomic || folio == last_folio) { 1956 - set_fsync_mark(folio, 1); 1949 + do_fsync = true; 1957 1950 percpu_counter_inc(&sbi->rf_node_block_count); 1958 1951 if (IS_INODE(folio)) { 1959 1952 if (is_inode_flag_set(inode, ··· 1967 1966 1968 1967 if (!__write_node_folio(folio, atomic && 1969 1968 folio == last_folio, 1970 - &submitted, wbc, true, 1971 - FS_NODE_IO, seq_id)) { 1969 + do_fsync, &submitted, 1970 + wbc, true, FS_NODE_IO, 1971 + seq_id)) { 1972 1972 f2fs_folio_put(last_folio, false); 1973 1973 folio_batch_release(&fbatch); 1974 1974 ret = -EIO; ··· 2169 2167 if (!folio_clear_dirty_for_io(folio)) 2170 2168 goto continue_unlock; 2171 2169 2172 - set_fsync_mark(folio, 0); 2173 - set_dentry_mark(folio, 0); 2174 - 2175 - if (!__write_node_folio(folio, false, &submitted, 2170 + if (!__write_node_folio(folio, false, false, &submitted, 2176 2171 wbc, do_balance, io_type, NULL)) { 2177 2172 folio_batch_release(&fbatch); 2178 2173 ret = -EIO;