]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
f2fs: optimize representative type determination in GC
authorDaeho Jeong <daehojeong@google.com>
Thu, 14 May 2026 20:55:13 +0000 (13:55 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 22 Jun 2026 19:52:34 +0000 (19:52 +0000)
In large section mode, do_garbage_collect() previously determined the
section's representative type by looking only at the first segment of
the section. However, if data was fsynced into an area previously used
as a node section, and this area is recovered during roll-forward
recovery after sudden power off (SPO), GC would incorrectly assume the
section's type based on an empty or obsolete first segment. This caused
the recovered data segment to be misunderstood as being stuck inside a
node section, triggering false inconsistency panics (Inconsistent
segment type in SSA and SIT) and subsequent mount failures.

This patch optimizes do_garbage_collect() to determine the section's
representative type by identifying the first segment that actually
contains valid blocks (valid_blocks > 0) during the main GC loop. This
eliminates false alarms from empty/obsolete leading segments while
maintaining strict section-level type consistency checks for genuine
corruption.

Signed-off-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/gc.c

index ba93010924c062d979485d095ed7aff8c05918ae..99bc598898251e227cfd8a8db391b2950159699d 100644 (file)
@@ -1754,9 +1754,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
        unsigned int end_segno = start_segno + SEGS_PER_SEC(sbi);
        unsigned int sec_end_segno;
        int seg_freed = 0, migrated = 0;
-       unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
-                                               SUM_TYPE_DATA : SUM_TYPE_NODE;
-       unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE;
+       unsigned char type;
+       unsigned char data_type;
        int submitted = 0, sum_blk_cnt;
 
        if (__is_large_section(sbi)) {
@@ -1855,6 +1854,12 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                                        migrated >= sbi->migration_granularity)
                                continue;
 
+                       if (migrated == 0) {
+                               type = IS_DATASEG(get_seg_entry(sbi, cur_segno)->type) ?
+                                                       SUM_TYPE_DATA : SUM_TYPE_NODE;
+                               data_type = (type == SUM_TYPE_DATA) ? DATA : NODE;
+                       }
+
                        sum = SUM_BLK_PAGE_ADDR(sbi, sum_folio, cur_segno);
                        if (type != GET_SUM_TYPE(sum_footer(sbi, sum))) {
                                f2fs_err(sbi, "Inconsistent segment (%u) type "