Commit 6e0b0ffc authored by Chao Yu's avatar Chao Yu Committed by Yifan Qiao
Browse files

f2fs: fix to stop filesystem update once CP failed

mainline inclusion
from mainline-v5.15-rc1
commit 91803392
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9L9NO
CVE: CVE-2024-27034

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=91803392c732c43b5cf440e885ea89be7f5fecef



--------------------------------

During f2fs_write_checkpoint(), once we failed in
f2fs_flush_nat_entries() or do_checkpoint(), metadata of filesystem
such as prefree bitmap, nat/sit version bitmap won't be recovered,
it may cause f2fs image to be inconsistent, let's just set CP error
flag to avoid further updates until we figure out a scheme to rollback
all metadatas in such condition.

Reported-by: default avatarYangtao Li <frank.li@vivo.com>
Signed-off-by: default avatarYangtao Li <frank.li@vivo.com>
Signed-off-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: default avatarYifan Qiao <qiaoyifan4@huawei.com>
parent e706c6b6
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -1645,8 +1645,11 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	/* write cached NAT/SIT entries to NAT/SIT area */
	err = f2fs_flush_nat_entries(sbi, cpc);
	if (err)
	if (err) {
		f2fs_err(sbi, "f2fs_flush_nat_entries failed err:%d, stop checkpoint", err);
		f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
		goto stop;
	}

	f2fs_flush_sit_entries(sbi, cpc);

@@ -1654,10 +1657,13 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	f2fs_save_inmem_curseg(sbi);

	err = do_checkpoint(sbi, cpc);
	if (err)
	if (err) {
		f2fs_err(sbi, "do_checkpoint failed err:%d, stop checkpoint", err);
		f2fs_bug_on(sbi, !f2fs_cp_error(sbi));
		f2fs_release_discard_addrs(sbi);
	else
	} else {
		f2fs_clear_prefree_segments(sbi, cpc);
	}

	f2fs_restore_inmem_curseg(sbi);
stop:
+1 −1
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ enum {
					 */
};

#define DEFAULT_RETRY_IO_COUNT	8	/* maximum retry read IO count */
#define DEFAULT_RETRY_IO_COUNT	8	/* maximum retry read IO or flush count */

/* congestion wait timeout value, default: 20ms */
#define	DEFAULT_IO_TIMEOUT	(msecs_to_jiffies(20))
+13 −2
Original line number Diff line number Diff line
@@ -777,11 +777,22 @@ int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
		return 0;

	for (i = 1; i < sbi->s_ndevs; i++) {
		int count = DEFAULT_RETRY_IO_COUNT;

		if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
			continue;

		do {
			ret = __submit_flush_wait(sbi, FDEV(i).bdev);
			if (ret)
				congestion_wait(BLK_RW_ASYNC,
						DEFAULT_IO_TIMEOUT);
		} while (ret && --count);

		if (ret) {
			f2fs_stop_checkpoint(sbi, false);
			break;
		}

		spin_lock(&sbi->dev_lock);
		f2fs_clear_bit(i, (char *)&sbi->dirty_device);