| From 69517cdd56b1c36951a36ff1c09e3ed657b3db1b Mon Sep 17 00:00:00 2001 |
| From: Icenowy Zheng <icenowy@aosc.io> |
| Date: Thu, 25 Jul 2019 11:08:52 +0800 |
| Subject: [PATCH] f2fs: use EINVAL for superblock with invalid magic |
| |
| commit 38fb6d0ea34299d97b031ed64fe994158b6f8eb3 upstream. |
| |
| The kernel mount_block_root() function expects -EACESS or -EINVAL for a |
| unmountable filesystem when trying to mount the root with different |
| filesystem types. |
| |
| However, in 5.3-rc1 the behavior when F2FS code cannot find valid block |
| changed to return -EFSCORRUPTED(-EUCLEAN), and this error code makes |
| mount_block_root() fail when trying to probe F2FS. |
| |
| When the magic number of the superblock mismatches, it has a high |
| probability that it's just not a F2FS. In this case return -EINVAL seems |
| to be a better result, and this return value can make mount_block_root() |
| probing work again. |
| |
| Return -EINVAL when the superblock has magic mismatch, -EFSCORRUPTED in |
| other cases (the magic matches but the superblock cannot be recognized). |
| |
| Fixes: 10f966bbf521 ("f2fs: use generic EFSBADCRC/EFSCORRUPTED") |
| Signed-off-by: Icenowy Zheng <icenowy@aosc.io> |
| Reviewed-by: Chao Yu <yuchao0@huawei.com> |
| Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c |
| index 01038aff5d8e..0e7ea25d6f4d 100644 |
| --- a/fs/f2fs/super.c |
| +++ b/fs/f2fs/super.c |
| @@ -2444,6 +2444,12 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| size_t crc_offset = 0; |
| __u32 crc = 0; |
| |
| + if (le32_to_cpu(raw_super->magic) != F2FS_SUPER_MAGIC) { |
| + f2fs_msg(sb, KERN_INFO, "Magic Mismatch, valid(0x%x) - read(0x%x)", |
| + F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic)); |
| + return -EINVAL; |
| + } |
| + |
| /* Check checksum_offset and crc in superblock */ |
| if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_SB_CHKSUM)) { |
| crc_offset = le32_to_cpu(raw_super->checksum_offset); |
| @@ -2452,29 +2458,22 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid SB checksum offset: %zu", |
| crc_offset); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| crc = le32_to_cpu(raw_super->crc); |
| if (!f2fs_crc_valid(sbi, crc, raw_super, crc_offset)) { |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid SB checksum value: %u", crc); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| } |
| |
| - if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { |
| - f2fs_msg(sb, KERN_INFO, |
| - "Magic Mismatch, valid(0x%x) - read(0x%x)", |
| - F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic)); |
| - return 1; |
| - } |
| - |
| /* Currently, support only 4KB page cache size */ |
| if (F2FS_BLKSIZE != PAGE_SIZE) { |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid page_cache_size (%lu), supports only 4KB", |
| PAGE_SIZE); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| /* Currently, support only 4KB block size */ |
| @@ -2483,7 +2482,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid blocksize (%u), supports only 4KB", |
| blocksize); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| /* check log blocks per segment */ |
| @@ -2491,7 +2490,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid log blocks per segment (%u)", |
| le32_to_cpu(raw_super->log_blocks_per_seg)); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| /* Currently, support 512/1024/2048/4096 bytes sector size */ |
| @@ -2501,7 +2500,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| F2FS_MIN_LOG_SECTOR_SIZE) { |
| f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize (%u)", |
| le32_to_cpu(raw_super->log_sectorsize)); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| if (le32_to_cpu(raw_super->log_sectors_per_block) + |
| le32_to_cpu(raw_super->log_sectorsize) != |
| @@ -2510,7 +2509,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| "Invalid log sectors per block(%u) log sectorsize(%u)", |
| le32_to_cpu(raw_super->log_sectors_per_block), |
| le32_to_cpu(raw_super->log_sectorsize)); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| segment_count = le32_to_cpu(raw_super->segment_count); |
| @@ -2526,7 +2525,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid segment count (%u)", |
| segment_count); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| if (total_sections > segment_count || |
| @@ -2535,28 +2534,28 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| f2fs_msg(sb, KERN_INFO, |
| "Invalid segment/section count (%u, %u x %u)", |
| segment_count, total_sections, segs_per_sec); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| if ((segment_count / segs_per_sec) < total_sections) { |
| f2fs_msg(sb, KERN_INFO, |
| "Small segment_count (%u < %u * %u)", |
| segment_count, segs_per_sec, total_sections); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) { |
| f2fs_msg(sb, KERN_INFO, |
| "Wrong segment_count / block_count (%u > %llu)", |
| segment_count, le64_to_cpu(raw_super->block_count)); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| if (secs_per_zone > total_sections || !secs_per_zone) { |
| f2fs_msg(sb, KERN_INFO, |
| "Wrong secs_per_zone / total_sections (%u, %u)", |
| secs_per_zone, total_sections); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION || |
| raw_super->hot_ext_count > F2FS_MAX_EXTENSION || |
| @@ -2567,7 +2566,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| le32_to_cpu(raw_super->extension_count), |
| raw_super->hot_ext_count, |
| F2FS_MAX_EXTENSION); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| if (le32_to_cpu(raw_super->cp_payload) > |
| @@ -2576,7 +2575,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| "Insane cp_payload (%u > %u)", |
| le32_to_cpu(raw_super->cp_payload), |
| blocks_per_seg - F2FS_CP_PACKS); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| /* check reserved ino info */ |
| @@ -2588,12 +2587,12 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, |
| le32_to_cpu(raw_super->node_ino), |
| le32_to_cpu(raw_super->meta_ino), |
| le32_to_cpu(raw_super->root_ino)); |
| - return 1; |
| + return -EFSCORRUPTED; |
| } |
| |
| /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ |
| if (sanity_check_area_boundary(sbi, bh)) |
| - return 1; |
| + return -EFSCORRUPTED; |
| |
| return 0; |
| } |
| @@ -2918,11 +2917,11 @@ static int read_raw_super_block(struct f2fs_sb_info *sbi, |
| } |
| |
| /* sanity checking of raw super */ |
| - if (sanity_check_raw_super(sbi, bh)) { |
| + err = sanity_check_raw_super(sbi, bh); |
| + if (err) { |
| f2fs_msg(sb, KERN_ERR, |
| "Can't find valid F2FS filesystem in %dth superblock", |
| block + 1); |
| - err = -EFSCORRUPTED; |
| brelse(bh); |
| continue; |
| } |
| -- |
| 2.7.4 |
| |