aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2016-03-20 18:33:20 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2016-03-28 13:43:01 -0400
commitfd694733d523df1e0a583cf5c4c08e41d7bf9fa3 (patch)
tree88eb7c9bc980ad39587cd211b6ba4d80f26ce824 /fs/f2fs
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
f2fs: cover large section in sanity check of super
This patch fixes the bug which does not cover a large section case when checking the sanity of superblock. If f2fs detects misalignment, it will fix the superblock during the mount time, so it doesn't need to trigger fsck.f2fs further. Reported-by: Matthias Prager <linux@matthiasprager.de> Reported-by: David Gnedt <david.gnedt@davizone.at> Cc: stable 4.5+ <stable@vger.kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/super.c102
1 files changed, 65 insertions, 37 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 15bb81f8dac2..5afb4a6e01a2 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -984,9 +984,25 @@ static loff_t max_file_blocks(void)
984 return result; 984 return result;
985} 985}
986 986
987static int __f2fs_commit_super(struct buffer_head *bh,
988 struct f2fs_super_block *super)
989{
990 lock_buffer(bh);
991 if (super)
992 memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
993 set_buffer_uptodate(bh);
994 set_buffer_dirty(bh);
995 unlock_buffer(bh);
996
997 /* it's rare case, we can do fua all the time */
998 return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
999}
1000
987static inline bool sanity_check_area_boundary(struct super_block *sb, 1001static inline bool sanity_check_area_boundary(struct super_block *sb,
988 struct f2fs_super_block *raw_super) 1002 struct buffer_head *bh)
989{ 1003{
1004 struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
1005 (bh->b_data + F2FS_SUPER_OFFSET);
990 u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); 1006 u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
991 u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); 1007 u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
992 u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); 1008 u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
@@ -1000,6 +1016,10 @@ static inline bool sanity_check_area_boundary(struct super_block *sb,
1000 u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); 1016 u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
1001 u32 segment_count = le32_to_cpu(raw_super->segment_count); 1017 u32 segment_count = le32_to_cpu(raw_super->segment_count);
1002 u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); 1018 u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
1019 u64 main_end_blkaddr = main_blkaddr +
1020 (segment_count_main << log_blocks_per_seg);
1021 u64 seg_end_blkaddr = segment0_blkaddr +
1022 (segment_count << log_blocks_per_seg);
1003 1023
1004 if (segment0_blkaddr != cp_blkaddr) { 1024 if (segment0_blkaddr != cp_blkaddr) {
1005 f2fs_msg(sb, KERN_INFO, 1025 f2fs_msg(sb, KERN_INFO,
@@ -1044,22 +1064,45 @@ static inline bool sanity_check_area_boundary(struct super_block *sb,
1044 return true; 1064 return true;
1045 } 1065 }
1046 1066
1047 if (main_blkaddr + (segment_count_main << log_blocks_per_seg) != 1067 if (main_end_blkaddr > seg_end_blkaddr) {
1048 segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
1049 f2fs_msg(sb, KERN_INFO, 1068 f2fs_msg(sb, KERN_INFO,
1050 "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)", 1069 "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
1051 main_blkaddr, 1070 main_blkaddr,
1052 segment0_blkaddr + (segment_count << log_blocks_per_seg), 1071 segment0_blkaddr +
1072 (segment_count << log_blocks_per_seg),
1053 segment_count_main << log_blocks_per_seg); 1073 segment_count_main << log_blocks_per_seg);
1054 return true; 1074 return true;
1075 } else if (main_end_blkaddr < seg_end_blkaddr) {
1076 int err = 0;
1077 char *res;
1078
1079 /* fix in-memory information all the time */
1080 raw_super->segment_count = cpu_to_le32((main_end_blkaddr -
1081 segment0_blkaddr) >> log_blocks_per_seg);
1082
1083 if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) {
1084 res = "internally";
1085 } else {
1086 err = __f2fs_commit_super(bh, NULL);
1087 res = err ? "failed" : "done";
1088 }
1089 f2fs_msg(sb, KERN_INFO,
1090 "Fix alignment : %s, start(%u) end(%u) block(%u)",
1091 res, main_blkaddr,
1092 segment0_blkaddr +
1093 (segment_count << log_blocks_per_seg),
1094 segment_count_main << log_blocks_per_seg);
1095 if (err)
1096 return true;
1055 } 1097 }
1056
1057 return false; 1098 return false;
1058} 1099}
1059 1100
1060static int sanity_check_raw_super(struct super_block *sb, 1101static int sanity_check_raw_super(struct super_block *sb,
1061 struct f2fs_super_block *raw_super) 1102 struct buffer_head *bh)
1062{ 1103{
1104 struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
1105 (bh->b_data + F2FS_SUPER_OFFSET);
1063 unsigned int blocksize; 1106 unsigned int blocksize;
1064 1107
1065 if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { 1108 if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
@@ -1126,7 +1169,7 @@ static int sanity_check_raw_super(struct super_block *sb,
1126 } 1169 }
1127 1170
1128 /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ 1171 /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
1129 if (sanity_check_area_boundary(sb, raw_super)) 1172 if (sanity_check_area_boundary(sb, bh))
1130 return 1; 1173 return 1;
1131 1174
1132 return 0; 1175 return 0;
@@ -1202,7 +1245,7 @@ static int read_raw_super_block(struct super_block *sb,
1202{ 1245{
1203 int block; 1246 int block;
1204 struct buffer_head *bh; 1247 struct buffer_head *bh;
1205 struct f2fs_super_block *super, *buf; 1248 struct f2fs_super_block *super;
1206 int err = 0; 1249 int err = 0;
1207 1250
1208 super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); 1251 super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
@@ -1218,11 +1261,8 @@ static int read_raw_super_block(struct super_block *sb,
1218 continue; 1261 continue;
1219 } 1262 }
1220 1263
1221 buf = (struct f2fs_super_block *)
1222 (bh->b_data + F2FS_SUPER_OFFSET);
1223
1224 /* sanity checking of raw super */ 1264 /* sanity checking of raw super */
1225 if (sanity_check_raw_super(sb, buf)) { 1265 if (sanity_check_raw_super(sb, bh)) {
1226 f2fs_msg(sb, KERN_ERR, 1266 f2fs_msg(sb, KERN_ERR,
1227 "Can't find valid F2FS filesystem in %dth superblock", 1267 "Can't find valid F2FS filesystem in %dth superblock",
1228 block + 1); 1268 block + 1);
@@ -1232,7 +1272,8 @@ static int read_raw_super_block(struct super_block *sb,
1232 } 1272 }
1233 1273
1234 if (!*raw_super) { 1274 if (!*raw_super) {
1235 memcpy(super, buf, sizeof(*super)); 1275 memcpy(super, bh->b_data + F2FS_SUPER_OFFSET,
1276 sizeof(*super));
1236 *valid_super_block = block; 1277 *valid_super_block = block;
1237 *raw_super = super; 1278 *raw_super = super;
1238 } 1279 }
@@ -1252,42 +1293,29 @@ static int read_raw_super_block(struct super_block *sb,
1252 return err; 1293 return err;
1253} 1294}
1254 1295
1255static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block) 1296int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
1256{ 1297{
1257 struct f2fs_super_block *super = F2FS_RAW_SUPER(sbi);
1258 struct buffer_head *bh; 1298 struct buffer_head *bh;
1259 int err; 1299 int err;
1260 1300
1261 bh = sb_getblk(sbi->sb, block); 1301 /* write back-up superblock first */
1302 bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1);
1262 if (!bh) 1303 if (!bh)
1263 return -EIO; 1304 return -EIO;
1264 1305 err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
1265 lock_buffer(bh);
1266 memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
1267 set_buffer_uptodate(bh);
1268 set_buffer_dirty(bh);
1269 unlock_buffer(bh);
1270
1271 /* it's rare case, we can do fua all the time */
1272 err = __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
1273 brelse(bh); 1306 brelse(bh);
1274 1307
1275 return err;
1276}
1277
1278int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
1279{
1280 int err;
1281
1282 /* write back-up superblock first */
1283 err = __f2fs_commit_super(sbi, sbi->valid_super_block ? 0 : 1);
1284
1285 /* if we are in recovery path, skip writing valid superblock */ 1308 /* if we are in recovery path, skip writing valid superblock */
1286 if (recover || err) 1309 if (recover || err)
1287 return err; 1310 return err;
1288 1311
1289 /* write current valid superblock */ 1312 /* write current valid superblock */
1290 return __f2fs_commit_super(sbi, sbi->valid_super_block); 1313 bh = sb_getblk(sbi->sb, sbi->valid_super_block);
1314 if (!bh)
1315 return -EIO;
1316 err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
1317 brelse(bh);
1318 return err;
1291} 1319}
1292 1320
1293static int f2fs_fill_super(struct super_block *sb, void *data, int silent) 1321static int f2fs_fill_super(struct super_block *sb, void *data, int silent)