Skip to content

Commit aaec2b1

Browse files
chaseyuJaegeuk Kim
authored and
Jaegeuk Kim
committed
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: Chao Yu <[email protected]> [Jaegeuk Kim: add __is_set_ckpt_flags likewise __set_ckpt_flags] Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent fadb2fb commit aaec2b1

File tree

6 files changed

+59
-28
lines changed

6 files changed

+59
-28
lines changed

fs/f2fs/checkpoint.c

+18-13
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct kmem_cache *inode_entry_slab;
2828

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

574-
if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
574+
if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
575575
return 0;
576576

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

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

10441044
/* 2 cp + n data seg summary + orphan inode blocks */
10451045
data_sum_blocks = npages_for_summary_flush(sbi, false);
1046+
spin_lock(&sbi->cp_lock);
10461047
if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
1047-
set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
1048+
__set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
10481049
else
1049-
clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
1050+
__clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
1051+
spin_unlock(&sbi->cp_lock);
10501052

10511053
orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
10521054
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)
10611063
cp_payload_blks + data_sum_blocks +
10621064
orphan_blocks);
10631065

1066+
spin_lock(&sbi->cp_lock);
10641067
if (cpc->reason == CP_UMOUNT)
1065-
set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
1068+
__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
10661069
else
1067-
clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
1070+
__clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
10681071

10691072
if (cpc->reason == CP_FASTBOOT)
1070-
set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
1073+
__set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
10711074
else
1072-
clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
1075+
__clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
10731076

10741077
if (orphan_num)
1075-
set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
1078+
__set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
10761079
else
1077-
clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
1080+
__clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
10781081

10791082
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
1080-
set_ckpt_flags(ckpt, CP_FSCK_FLAG);
1083+
__set_ckpt_flags(ckpt, CP_FSCK_FLAG);
10811084

10821085
/* set this flag to activate crc|cp_ver for recovery */
1083-
set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
1086+
__set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
1087+
1088+
spin_unlock(&sbi->cp_lock);
10841089

10851090
/* update SIT/NAT bitmap */
10861091
get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));

fs/f2fs/f2fs.h

+33-8
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ struct f2fs_sb_info {
797797

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

1067-
static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1068+
static inline bool __is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
10681069
{
10691070
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
1071+
10701072
return ckpt_flags & f;
10711073
}
10721074

1073-
static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1075+
static inline bool is_set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
10741076
{
1075-
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
1077+
return __is_set_ckpt_flags(F2FS_CKPT(sbi), f);
1078+
}
1079+
1080+
static inline void __set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1081+
{
1082+
unsigned int ckpt_flags;
1083+
1084+
ckpt_flags = le32_to_cpu(cp->ckpt_flags);
10761085
ckpt_flags |= f;
10771086
cp->ckpt_flags = cpu_to_le32(ckpt_flags);
10781087
}
10791088

1080-
static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1089+
static inline void set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
10811090
{
1082-
unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
1091+
spin_lock(&sbi->cp_lock);
1092+
__set_ckpt_flags(F2FS_CKPT(sbi), f);
1093+
spin_unlock(&sbi->cp_lock);
1094+
}
1095+
1096+
static inline void __clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1097+
{
1098+
unsigned int ckpt_flags;
1099+
1100+
ckpt_flags = le32_to_cpu(cp->ckpt_flags);
10831101
ckpt_flags &= (~f);
10841102
cp->ckpt_flags = cpu_to_le32(ckpt_flags);
10851103
}
10861104

1105+
static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
1106+
{
1107+
spin_lock(&sbi->cp_lock);
1108+
__clear_ckpt_flags(F2FS_CKPT(sbi), f);
1109+
spin_unlock(&sbi->cp_lock);
1110+
}
1111+
10871112
static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi)
10881113
{
10891114
struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
@@ -1129,8 +1154,8 @@ static inline bool __remain_node_summaries(int reason)
11291154

11301155
static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi)
11311156
{
1132-
return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) ||
1133-
is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG));
1157+
return (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG) ||
1158+
is_set_ckpt_flags(sbi, CP_FASTBOOT_FLAG));
11341159
}
11351160

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

18331858
static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
18341859
{
1835-
return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
1860+
return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
18361861
}
18371862

18381863
static inline bool is_dot_dotdot(const struct qstr *str)

fs/f2fs/node.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
293293
size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
294294
__u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);
295295

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

311-
if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
311+
if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
312312
__u64 crc = le32_to_cpu(*((__le32 *)
313313
((unsigned char *)ckpt + crc_offset)));
314314
cp_ver |= (crc << 32);

fs/f2fs/recovery.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
627627

628628
clear_sbi_flag(sbi, SBI_POR_DOING);
629629
if (err)
630-
set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
630+
set_ckpt_flags(sbi, CP_ERROR_FLAG);
631631
mutex_unlock(&sbi->cp_mutex);
632632

633633
/* let's drop all the directory inodes for clean checkpoint */

fs/f2fs/segment.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
18011801
int type = CURSEG_HOT_DATA;
18021802
int err;
18031803

1804-
if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
1804+
if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
18051805
int npages = npages_for_summary_flush(sbi, true);
18061806

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

18991899
void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
19001900
{
1901-
if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG))
1901+
if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
19021902
write_compacted_summaries(sbi, start_blk);
19031903
else
19041904
write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);

fs/f2fs/super.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ static void f2fs_put_super(struct super_block *sb)
736736
* clean checkpoint again.
737737
*/
738738
if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
739-
!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) {
739+
!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
740740
struct cp_control cpc = {
741741
.reason = CP_UMOUNT,
742742
};
@@ -1478,6 +1478,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
14781478
mutex_init(&sbi->umount_mutex);
14791479
mutex_init(&sbi->wio_mutex[NODE]);
14801480
mutex_init(&sbi->wio_mutex[DATA]);
1481+
spin_lock_init(&sbi->cp_lock);
14811482

14821483
#ifdef CONFIG_F2FS_FS_ENCRYPTION
14831484
memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
@@ -1819,7 +1820,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
18191820
* previous checkpoint was not done by clean system shutdown.
18201821
*/
18211822
if (bdev_read_only(sb->s_bdev) &&
1822-
!is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) {
1823+
!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
18231824
err = -EROFS;
18241825
goto free_kobj;
18251826
}

0 commit comments

Comments
 (0)