Commit e791d00b authored by Daeho Jeong's avatar Daeho Jeong Committed by Jaegeuk Kim
Browse files

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.

Signed-off-by: default avatarDaeho Jeong <daehojeong@google.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 9a481a1c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -811,3 +811,11 @@ Contact: "Daeho Jeong" <daehojeong@google.com>
Description:	If the percentage of free sections over total sections is under this
		number, F2FS boosts garbage collection for zoned devices through the
		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.
+1 −1
Original line number Diff line number Diff line
@@ -3922,7 +3922,7 @@ void f2fs_destroy_garbage_collection_cache(void);
/* victim selection function for cleaning and SSR */
int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
			int gc_type, int type, char alloc_mode,
			unsigned long long age);
			unsigned long long age, bool one_time);

/*
 * recovery.c
+12 −4
Original line number Diff line number Diff line
@@ -196,6 +196,7 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
		return -ENOMEM;

	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)) {
		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)
		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 */
	if (p->gc_mode == GC_GREEDY)
		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 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 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.age = age;
	p.age_threshold = sbi->am.age_threshold;
	p.one_time_gc = one_time;

retry:
	select_policy(sbi, gc_type, type, &p);
@@ -1698,13 +1705,14 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
}

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);
	int ret;

	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);
	return ret;
}
@@ -1911,7 +1919,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
		goto stop;
	}
retry:
	ret = __get_victim(sbi, &segno, gc_type);
	ret = __get_victim(sbi, &segno, gc_type, gc_control->one_time);
	if (ret) {
		/* allow to search victim from sections has pinned data */
		if (ret == -ENODATA && gc_type == FG_GC &&
+2 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#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_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 LIMIT_INVALID_BLOCK	40 /* percentage over total user space */
@@ -65,6 +66,7 @@ struct f2fs_gc_kthread {
	/* for gc control for zoned devices */
	unsigned int no_zoned_gc_percent;
	unsigned int boost_zoned_gc_percent;
	unsigned int valid_thresh_ratio;
};

struct gc_inode_list {
+4 −2
Original line number Diff line number Diff line
@@ -3090,7 +3090,8 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
	sanity_check_seg_type(sbi, seg_type);

	/* 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;
		return 1;
	}
@@ -3117,7 +3118,8 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
	for (; cnt-- > 0; reversed ? i-- : i++) {
		if (i == seg_type)
			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;
			return 1;
		}
Loading