UPSTREAM: f2fs: add valid block ratio not to do excessive GC for one time GC

We need to introduce a valid block ratio threshold not to trigger
excessive GC for zoned deivces. The initial value of it is 95%. So, F2FS
will stop the thread from intiating GC for sections having valid blocks
exceeding the ratio.

Change-Id: I279b53971a604c3270beb05b91fed69e5c0e8ff0
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
(cherry picked from commit e791d00bd0)
This commit is contained in:
Daeho Jeong 2024-09-09 15:19:46 -07:00 committed by Matthias Männich
parent 9e1830d502
commit 8c9ffe678f
7 changed files with 30 additions and 7 deletions

View File

@ -811,3 +811,11 @@ Contact: "Daeho Jeong" <daehojeong@google.com>
Description: If the percentage of free sections over total sections is under this Description: If the percentage of free sections over total sections is under this
number, F2FS boosts garbage collection for zoned devices through the number, F2FS boosts garbage collection for zoned devices through the
background GC thread. the default number is "25". background GC thread. the default number is "25".
What: /sys/fs/f2fs/<disk>/gc_valid_thresh_ratio
Date: September 2024
Contact: "Daeho Jeong" <daehojeong@google.com>
Description: It controls the valid block ratio threshold not to trigger excessive GC
for zoned deivces. The initial value of it is 95(%). F2FS will stop the
background GC thread from intiating GC for sections having valid blocks
exceeding the ratio.

View File

@ -3916,7 +3916,7 @@ void f2fs_destroy_garbage_collection_cache(void);
/* victim selection function for cleaning and SSR */ /* victim selection function for cleaning and SSR */
int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
int gc_type, int type, char alloc_mode, int gc_type, int type, char alloc_mode,
unsigned long long age); unsigned long long age, bool one_time);
/* /*
* recovery.c * recovery.c

View File

@ -196,6 +196,7 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
return -ENOMEM; return -ENOMEM;
gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME; gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME;
gc_th->valid_thresh_ratio = DEF_GC_THREAD_VALID_THRESH_RATIO;
if (f2fs_sb_has_blkzoned(sbi)) { if (f2fs_sb_has_blkzoned(sbi)) {
gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME_ZONED; gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME_ZONED;
@ -396,6 +397,11 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
if (p->alloc_mode == SSR) if (p->alloc_mode == SSR)
return get_seg_entry(sbi, segno)->ckpt_valid_blocks; return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
if (p->one_time_gc && (get_valid_blocks(sbi, segno, true) >=
CAP_BLKS_PER_SEC(sbi) * sbi->gc_thread->valid_thresh_ratio /
100))
return UINT_MAX;
/* alloc_mode == LFS */ /* alloc_mode == LFS */
if (p->gc_mode == GC_GREEDY) if (p->gc_mode == GC_GREEDY)
return get_valid_blocks(sbi, segno, true); return get_valid_blocks(sbi, segno, true);
@ -770,7 +776,7 @@ static int f2fs_gc_pinned_control(struct inode *inode, int gc_type,
*/ */
int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result, int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
int gc_type, int type, char alloc_mode, int gc_type, int type, char alloc_mode,
unsigned long long age) unsigned long long age, bool one_time)
{ {
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
struct sit_info *sm = SIT_I(sbi); struct sit_info *sm = SIT_I(sbi);
@ -787,6 +793,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
p.alloc_mode = alloc_mode; p.alloc_mode = alloc_mode;
p.age = age; p.age = age;
p.age_threshold = sbi->am.age_threshold; p.age_threshold = sbi->am.age_threshold;
p.one_time_gc = one_time;
retry: retry:
select_policy(sbi, gc_type, type, &p); select_policy(sbi, gc_type, type, &p);
@ -1698,13 +1705,14 @@ next_step:
} }
static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
int gc_type) int gc_type, bool one_time)
{ {
struct sit_info *sit_i = SIT_I(sbi); struct sit_info *sit_i = SIT_I(sbi);
int ret; int ret;
down_write(&sit_i->sentry_lock); down_write(&sit_i->sentry_lock);
ret = f2fs_get_victim(sbi, victim, gc_type, NO_CHECK_TYPE, LFS, 0); ret = f2fs_get_victim(sbi, victim, gc_type, NO_CHECK_TYPE,
LFS, 0, one_time);
up_write(&sit_i->sentry_lock); up_write(&sit_i->sentry_lock);
return ret; return ret;
} }
@ -1911,7 +1919,7 @@ gc_more:
goto stop; goto stop;
} }
retry: retry:
ret = __get_victim(sbi, &segno, gc_type); ret = __get_victim(sbi, &segno, gc_type, gc_control->one_time);
if (ret) { if (ret) {
/* allow to search victim from sections has pinned data */ /* allow to search victim from sections has pinned data */
if (ret == -ENODATA && gc_type == FG_GC && if (ret == -ENODATA && gc_type == FG_GC &&

View File

@ -25,6 +25,7 @@
#define DEF_GC_THREAD_CANDIDATE_RATIO 20 /* select 20% oldest sections as candidates */ #define DEF_GC_THREAD_CANDIDATE_RATIO 20 /* select 20% oldest sections as candidates */
#define DEF_GC_THREAD_MAX_CANDIDATE_COUNT 10 /* select at most 10 sections as candidates */ #define DEF_GC_THREAD_MAX_CANDIDATE_COUNT 10 /* select at most 10 sections as candidates */
#define DEF_GC_THREAD_AGE_WEIGHT 60 /* age weight */ #define DEF_GC_THREAD_AGE_WEIGHT 60 /* age weight */
#define DEF_GC_THREAD_VALID_THRESH_RATIO 95 /* do not GC over 95% valid block ratio for one time GC */
#define DEFAULT_ACCURACY_CLASS 10000 /* accuracy class */ #define DEFAULT_ACCURACY_CLASS 10000 /* accuracy class */
#define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ #define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */
@ -65,6 +66,7 @@ struct f2fs_gc_kthread {
/* for gc control for zoned devices */ /* for gc control for zoned devices */
unsigned int no_zoned_gc_percent; unsigned int no_zoned_gc_percent;
unsigned int boost_zoned_gc_percent; unsigned int boost_zoned_gc_percent;
unsigned int valid_thresh_ratio;
}; };
struct gc_inode_list { struct gc_inode_list {

View File

@ -3084,7 +3084,8 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
sanity_check_seg_type(sbi, seg_type); sanity_check_seg_type(sbi, seg_type);
/* f2fs_need_SSR() already forces to do this */ /* f2fs_need_SSR() already forces to do this */
if (!f2fs_get_victim(sbi, &segno, BG_GC, seg_type, alloc_mode, age)) { if (!f2fs_get_victim(sbi, &segno, BG_GC, seg_type,
alloc_mode, age, false)) {
curseg->next_segno = segno; curseg->next_segno = segno;
return 1; return 1;
} }
@ -3111,7 +3112,8 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
for (; cnt-- > 0; reversed ? i-- : i++) { for (; cnt-- > 0; reversed ? i-- : i++) {
if (i == seg_type) if (i == seg_type)
continue; continue;
if (!f2fs_get_victim(sbi, &segno, BG_GC, i, alloc_mode, age)) { if (!f2fs_get_victim(sbi, &segno, BG_GC, i,
alloc_mode, age, false)) {
curseg->next_segno = segno; curseg->next_segno = segno;
return 1; return 1;
} }

View File

@ -188,6 +188,7 @@ struct victim_sel_policy {
unsigned int min_segno; /* segment # having min. cost */ unsigned int min_segno; /* segment # having min. cost */
unsigned long long age; /* mtime of GCed section*/ unsigned long long age; /* mtime of GCed section*/
unsigned long long age_threshold;/* age threshold */ unsigned long long age_threshold;/* age threshold */
bool one_time_gc; /* one time GC */
}; };
struct seg_entry { struct seg_entry {

View File

@ -979,6 +979,7 @@ GC_THREAD_RW_ATTR(gc_max_sleep_time, max_sleep_time);
GC_THREAD_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); GC_THREAD_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time);
GC_THREAD_RW_ATTR(gc_no_zoned_gc_percent, no_zoned_gc_percent); GC_THREAD_RW_ATTR(gc_no_zoned_gc_percent, no_zoned_gc_percent);
GC_THREAD_RW_ATTR(gc_boost_zoned_gc_percent, boost_zoned_gc_percent); GC_THREAD_RW_ATTR(gc_boost_zoned_gc_percent, boost_zoned_gc_percent);
GC_THREAD_RW_ATTR(gc_valid_thresh_ratio, valid_thresh_ratio);
/* SM_INFO ATTR */ /* SM_INFO ATTR */
SM_INFO_RW_ATTR(reclaim_segments, rec_prefree_segments); SM_INFO_RW_ATTR(reclaim_segments, rec_prefree_segments);
@ -1141,6 +1142,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(gc_no_gc_sleep_time), ATTR_LIST(gc_no_gc_sleep_time),
ATTR_LIST(gc_no_zoned_gc_percent), ATTR_LIST(gc_no_zoned_gc_percent),
ATTR_LIST(gc_boost_zoned_gc_percent), ATTR_LIST(gc_boost_zoned_gc_percent),
ATTR_LIST(gc_valid_thresh_ratio),
ATTR_LIST(gc_idle), ATTR_LIST(gc_idle),
ATTR_LIST(gc_urgent), ATTR_LIST(gc_urgent),
ATTR_LIST(reclaim_segments), ATTR_LIST(reclaim_segments),