ext4: avoid modifying checksum fields directly during checksum verification
We temporally change checksum fields in buffers of some types of metadata into '0' for verifying the checksum values. By doing this without locking the buffer, some metadata's checksums, which are being committed or written back to the storage, could be damaged. In our test, several metadata blocks were found with damaged metadata checksum value during recovery process. When we only verify the checksum value, we have to avoid modifying checksum fields directly. Signed-off-by: Daeho Jeong <daeho.jeong@samsung.com> Signed-off-by: Youngjin Gil <youngjin.gil@samsung.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:

committed by
Theodore Ts'o

parent
f70749ca42
commit
b47820edd1
@@ -51,26 +51,32 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
|
||||
struct ext4_inode_info *ei)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
__u16 csum_lo;
|
||||
__u16 csum_hi = 0;
|
||||
__u32 csum;
|
||||
__u16 dummy_csum = 0;
|
||||
int offset = offsetof(struct ext4_inode, i_checksum_lo);
|
||||
unsigned int csum_size = sizeof(dummy_csum);
|
||||
|
||||
csum_lo = le16_to_cpu(raw->i_checksum_lo);
|
||||
raw->i_checksum_lo = 0;
|
||||
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
||||
EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
|
||||
csum_hi = le16_to_cpu(raw->i_checksum_hi);
|
||||
raw->i_checksum_hi = 0;
|
||||
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw, offset);
|
||||
csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, csum_size);
|
||||
offset += csum_size;
|
||||
csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
|
||||
EXT4_GOOD_OLD_INODE_SIZE - offset);
|
||||
|
||||
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
|
||||
offset = offsetof(struct ext4_inode, i_checksum_hi);
|
||||
csum = ext4_chksum(sbi, csum, (__u8 *)raw +
|
||||
EXT4_GOOD_OLD_INODE_SIZE,
|
||||
offset - EXT4_GOOD_OLD_INODE_SIZE);
|
||||
if (EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
|
||||
csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
|
||||
csum_size);
|
||||
offset += csum_size;
|
||||
csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
|
||||
EXT4_INODE_SIZE(inode->i_sb) -
|
||||
offset);
|
||||
}
|
||||
}
|
||||
|
||||
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
|
||||
EXT4_INODE_SIZE(inode->i_sb));
|
||||
|
||||
raw->i_checksum_lo = cpu_to_le16(csum_lo);
|
||||
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
||||
EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
|
||||
raw->i_checksum_hi = cpu_to_le16(csum_hi);
|
||||
|
||||
return csum;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user