|
@@ -1952,43 +1952,69 @@ failed:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-__le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
|
|
|
- struct ext4_group_desc *gdp)
|
|
|
+static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
|
|
|
+ struct ext4_group_desc *gdp)
|
|
|
{
|
|
|
+ int offset;
|
|
|
__u16 crc = 0;
|
|
|
+ __le32 le_group = cpu_to_le32(block_group);
|
|
|
|
|
|
- if (sbi->s_es->s_feature_ro_compat &
|
|
|
- cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
|
|
|
- int offset = offsetof(struct ext4_group_desc, bg_checksum);
|
|
|
- __le32 le_group = cpu_to_le32(block_group);
|
|
|
-
|
|
|
- crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
|
|
|
- crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
|
|
|
- crc = crc16(crc, (__u8 *)gdp, offset);
|
|
|
- offset += sizeof(gdp->bg_checksum); /* skip checksum */
|
|
|
- /* for checksum of struct ext4_group_desc do the rest...*/
|
|
|
- if ((sbi->s_es->s_feature_incompat &
|
|
|
- cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
|
|
|
- offset < le16_to_cpu(sbi->s_es->s_desc_size))
|
|
|
- crc = crc16(crc, (__u8 *)gdp + offset,
|
|
|
- le16_to_cpu(sbi->s_es->s_desc_size) -
|
|
|
- offset);
|
|
|
+ if ((sbi->s_es->s_feature_ro_compat &
|
|
|
+ cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))) {
|
|
|
+ /* Use new metadata_csum algorithm */
|
|
|
+ __u16 old_csum;
|
|
|
+ __u32 csum32;
|
|
|
+
|
|
|
+ old_csum = gdp->bg_checksum;
|
|
|
+ gdp->bg_checksum = 0;
|
|
|
+ csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
|
|
|
+ sizeof(le_group));
|
|
|
+ csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp,
|
|
|
+ sbi->s_desc_size);
|
|
|
+ gdp->bg_checksum = old_csum;
|
|
|
+
|
|
|
+ crc = csum32 & 0xFFFF;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
+ /* old crc16 code */
|
|
|
+ offset = offsetof(struct ext4_group_desc, bg_checksum);
|
|
|
+
|
|
|
+ crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
|
|
|
+ crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
|
|
|
+ crc = crc16(crc, (__u8 *)gdp, offset);
|
|
|
+ offset += sizeof(gdp->bg_checksum); /* skip checksum */
|
|
|
+ /* for checksum of struct ext4_group_desc do the rest...*/
|
|
|
+ if ((sbi->s_es->s_feature_incompat &
|
|
|
+ cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
|
|
|
+ offset < le16_to_cpu(sbi->s_es->s_desc_size))
|
|
|
+ crc = crc16(crc, (__u8 *)gdp + offset,
|
|
|
+ le16_to_cpu(sbi->s_es->s_desc_size) -
|
|
|
+ offset);
|
|
|
+
|
|
|
+out:
|
|
|
return cpu_to_le16(crc);
|
|
|
}
|
|
|
|
|
|
-int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
|
|
|
+int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
|
|
|
struct ext4_group_desc *gdp)
|
|
|
{
|
|
|
- if ((sbi->s_es->s_feature_ro_compat &
|
|
|
- cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
|
|
|
- (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
|
|
|
+ if (ext4_has_group_desc_csum(sb) &&
|
|
|
+ (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb),
|
|
|
+ block_group, gdp)))
|
|
|
return 0;
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
|
|
|
+ struct ext4_group_desc *gdp)
|
|
|
+{
|
|
|
+ if (!ext4_has_group_desc_csum(sb))
|
|
|
+ return;
|
|
|
+ gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp);
|
|
|
+}
|
|
|
+
|
|
|
/* Called at mount-time, super-block is locked */
|
|
|
static int ext4_check_descriptors(struct super_block *sb,
|
|
|
ext4_group_t *first_not_zeroed)
|
|
@@ -2043,7 +2069,7 @@ static int ext4_check_descriptors(struct super_block *sb,
|
|
|
return 0;
|
|
|
}
|
|
|
ext4_lock_group(sb, i);
|
|
|
- if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
|
|
|
+ if (!ext4_group_desc_csum_verify(sb, i, gdp)) {
|
|
|
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
|
|
|
"Checksum for group %u failed (%u!=%u)",
|
|
|
i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
|
|
@@ -3069,6 +3095,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
goto cantfind_ext4;
|
|
|
sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
|
|
|
|
|
|
+ /* Warn if metadata_csum and gdt_csum are both set. */
|
|
|
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
|
|
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
|
|
|
+ EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
|
|
|
+ ext4_warning(sb, KERN_INFO "metadata_csum and uninit_bg are "
|
|
|
+ "redundant flags; please run fsck.");
|
|
|
+
|
|
|
/* Check for a known checksum algorithm */
|
|
|
if (!ext4_verify_csum_type(sb, es)) {
|
|
|
ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
|
|
@@ -4400,7 +4433,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|
|
struct ext4_group_desc *gdp =
|
|
|
ext4_get_group_desc(sb, g, NULL);
|
|
|
|
|
|
- if (!ext4_group_desc_csum_verify(sbi, g, gdp)) {
|
|
|
+ if (!ext4_group_desc_csum_verify(sb, g, gdp)) {
|
|
|
ext4_msg(sb, KERN_ERR,
|
|
|
"ext4_remount: Checksum for group %u failed (%u!=%u)",
|
|
|
g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)),
|