diff options
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 81 |
1 files changed, 57 insertions, 24 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f80c7e612829..c18c5968cd96 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -1952,43 +1952,69 @@ failed: | |||
1952 | return 0; | 1952 | return 0; |
1953 | } | 1953 | } |
1954 | 1954 | ||
1955 | __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, | 1955 | static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, |
1956 | struct ext4_group_desc *gdp) | 1956 | struct ext4_group_desc *gdp) |
1957 | { | 1957 | { |
1958 | int offset; | ||
1958 | __u16 crc = 0; | 1959 | __u16 crc = 0; |
1960 | __le32 le_group = cpu_to_le32(block_group); | ||
1959 | 1961 | ||
1960 | if (sbi->s_es->s_feature_ro_compat & | 1962 | if ((sbi->s_es->s_feature_ro_compat & |
1961 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { | 1963 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))) { |
1962 | int offset = offsetof(struct ext4_group_desc, bg_checksum); | 1964 | /* Use new metadata_csum algorithm */ |
1963 | __le32 le_group = cpu_to_le32(block_group); | 1965 | __u16 old_csum; |
1964 | 1966 | __u32 csum32; | |
1965 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | 1967 | |
1966 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | 1968 | old_csum = gdp->bg_checksum; |
1967 | crc = crc16(crc, (__u8 *)gdp, offset); | 1969 | gdp->bg_checksum = 0; |
1968 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | 1970 | csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group, |
1969 | /* for checksum of struct ext4_group_desc do the rest...*/ | 1971 | sizeof(le_group)); |
1970 | if ((sbi->s_es->s_feature_incompat & | 1972 | csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, |
1971 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | 1973 | sbi->s_desc_size); |
1972 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | 1974 | gdp->bg_checksum = old_csum; |
1973 | crc = crc16(crc, (__u8 *)gdp + offset, | 1975 | |
1974 | le16_to_cpu(sbi->s_es->s_desc_size) - | 1976 | crc = csum32 & 0xFFFF; |
1975 | offset); | 1977 | goto out; |
1976 | } | 1978 | } |
1977 | 1979 | ||
1980 | /* old crc16 code */ | ||
1981 | offset = offsetof(struct ext4_group_desc, bg_checksum); | ||
1982 | |||
1983 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | ||
1984 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | ||
1985 | crc = crc16(crc, (__u8 *)gdp, offset); | ||
1986 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | ||
1987 | /* for checksum of struct ext4_group_desc do the rest...*/ | ||
1988 | if ((sbi->s_es->s_feature_incompat & | ||
1989 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | ||
1990 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | ||
1991 | crc = crc16(crc, (__u8 *)gdp + offset, | ||
1992 | le16_to_cpu(sbi->s_es->s_desc_size) - | ||
1993 | offset); | ||
1994 | |||
1995 | out: | ||
1978 | return cpu_to_le16(crc); | 1996 | return cpu_to_le16(crc); |
1979 | } | 1997 | } |
1980 | 1998 | ||
1981 | int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, | 1999 | int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group, |
1982 | struct ext4_group_desc *gdp) | 2000 | struct ext4_group_desc *gdp) |
1983 | { | 2001 | { |
1984 | if ((sbi->s_es->s_feature_ro_compat & | 2002 | if (ext4_has_group_desc_csum(sb) && |
1985 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) && | 2003 | (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb), |
1986 | (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp))) | 2004 | block_group, gdp))) |
1987 | return 0; | 2005 | return 0; |
1988 | 2006 | ||
1989 | return 1; | 2007 | return 1; |
1990 | } | 2008 | } |
1991 | 2009 | ||
2010 | void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group, | ||
2011 | struct ext4_group_desc *gdp) | ||
2012 | { | ||
2013 | if (!ext4_has_group_desc_csum(sb)) | ||
2014 | return; | ||
2015 | gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp); | ||
2016 | } | ||
2017 | |||
1992 | /* Called at mount-time, super-block is locked */ | 2018 | /* Called at mount-time, super-block is locked */ |
1993 | static int ext4_check_descriptors(struct super_block *sb, | 2019 | static int ext4_check_descriptors(struct super_block *sb, |
1994 | ext4_group_t *first_not_zeroed) | 2020 | ext4_group_t *first_not_zeroed) |
@@ -2043,7 +2069,7 @@ static int ext4_check_descriptors(struct super_block *sb, | |||
2043 | return 0; | 2069 | return 0; |
2044 | } | 2070 | } |
2045 | ext4_lock_group(sb, i); | 2071 | ext4_lock_group(sb, i); |
2046 | if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { | 2072 | if (!ext4_group_desc_csum_verify(sb, i, gdp)) { |
2047 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " | 2073 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " |
2048 | "Checksum for group %u failed (%u!=%u)", | 2074 | "Checksum for group %u failed (%u!=%u)", |
2049 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, | 2075 | 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) | |||
3069 | goto cantfind_ext4; | 3095 | goto cantfind_ext4; |
3070 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); | 3096 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); |
3071 | 3097 | ||
3098 | /* Warn if metadata_csum and gdt_csum are both set. */ | ||
3099 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3100 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && | ||
3101 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) | ||
3102 | ext4_warning(sb, KERN_INFO "metadata_csum and uninit_bg are " | ||
3103 | "redundant flags; please run fsck."); | ||
3104 | |||
3072 | /* Check for a known checksum algorithm */ | 3105 | /* Check for a known checksum algorithm */ |
3073 | if (!ext4_verify_csum_type(sb, es)) { | 3106 | if (!ext4_verify_csum_type(sb, es)) { |
3074 | ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " | 3107 | 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) | |||
4400 | struct ext4_group_desc *gdp = | 4433 | struct ext4_group_desc *gdp = |
4401 | ext4_get_group_desc(sb, g, NULL); | 4434 | ext4_get_group_desc(sb, g, NULL); |
4402 | 4435 | ||
4403 | if (!ext4_group_desc_csum_verify(sbi, g, gdp)) { | 4436 | if (!ext4_group_desc_csum_verify(sb, g, gdp)) { |
4404 | ext4_msg(sb, KERN_ERR, | 4437 | ext4_msg(sb, KERN_ERR, |
4405 | "ext4_remount: Checksum for group %u failed (%u!=%u)", | 4438 | "ext4_remount: Checksum for group %u failed (%u!=%u)", |
4406 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), | 4439 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), |