ext4: make block group checksums use metadata_csum algorithm
metadata_csum supersedes uninit_bg. Convert the ROCOMPAT uninit_bg flag check to a helper function that covers both, and make the checksum calculation algorithm use either crc16 or the metadata_csum chosen algorithm depending on which flag is set. Print a warning if we try to mount a filesystem with both feature flags set. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:

committed by
Theodore Ts'o

parent
cc8e94fd12
commit
feb0ab32a5
@@ -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);
|
||||
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;
|
||||
|
||||
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);
|
||||
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)),
|
||||
|
Reference in New Issue
Block a user