Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

f2fs: introduce cp_lock to protect updating of ckpt_flags



This patch introduces spinlock to protect updating process of ckpt_flags
field in struct f2fs_checkpoint, it avoids incorrectly updating in race
condition.

Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: add __is_set_ckpt_flags likewise __set_ckpt_flags]
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent fadb2fb8
Loading
Loading
Loading
Loading
+18 −13
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct kmem_cache *inode_entry_slab;

void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
{
	set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
	set_ckpt_flags(sbi, CP_ERROR_FLAG);
	sbi->sb->s_flags |= MS_RDONLY;
	if (!end_io)
		f2fs_flush_merged_bios(sbi);
@@ -571,7 +571,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
	block_t start_blk, orphan_blocks, i, j;
	int err;

	if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
	if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
		return 0;

	start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
@@ -595,7 +595,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
		f2fs_put_page(page, 1);
	}
	/* clear Orphan Flag */
	clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
	clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG);
	return 0;
}

@@ -1043,10 +1043,12 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	/* 2 cp  + n data seg summary + orphan inode blocks */
	data_sum_blocks = npages_for_summary_flush(sbi, false);
	spin_lock(&sbi->cp_lock);
	if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
		set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
		__set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
	else
		clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
		__clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
	spin_unlock(&sbi->cp_lock);

	orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
	ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
@@ -1061,26 +1063,29 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
				cp_payload_blks + data_sum_blocks +
				orphan_blocks);

	spin_lock(&sbi->cp_lock);
	if (cpc->reason == CP_UMOUNT)
		set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
	else
		clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		__clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);

	if (cpc->reason == CP_FASTBOOT)
		set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
		__set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
	else
		clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
		__clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);

	if (orphan_num)
		set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
		__set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
	else
		clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
		__clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);

	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
		set_ckpt_flags(ckpt, CP_FSCK_FLAG);
		__set_ckpt_flags(ckpt, CP_FSCK_FLAG);

	/* set this flag to activate crc|cp_ver for recovery */
	set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
	__set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);

	spin_unlock(&sbi->cp_lock);

	/* update SIT/NAT bitmap */
	get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
+33 −8
Original line number Diff line number Diff line
@@ -797,6 +797,7 @@ struct f2fs_sb_info {

	/* for checkpoint */
	struct f2fs_checkpoint *ckpt;		/* raw checkpoint pointer */
	spinlock_t cp_lock;			/* for flag in ckpt */
	struct inode *meta_inode;		/* cache meta blocks */
	struct mutex cp_mutex;			/* checkpoint procedure lock */
	struct rw_semaphore cp_rwsem;		/* blocking FS operations */
@@ -1064,26 +1065,50 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
	return le64_to_cpu(cp->checkpoint_ver);
}

static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
static inline bool __is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
{
	unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);

	return ckpt_flags & f;
}

static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
static inline bool is_set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
{
	unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
	return __is_set_ckpt_flags(F2FS_CKPT(sbi), f);
}

static inline void __set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
{
	unsigned int ckpt_flags;

	ckpt_flags = le32_to_cpu(cp->ckpt_flags);
	ckpt_flags |= f;
	cp->ckpt_flags = cpu_to_le32(ckpt_flags);
}

static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
static inline void set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
{
	unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
	spin_lock(&sbi->cp_lock);
	__set_ckpt_flags(F2FS_CKPT(sbi), f);
	spin_unlock(&sbi->cp_lock);
}

static inline void __clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
{
	unsigned int ckpt_flags;

	ckpt_flags = le32_to_cpu(cp->ckpt_flags);
	ckpt_flags &= (~f);
	cp->ckpt_flags = cpu_to_le32(ckpt_flags);
}

static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
{
	spin_lock(&sbi->cp_lock);
	__clear_ckpt_flags(F2FS_CKPT(sbi), f);
	spin_unlock(&sbi->cp_lock);
}

static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi)
{
	struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
@@ -1129,8 +1154,8 @@ static inline bool __remain_node_summaries(int reason)

static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi)
{
	return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) ||
			is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG));
	return (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG) ||
			is_set_ckpt_flags(sbi, CP_FASTBOOT_FLAG));
}

/*
@@ -1832,7 +1857,7 @@ static inline int f2fs_readonly(struct super_block *sb)

static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
{
	return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
	return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
}

static inline bool is_dot_dotdot(const struct qstr *str)
+2 −2
Original line number Diff line number Diff line
@@ -293,7 +293,7 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
	size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
	__u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);

	if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
	if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
		__u64 crc = le32_to_cpu(*((__le32 *)
				((unsigned char *)ckpt + crc_offset)));
		cp_ver |= (crc << 32);
@@ -308,7 +308,7 @@ static inline bool is_recoverable_dnode(struct page *page)
	size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
	__u64 cp_ver = cur_cp_version(ckpt);

	if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
	if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
		__u64 crc = le32_to_cpu(*((__le32 *)
				((unsigned char *)ckpt + crc_offset)));
		cp_ver |= (crc << 32);
+1 −1
Original line number Diff line number Diff line
@@ -627,7 +627,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)

	clear_sbi_flag(sbi, SBI_POR_DOING);
	if (err)
		set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
		set_ckpt_flags(sbi, CP_ERROR_FLAG);
	mutex_unlock(&sbi->cp_mutex);

	/* let's drop all the directory inodes for clean checkpoint */
+2 −2
Original line number Diff line number Diff line
@@ -1801,7 +1801,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
	int type = CURSEG_HOT_DATA;
	int err;

	if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
	if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
		int npages = npages_for_summary_flush(sbi, true);

		if (npages >= 2)
@@ -1898,7 +1898,7 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi,

void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
{
	if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG))
	if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
		write_compacted_summaries(sbi, start_blk);
	else
		write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
Loading