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: flush plug periodically during GC to maximize readahead effect

During the garbage collection process, F2FS submits readahead I/Os for
valid blocks. However, since the GC loop runs within a single plug scope
without intermediate flushing, these readahead I/Os often accumulate in
the block layer's plug list instead of being dispatched to the device
immediately.

Consequently, when the GC thread attempts to lock the page later, the
I/O might not have completed (or even started), leading to a "read try
and wait" scenario. This negates the benefit of readahead and causes
unnecessary delays in GC latency.

This patch addresses this issue by introducing an intermediate
blk_finish_plug() and blk_start_plug() pair within the GC loop. This
forces the dispatch of pending I/Os, ensuring that readahead pages are
fetched in time, thereby reducing GC latency.

Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Daeho Jeong and committed by
Jaegeuk Kim
7ec19911 572b1c6f

+13 -6
+13 -6
fs/f2fs/gc.c
··· 1031 1031 * ignore that. 1032 1032 */ 1033 1033 static int gc_node_segment(struct f2fs_sb_info *sbi, 1034 - struct f2fs_summary *sum, unsigned int segno, int gc_type) 1034 + struct f2fs_summary *sum, unsigned int segno, int gc_type, 1035 + struct blk_plug *plug) 1035 1036 { 1036 1037 struct f2fs_summary *entry; 1037 1038 block_t start_addr; ··· 1101 1100 stat_inc_node_blk_count(sbi, 1, gc_type); 1102 1101 } 1103 1102 1104 - if (++phase < 3) 1103 + if (++phase < 3) { 1104 + blk_finish_plug(plug); 1105 + blk_start_plug(plug); 1105 1106 goto next_step; 1107 + } 1106 1108 1107 1109 if (fggc) 1108 1110 atomic_dec(&sbi->wb_sync_req[NODE]); ··· 1543 1539 */ 1544 1540 static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, 1545 1541 struct gc_inode_list *gc_list, unsigned int segno, int gc_type, 1546 - bool force_migrate) 1542 + bool force_migrate, struct blk_plug *plug) 1547 1543 { 1548 1544 struct super_block *sb = sbi->sb; 1549 1545 struct f2fs_summary *entry; ··· 1711 1707 } 1712 1708 } 1713 1709 1714 - if (++phase < 5) 1710 + if (++phase < 5) { 1711 + blk_finish_plug(plug); 1712 + blk_start_plug(plug); 1715 1713 goto next_step; 1714 + } 1716 1715 1717 1716 return submitted; 1718 1717 } ··· 1864 1857 */ 1865 1858 if (type == SUM_TYPE_NODE) 1866 1859 submitted += gc_node_segment(sbi, sum->entries, 1867 - cur_segno, gc_type); 1860 + cur_segno, gc_type, &plug); 1868 1861 else 1869 1862 submitted += gc_data_segment(sbi, sum->entries, 1870 1863 gc_list, cur_segno, 1871 - gc_type, force_migrate); 1864 + gc_type, force_migrate, &plug); 1872 1865 1873 1866 stat_inc_gc_seg_count(sbi, data_type, gc_type); 1874 1867 sbi->gc_reclaimed_segs[sbi->gc_mode]++;