aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2016-09-19 23:04:18 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2016-09-30 20:34:20 -0400
commitaaec2b1d18792a5f27b69ff37f34f43f89f5aa3b (patch)
treed21e6ad4e210ad826580c03a55cb97230543c280
parentfadb2fb8af5348c1bc59cab17c6f8bf515e50d55 (diff)
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 <yuchao0@huawei.com> [Jaegeuk Kim: add __is_set_ckpt_flags likewise __set_ckpt_flags] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/checkpoint.c31
-rw-r--r--fs/f2fs/f2fs.h41
-rw-r--r--fs/f2fs/node.h4
-rw-r--r--fs/f2fs/recovery.c2
-rw-r--r--fs/f2fs/segment.c4
-rw-r--r--fs/f2fs/super.c5
6 files changed, 59 insertions, 28 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 9c6439b0e8d2..591db95222d1 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -28,7 +28,7 @@ struct kmem_cache *inode_entry_slab;
28 28
29void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) 29void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
30{ 30{
31 set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); 31 set_ckpt_flags(sbi, CP_ERROR_FLAG);
32 sbi->sb->s_flags |= MS_RDONLY; 32 sbi->sb->s_flags |= MS_RDONLY;
33 if (!end_io) 33 if (!end_io)
34 f2fs_flush_merged_bios(sbi); 34 f2fs_flush_merged_bios(sbi);
@@ -571,7 +571,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
571 block_t start_blk, orphan_blocks, i, j; 571 block_t start_blk, orphan_blocks, i, j;
572 int err; 572 int err;
573 573
574 if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) 574 if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
575 return 0; 575 return 0;
576 576
577 start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); 577 start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
@@ -595,7 +595,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
595 f2fs_put_page(page, 1); 595 f2fs_put_page(page, 1);
596 } 596 }
597 /* clear Orphan Flag */ 597 /* clear Orphan Flag */
598 clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); 598 clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG);
599 return 0; 599 return 0;
600} 600}
601 601
@@ -1043,10 +1043,12 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
1043 1043
1044 /* 2 cp + n data seg summary + orphan inode blocks */ 1044 /* 2 cp + n data seg summary + orphan inode blocks */
1045 data_sum_blocks = npages_for_summary_flush(sbi, false); 1045 data_sum_blocks = npages_for_summary_flush(sbi, false);
1046 spin_lock(&sbi->cp_lock);
1046 if (data_sum_blocks < NR_CURSEG_DATA_TYPE) 1047 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);
1048 else 1049 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);
1050 1052
1051 orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num); 1053 orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
1052 ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + 1054 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)
1061 cp_payload_blks + data_sum_blocks + 1063 cp_payload_blks + data_sum_blocks +
1062 orphan_blocks); 1064 orphan_blocks);
1063 1065
1066 spin_lock(&sbi->cp_lock);
1064 if (cpc->reason == CP_UMOUNT) 1067 if (cpc->reason == CP_UMOUNT)
1065 set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); 1068 __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
1066 else 1069 else
1067 clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); 1070 __clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
1068 1071
1069 if (cpc->reason == CP_FASTBOOT) 1072 if (cpc->reason == CP_FASTBOOT)
1070 set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); 1073 __set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
1071 else 1074 else
1072 clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); 1075 __clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
1073 1076
1074 if (orphan_num) 1077 if (orphan_num)
1075 set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); 1078 __set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
1076 else 1079 else
1077 clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); 1080 __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
1078 1081
1079 if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) 1082 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);
1081 1084
1082 /* set this flag to activate crc|cp_ver for recovery */ 1085 /* 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);
1084 1089
1085 /* update SIT/NAT bitmap */ 1090 /* update SIT/NAT bitmap */
1086 get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); 1091 get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 04e96181e928..2fb8c353ab4a 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -797,6 +797,7 @@ struct f2fs_sb_info {
797 797
798 /* for checkpoint */ 798 /* for checkpoint */
799 struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ 799 struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
800 spinlock_t cp_lock; /* for flag in ckpt */
800 struct inode *meta_inode; /* cache meta blocks */ 801 struct inode *meta_inode; /* cache meta blocks */
801 struct mutex cp_mutex; /* checkpoint procedure lock */ 802 struct mutex cp_mutex; /* checkpoint procedure lock */
802 struct rw_semaphore cp_rwsem; /* blocking FS operations */ 803 struct rw_semaphore cp_rwsem; /* blocking FS operations */
@@ -1064,26 +1065,50 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
1064 return le64_to_cpu(cp->checkpoint_ver); 1065 return le64_to_cpu(cp->checkpoint_ver);
1065} 1066}
1066 1067
1067static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) 1068static inline bool __is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
1068{ 1069{
1069 unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); 1070 unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
1071
1070 return ckpt_flags & f; 1072 return ckpt_flags & f;
1071} 1073}
1072 1074
1073static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) 1075static inline bool is_set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
1074{ 1076{
1075 unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); 1077 return __is_set_ckpt_flags(F2FS_CKPT(sbi), f);
1078}
1079
1080static 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);
1076 ckpt_flags |= f; 1085 ckpt_flags |= f;
1077 cp->ckpt_flags = cpu_to_le32(ckpt_flags); 1086 cp->ckpt_flags = cpu_to_le32(ckpt_flags);
1078} 1087}
1079 1088
1080static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) 1089static inline void set_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
1081{ 1090{
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
1096static 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);
1083 ckpt_flags &= (~f); 1101 ckpt_flags &= (~f);
1084 cp->ckpt_flags = cpu_to_le32(ckpt_flags); 1102 cp->ckpt_flags = cpu_to_le32(ckpt_flags);
1085} 1103}
1086 1104
1105static 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
1087static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi) 1112static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi)
1088{ 1113{
1089 struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev); 1114 struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
@@ -1129,8 +1154,8 @@ static inline bool __remain_node_summaries(int reason)
1129 1154
1130static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi) 1155static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi)
1131{ 1156{
1132 return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) || 1157 return (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG) ||
1133 is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG)); 1158 is_set_ckpt_flags(sbi, CP_FASTBOOT_FLAG));
1134} 1159}
1135 1160
1136/* 1161/*
@@ -1832,7 +1857,7 @@ static inline int f2fs_readonly(struct super_block *sb)
1832 1857
1833static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi) 1858static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
1834{ 1859{
1835 return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); 1860 return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
1836} 1861}
1837 1862
1838static inline bool is_dot_dotdot(const struct qstr *str) 1863static inline bool is_dot_dotdot(const struct qstr *str)
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index e8ca64a70de0..868bec65e51c 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -293,7 +293,7 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
293 size_t crc_offset = le32_to_cpu(ckpt->checksum_offset); 293 size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
294 __u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver); 294 __u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);
295 295
296 if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) { 296 if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
297 __u64 crc = le32_to_cpu(*((__le32 *) 297 __u64 crc = le32_to_cpu(*((__le32 *)
298 ((unsigned char *)ckpt + crc_offset))); 298 ((unsigned char *)ckpt + crc_offset)));
299 cp_ver |= (crc << 32); 299 cp_ver |= (crc << 32);
@@ -308,7 +308,7 @@ static inline bool is_recoverable_dnode(struct page *page)
308 size_t crc_offset = le32_to_cpu(ckpt->checksum_offset); 308 size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
309 __u64 cp_ver = cur_cp_version(ckpt); 309 __u64 cp_ver = cur_cp_version(ckpt);
310 310
311 if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) { 311 if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
312 __u64 crc = le32_to_cpu(*((__le32 *) 312 __u64 crc = le32_to_cpu(*((__le32 *)
313 ((unsigned char *)ckpt + crc_offset))); 313 ((unsigned char *)ckpt + crc_offset)));
314 cp_ver |= (crc << 32); 314 cp_ver |= (crc << 32);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 509273a65157..2fc84a991325 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -627,7 +627,7 @@ out:
627 627
628 clear_sbi_flag(sbi, SBI_POR_DOING); 628 clear_sbi_flag(sbi, SBI_POR_DOING);
629 if (err) 629 if (err)
630 set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); 630 set_ckpt_flags(sbi, CP_ERROR_FLAG);
631 mutex_unlock(&sbi->cp_mutex); 631 mutex_unlock(&sbi->cp_mutex);
632 632
633 /* let's drop all the directory inodes for clean checkpoint */ 633 /* let's drop all the directory inodes for clean checkpoint */
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 2d23d7b17d6c..e78501ca761e 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1801,7 +1801,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
1801 int type = CURSEG_HOT_DATA; 1801 int type = CURSEG_HOT_DATA;
1802 int err; 1802 int err;
1803 1803
1804 if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { 1804 if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
1805 int npages = npages_for_summary_flush(sbi, true); 1805 int npages = npages_for_summary_flush(sbi, true);
1806 1806
1807 if (npages >= 2) 1807 if (npages >= 2)
@@ -1898,7 +1898,7 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi,
1898 1898
1899void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) 1899void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
1900{ 1900{
1901 if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) 1901 if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
1902 write_compacted_summaries(sbi, start_blk); 1902 write_compacted_summaries(sbi, start_blk);
1903 else 1903 else
1904 write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); 1904 write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 9649b79eefe8..95986a9aa615 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -736,7 +736,7 @@ static void f2fs_put_super(struct super_block *sb)
736 * clean checkpoint again. 736 * clean checkpoint again.
737 */ 737 */
738 if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || 738 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)) {
740 struct cp_control cpc = { 740 struct cp_control cpc = {
741 .reason = CP_UMOUNT, 741 .reason = CP_UMOUNT,
742 }; 742 };
@@ -1478,6 +1478,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
1478 mutex_init(&sbi->umount_mutex); 1478 mutex_init(&sbi->umount_mutex);
1479 mutex_init(&sbi->wio_mutex[NODE]); 1479 mutex_init(&sbi->wio_mutex[NODE]);
1480 mutex_init(&sbi->wio_mutex[DATA]); 1480 mutex_init(&sbi->wio_mutex[DATA]);
1481 spin_lock_init(&sbi->cp_lock);
1481 1482
1482#ifdef CONFIG_F2FS_FS_ENCRYPTION 1483#ifdef CONFIG_F2FS_FS_ENCRYPTION
1483 memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX, 1484 memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
@@ -1819,7 +1820,7 @@ try_onemore:
1819 * previous checkpoint was not done by clean system shutdown. 1820 * previous checkpoint was not done by clean system shutdown.
1820 */ 1821 */
1821 if (bdev_read_only(sb->s_bdev) && 1822 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)) {
1823 err = -EROFS; 1824 err = -EROFS;
1824 goto free_kobj; 1825 goto free_kobj;
1825 } 1826 }