Commit 3fd97359 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim
Browse files

f2fs: fix error path of f2fs_remount()



In error path of f2fs_remount(), it missed to restart/stop kernel thread
or enable/disable checkpoint, then mount option status may not be
consistent with real condition of filesystem, so let's reorder remount
flow a bit as below and do recovery correctly in error path:

1) handle gc thread
2) handle ckpt thread
3) handle flush thread
4) handle checkpoint disabling

Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent f3e367d4
Loading
Loading
Loading
Loading
+34 −13
Original line number Diff line number Diff line
@@ -1927,8 +1927,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
	struct f2fs_mount_info org_mount_opt;
	unsigned long old_sb_flags;
	int err;
	bool need_restart_gc = false;
	bool need_stop_gc = false;
	bool need_restart_gc = false, need_stop_gc = false;
	bool need_restart_ckpt = false, need_stop_ckpt = false;
	bool need_restart_flush = false, need_stop_flush = false;
	bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
	bool disable_checkpoint = test_opt(sbi, DISABLE_CHECKPOINT);
	bool no_io_align = !F2FS_IO_ALIGNED(sbi);
@@ -2059,19 +2060,10 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
		clear_sbi_flag(sbi, SBI_IS_CLOSE);
	}

	if (checkpoint_changed) {
		if (test_opt(sbi, DISABLE_CHECKPOINT)) {
			err = f2fs_disable_checkpoint(sbi);
			if (err)
				goto restore_gc;
		} else {
			f2fs_enable_checkpoint(sbi);
		}
	}

	if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
			!test_opt(sbi, MERGE_CHECKPOINT)) {
		f2fs_stop_ckpt_thread(sbi);
		need_restart_ckpt = true;
	} else {
		err = f2fs_start_ckpt_thread(sbi);
		if (err) {
@@ -2080,6 +2072,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
			    err);
			goto restore_gc;
		}
		need_stop_ckpt = true;
	}

	/*
@@ -2089,11 +2082,24 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
	if ((*flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
		clear_opt(sbi, FLUSH_MERGE);
		f2fs_destroy_flush_cmd_control(sbi, false);
		need_restart_flush = true;
	} else {
		err = f2fs_create_flush_cmd_control(sbi);
		if (err)
			goto restore_gc;
			goto restore_ckpt;
		need_stop_flush = true;
	}

	if (checkpoint_changed) {
		if (test_opt(sbi, DISABLE_CHECKPOINT)) {
			err = f2fs_disable_checkpoint(sbi);
			if (err)
				goto restore_flush;
		} else {
			f2fs_enable_checkpoint(sbi);
		}
	}

skip:
#ifdef CONFIG_QUOTA
	/* Release old quota file names */
@@ -2108,6 +2114,21 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
	adjust_unusable_cap_perc(sbi);
	*flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
	return 0;
restore_flush:
	if (need_restart_flush) {
		if (f2fs_create_flush_cmd_control(sbi))
			f2fs_warn(sbi, "background flush thread has stopped");
	} else if (need_stop_flush) {
		clear_opt(sbi, FLUSH_MERGE);
		f2fs_destroy_flush_cmd_control(sbi, false);
	}
restore_ckpt:
	if (need_restart_ckpt) {
		if (f2fs_start_ckpt_thread(sbi))
			f2fs_warn(sbi, "background ckpt thread has stopped");
	} else if (need_stop_ckpt) {
		f2fs_stop_ckpt_thread(sbi);
	}
restore_gc:
	if (need_restart_gc) {
		if (f2fs_start_gc_thread(sbi))