Incorporate a check using has_enough_dirty_blocks() to prevent redundant
background GC in Zoned UFS. When there are insufficient dirty segments,
continuous execution of background GC should be avoided, as it results in
unnecessary write operations and impacts device lifespan. The initial
threshold is set to 3 * section size (since f2fs data uses three write
pointers).
Signed-off-by: Liao Yuanhong <liaoyuanhong@vivo.com>
---
fs/f2fs/gc.c | 8 ++++++--
fs/f2fs/gc.h | 10 +++++++++-
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index ed3acbfc83ca..4a8c08f970e3 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -120,7 +120,9 @@ static int gc_thread_func(void *data)
if (f2fs_sb_has_blkzoned(sbi)) {
if (has_enough_free_blocks(sbi,
- gc_th->no_zoned_gc_percent)) {
+ gc_th->no_zoned_gc_percent) ||
+ !has_enough_dirty_blocks(sbi,
+ LIMIT_GC_DIRTY_SECTION_NUM)) {
wait_ms = gc_th->no_gc_sleep_time;
f2fs_up_write(&sbi->gc_lock);
goto next;
@@ -1750,7 +1752,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
if (f2fs_sb_has_blkzoned(sbi) &&
!has_enough_free_blocks(sbi,
- sbi->gc_thread->boost_zoned_gc_percent))
+ sbi->gc_thread->boost_zoned_gc_percent) &&
+ has_enough_dirty_blocks(sbi,
+ LIMIT_GC_DIRTY_SECTION_NUM))
window_granularity *=
sbi->gc_thread->boost_gc_multiple;
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
index 24e8b1c27acc..1ef234c2702b 100644
--- a/fs/f2fs/gc.h
+++ b/fs/f2fs/gc.h
@@ -36,6 +36,7 @@
#define DEF_MIGRATION_WINDOW_GRANULARITY_ZONED 3
#define BOOST_GC_MULTIPLE 5
#define ZONED_PIN_SEC_REQUIRED_COUNT 1
+#define LIMIT_GC_DIRTY_SECTION_NUM 3
#define DEF_GC_FAILED_PINNED_FILES 2048
#define MAX_GC_FAILED_PINNED_FILES USHRT_MAX
@@ -177,6 +178,12 @@ static inline bool has_enough_free_blocks(struct f2fs_sb_info *sbi,
return free_sections(sbi) > ((sbi->total_sections * limit_perc) / 100);
}
+static inline bool has_enough_dirty_blocks(struct f2fs_sb_info *sbi,
+ unsigned int limit_num)
+{
+ return dirty_segments(sbi) > limit_num * SEGS_PER_SEC(sbi);
+}
+
static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
{
block_t user_block_count = sbi->user_block_count;
@@ -197,6 +204,7 @@ static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi)
{
if (f2fs_sb_has_blkzoned(sbi))
return !has_enough_free_blocks(sbi,
- sbi->gc_thread->boost_zoned_gc_percent);
+ sbi->gc_thread->boost_zoned_gc_percent) &&
+ has_enough_dirty_blocks(sbi, LIMIT_GC_DIRTY_SECTION_NUM);
return has_enough_invalid_blocks(sbi);
}
--
2.34.1
Could you please share some trends of relation between has_enough_free_blocks() vs. has_enough_dirty_blocks()? I'm wondering whethere there's a missing case where has_enough_free_blocks() is not enough. On 09/09, Liao Yuanhong wrote: > Incorporate a check using has_enough_dirty_blocks() to prevent redundant > background GC in Zoned UFS. When there are insufficient dirty segments, > continuous execution of background GC should be avoided, as it results in > unnecessary write operations and impacts device lifespan. The initial > threshold is set to 3 * section size (since f2fs data uses three write > pointers). > > Signed-off-by: Liao Yuanhong <liaoyuanhong@vivo.com> > --- > fs/f2fs/gc.c | 8 ++++++-- > fs/f2fs/gc.h | 10 +++++++++- > 2 files changed, 15 insertions(+), 3 deletions(-) > > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > index ed3acbfc83ca..4a8c08f970e3 100644 > --- a/fs/f2fs/gc.c > +++ b/fs/f2fs/gc.c > @@ -120,7 +120,9 @@ static int gc_thread_func(void *data) > > if (f2fs_sb_has_blkzoned(sbi)) { > if (has_enough_free_blocks(sbi, > - gc_th->no_zoned_gc_percent)) { > + gc_th->no_zoned_gc_percent) || > + !has_enough_dirty_blocks(sbi, > + LIMIT_GC_DIRTY_SECTION_NUM)) { > wait_ms = gc_th->no_gc_sleep_time; > f2fs_up_write(&sbi->gc_lock); > goto next; > @@ -1750,7 +1752,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, > > if (f2fs_sb_has_blkzoned(sbi) && > !has_enough_free_blocks(sbi, > - sbi->gc_thread->boost_zoned_gc_percent)) > + sbi->gc_thread->boost_zoned_gc_percent) && > + has_enough_dirty_blocks(sbi, > + LIMIT_GC_DIRTY_SECTION_NUM)) > window_granularity *= > sbi->gc_thread->boost_gc_multiple; > > diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h > index 24e8b1c27acc..1ef234c2702b 100644 > --- a/fs/f2fs/gc.h > +++ b/fs/f2fs/gc.h > @@ -36,6 +36,7 @@ > #define DEF_MIGRATION_WINDOW_GRANULARITY_ZONED 3 > #define BOOST_GC_MULTIPLE 5 > #define ZONED_PIN_SEC_REQUIRED_COUNT 1 > +#define LIMIT_GC_DIRTY_SECTION_NUM 3 > > #define DEF_GC_FAILED_PINNED_FILES 2048 > #define MAX_GC_FAILED_PINNED_FILES USHRT_MAX > @@ -177,6 +178,12 @@ static inline bool has_enough_free_blocks(struct f2fs_sb_info *sbi, > return free_sections(sbi) > ((sbi->total_sections * limit_perc) / 100); > } > > +static inline bool has_enough_dirty_blocks(struct f2fs_sb_info *sbi, > + unsigned int limit_num) > +{ > + return dirty_segments(sbi) > limit_num * SEGS_PER_SEC(sbi); > +} > + > static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) > { > block_t user_block_count = sbi->user_block_count; > @@ -197,6 +204,7 @@ static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi) > { > if (f2fs_sb_has_blkzoned(sbi)) > return !has_enough_free_blocks(sbi, > - sbi->gc_thread->boost_zoned_gc_percent); > + sbi->gc_thread->boost_zoned_gc_percent) && > + has_enough_dirty_blocks(sbi, LIMIT_GC_DIRTY_SECTION_NUM); > return has_enough_invalid_blocks(sbi); > } > -- > 2.34.1
On 9/16/2025 10:28 AM, Jaegeuk Kim wrote: > Could you please share some trends of relation between has_enough_free_blocks() > vs. has_enough_dirty_blocks()? I'm wondering whethere there's a missing case > where has_enough_free_blocks() is not enough. Sure. I will find some time to test the data and create a table to see if there are any omissions. Thanks, Liao > On 09/09, Liao Yuanhong wrote: >> Incorporate a check using has_enough_dirty_blocks() to prevent redundant >> background GC in Zoned UFS. When there are insufficient dirty segments, >> continuous execution of background GC should be avoided, as it results in >> unnecessary write operations and impacts device lifespan. The initial >> threshold is set to 3 * section size (since f2fs data uses three write >> pointers). >> >> Signed-off-by: Liao Yuanhong <liaoyuanhong@vivo.com> >> --- >> fs/f2fs/gc.c | 8 ++++++-- >> fs/f2fs/gc.h | 10 +++++++++- >> 2 files changed, 15 insertions(+), 3 deletions(-) >> >> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c >> index ed3acbfc83ca..4a8c08f970e3 100644 >> --- a/fs/f2fs/gc.c >> +++ b/fs/f2fs/gc.c >> @@ -120,7 +120,9 @@ static int gc_thread_func(void *data) >> >> if (f2fs_sb_has_blkzoned(sbi)) { >> if (has_enough_free_blocks(sbi, >> - gc_th->no_zoned_gc_percent)) { >> + gc_th->no_zoned_gc_percent) || >> + !has_enough_dirty_blocks(sbi, >> + LIMIT_GC_DIRTY_SECTION_NUM)) { >> wait_ms = gc_th->no_gc_sleep_time; >> f2fs_up_write(&sbi->gc_lock); >> goto next; >> @@ -1750,7 +1752,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, >> >> if (f2fs_sb_has_blkzoned(sbi) && >> !has_enough_free_blocks(sbi, >> - sbi->gc_thread->boost_zoned_gc_percent)) >> + sbi->gc_thread->boost_zoned_gc_percent) && >> + has_enough_dirty_blocks(sbi, >> + LIMIT_GC_DIRTY_SECTION_NUM)) >> window_granularity *= >> sbi->gc_thread->boost_gc_multiple; >> >> diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h >> index 24e8b1c27acc..1ef234c2702b 100644 >> --- a/fs/f2fs/gc.h >> +++ b/fs/f2fs/gc.h >> @@ -36,6 +36,7 @@ >> #define DEF_MIGRATION_WINDOW_GRANULARITY_ZONED 3 >> #define BOOST_GC_MULTIPLE 5 >> #define ZONED_PIN_SEC_REQUIRED_COUNT 1 >> +#define LIMIT_GC_DIRTY_SECTION_NUM 3 >> >> #define DEF_GC_FAILED_PINNED_FILES 2048 >> #define MAX_GC_FAILED_PINNED_FILES USHRT_MAX >> @@ -177,6 +178,12 @@ static inline bool has_enough_free_blocks(struct f2fs_sb_info *sbi, >> return free_sections(sbi) > ((sbi->total_sections * limit_perc) / 100); >> } >> >> +static inline bool has_enough_dirty_blocks(struct f2fs_sb_info *sbi, >> + unsigned int limit_num) >> +{ >> + return dirty_segments(sbi) > limit_num * SEGS_PER_SEC(sbi); >> +} >> + >> static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) >> { >> block_t user_block_count = sbi->user_block_count; >> @@ -197,6 +204,7 @@ static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi) >> { >> if (f2fs_sb_has_blkzoned(sbi)) >> return !has_enough_free_blocks(sbi, >> - sbi->gc_thread->boost_zoned_gc_percent); >> + sbi->gc_thread->boost_zoned_gc_percent) && >> + has_enough_dirty_blocks(sbi, LIMIT_GC_DIRTY_SECTION_NUM); >> return has_enough_invalid_blocks(sbi); >> } >> -- >> 2.34.1
On 9/9/25 21:44, Liao Yuanhong wrote: > Incorporate a check using has_enough_dirty_blocks() to prevent redundant > background GC in Zoned UFS. When there are insufficient dirty segments, > continuous execution of background GC should be avoided, as it results in > unnecessary write operations and impacts device lifespan. The initial > threshold is set to 3 * section size (since f2fs data uses three write > pointers). > > Signed-off-by: Liao Yuanhong <liaoyuanhong@vivo.com> Reviewed-by: Chao Yu <chao@kernel.org> Thanks,
© 2016 - 2025 Red Hat, Inc.