Commit c81d5bae authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: do not stop GC when requiring a free section



The f2fs_gc uses a bitmap to indicate pinned sections, but when disabling
chckpoint, we call f2fs_gc() with NULL_SEGNO which selects the same dirty
segment as a victim all the time, resulting in checkpoint=disable failure,
for example. Let's pick another one, if we fail to collect it.

Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent c58d7c55
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1271,6 +1271,7 @@ struct f2fs_gc_control {
	bool no_bg_gc;			/* check the space and stop bg_gc */
	bool should_migrate_blocks;	/* should migrate blocks */
	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
	unsigned int nr_free_secs;	/* # of free sections to do GC */
};

/* For s_flag in struct f2fs_sb_info */
+8 −4
Original line number Diff line number Diff line
@@ -1650,7 +1650,8 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
			.init_gc_type = FG_GC,
			.should_migrate_blocks = false,
			.err_gc_skipped = true };
			.err_gc_skipped = true,
			.nr_free_secs = 0 };
	pgoff_t pg_start, pg_end;
	loff_t new_size = i_size_read(inode);
	loff_t off_end;
@@ -2350,7 +2351,8 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
			.no_bg_gc = false,
			.should_migrate_blocks = false };
			.should_migrate_blocks = false,
			.nr_free_secs = 0 };
	__u32 sync;
	int ret;

@@ -2391,7 +2393,8 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
			.init_gc_type = range->sync ? FG_GC : BG_GC,
			.no_bg_gc = false,
			.should_migrate_blocks = false,
			.err_gc_skipped = range->sync };
			.err_gc_skipped = range->sync,
			.nr_free_secs = 0 };
	u64 end;
	int ret;

@@ -2837,7 +2840,8 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
	struct f2fs_gc_control gc_control = {
			.init_gc_type = FG_GC,
			.should_migrate_blocks = true,
			.err_gc_skipped = true };
			.err_gc_skipped = true,
			.nr_free_secs = 0 };
	int ret;

	if (!capable(CAP_SYS_ADMIN))
+9 −5
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ static int gc_thread_func(void *data)

		gc_control.init_gc_type = sync_mode ? FG_GC : BG_GC;
		gc_control.no_bg_gc = foreground;
		gc_control.nr_free_secs = foreground ? 1 : 0;

		/* if return value is not zero, no victim was selected */
		if (f2fs_gc(sbi, &gc_control))
@@ -1761,6 +1762,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
	unsigned int skipped_round = 0, round = 0;

	trace_f2fs_gc_begin(sbi->sb, gc_type, gc_control->no_bg_gc,
				gc_control->nr_free_secs,
				get_pages(sbi, F2FS_DIRTY_NODES),
				get_pages(sbi, F2FS_DIRTY_DENTS),
				get_pages(sbi, F2FS_DIRTY_IMETA),
@@ -1823,12 +1825,13 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
	if (gc_type == FG_GC)
		sbi->cur_victim_sec = NULL_SEGNO;

	if (gc_control->init_gc_type == FG_GC)
		goto stop;

	if (!has_not_enough_free_secs(sbi,
			(gc_type == FG_GC) ? sec_freed : 0, 0))
	if (gc_control->init_gc_type == FG_GC ||
	    !has_not_enough_free_secs(sbi,
				(gc_type == FG_GC) ? sec_freed : 0, 0)) {
		if (gc_type == FG_GC && sec_freed < gc_control->nr_free_secs)
			goto go_gc_more;
		goto stop;
	}

	/* FG_GC stops GC by skip_count */
	if (gc_type == FG_GC) {
@@ -1849,6 +1852,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
		if (ret)
			goto stop;
	}
go_gc_more:
	segno = NULL_SEGNO;
	goto gc_more;

+2 −1
Original line number Diff line number Diff line
@@ -404,7 +404,8 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
				.init_gc_type = BG_GC,
				.no_bg_gc = true,
				.should_migrate_blocks = false,
				.err_gc_skipped = false };
				.err_gc_skipped = false,
				.nr_free_secs = 1 };
			f2fs_down_write(&sbi->gc_lock);
			f2fs_gc(sbi, &gc_control);
		}
+2 −1
Original line number Diff line number Diff line
@@ -2080,7 +2080,8 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
			.victim_segno = NULL_SEGNO,
			.init_gc_type = FG_GC,
			.should_migrate_blocks = false,
			.err_gc_skipped = true };
			.err_gc_skipped = true,
			.nr_free_secs = 1 };

		f2fs_down_write(&sbi->gc_lock);
		err = f2fs_gc(sbi, &gc_control);
Loading