diff options
author | Fedor Uporov <fsu@FreeBSD.org> | 2018-05-13 19:29:35 +0000 |
---|---|---|
committer | Fedor Uporov <fsu@FreeBSD.org> | 2018-05-13 19:29:35 +0000 |
commit | c4aa9a026d9fd685bb417ae172875ce6d1e01e1b (patch) | |
tree | 300da828b27342311937fb805e51b16d07838531 | |
parent | e06e5241a067e3a3bc4756a3bb2674b55d764493 (diff) | |
download | src-c4aa9a026d9fd685bb417ae172875ce6d1e01e1b.tar.gz src-c4aa9a026d9fd685bb417ae172875ce6d1e01e1b.zip |
Fix on-disk inode checksum calculation logic.
Reviewed by: pfg
MFC after: 3 months
Differential Revision: https://reviews.freebsd.org/D15395
Notes
Notes:
svn path=/head/; revision=333585
-rw-r--r-- | sys/fs/ext2fs/ext2_csum.c | 62 | ||||
-rw-r--r-- | sys/fs/ext2fs/ext2_inode_cnv.c | 9 |
2 files changed, 41 insertions, 30 deletions
diff --git a/sys/fs/ext2fs/ext2_csum.c b/sys/fs/ext2fs/ext2_csum.c index 3682b7acd8be..881a7b16dfc0 100644 --- a/sys/fs/ext2fs/ext2_csum.c +++ b/sys/fs/ext2fs/ext2_csum.c @@ -535,28 +535,41 @@ static uint32_t ext2_ei_csum(struct inode *ip, struct ext2fs_dinode *ei) { struct m_ext2fs *fs; - uint16_t old_hi; - uint32_t inum, gen, crc; + uint32_t inode_csum_seed, inum, gen, crc; + uint16_t dummy_csum = 0; + unsigned int offset, csum_size; fs = ip->i_e2fs; - - ei->e2di_chksum_lo = 0; - if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE && - ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { - old_hi = ei->e2di_chksum_hi; - ei->e2di_chksum_hi = 0; - } - + offset = offsetof(struct ext2fs_dinode, e2di_chksum_lo); + csum_size = sizeof(dummy_csum); inum = ip->i_number; gen = ip->i_gen; + crc = calculate_crc32c(fs->e2fs_csum_seed, + (uint8_t *)&inum, sizeof(inum)); + inode_csum_seed = calculate_crc32c(crc, + (uint8_t *)&gen, sizeof(gen)); + + crc = calculate_crc32c(inode_csum_seed, (uint8_t *)ei, offset); + crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, csum_size); + offset += csum_size; + crc = calculate_crc32c(crc, (uint8_t *)ei + offset, + E2FS_REV0_INODE_SIZE - offset); + + if (EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE) { + offset = offsetof(struct ext2fs_dinode, e2di_chksum_hi); + crc = calculate_crc32c(crc, (uint8_t *)ei + + E2FS_REV0_INODE_SIZE, offset - E2FS_REV0_INODE_SIZE); + + if ((EXT2_INODE_SIZE(ip->i_e2fs) > E2FS_REV0_INODE_SIZE && + ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) { + crc = calculate_crc32c(crc, (uint8_t *)&dummy_csum, + csum_size); + offset += csum_size; + } - crc = calculate_crc32c(fs->e2fs_csum_seed, (uint8_t *)&inum, sizeof(inum)); - crc = calculate_crc32c(crc, (uint8_t *)&gen, sizeof(gen)); - crc = calculate_crc32c(crc, (uint8_t *)ei, fs->e2fs->e2fs_inode_size); - - if ((EXT2_INODE_SIZE(fs) > E2FS_REV0_INODE_SIZE && - ei->e2di_extra_isize >= EXT2_INODE_CSUM_HI_EXTRA_END)) - ei->e2di_chksum_hi = old_hi; + crc = calculate_crc32c(crc, (uint8_t *)ei + offset, + EXT2_INODE_SIZE(fs) - offset); + } return (crc); } @@ -573,10 +586,6 @@ ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei) if (!EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) return (0); - /* Check case, when dinode was not initialized */ - if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode))) - return (0); - provided = ei->e2di_chksum_lo; calculated = ext2_ei_csum(ip, ei); @@ -587,8 +596,17 @@ ext2_ei_csum_verify(struct inode *ip, struct ext2fs_dinode *ei) } else calculated &= 0xFFFF; - if (provided != calculated) + if (provided != calculated) { + /* + * If it is first time used dinode, + * it is expected that it will be zeroed + * and we will not return checksum error in this case. + */ + if (!memcmp(ei, &ei_zero, sizeof(struct ext2fs_dinode))) + return (0); + return (EIO); + } return (0); } diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c index 4e307f615c08..558de7b05605 100644 --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -92,10 +92,7 @@ ext2_print_inode(struct inode *in) int ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip) { - struct m_ext2fs *fs; - const static struct ext2fs_dinode ei_zero; - fs = ip->i_e2fs; ip->i_nlink = ei->e2di_nlink; /* * Godmar thinks - if the link count is zero, then the inode is @@ -139,11 +136,7 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip) memcpy(ip->i_data, ei->e2di_blocks, sizeof(ei->e2di_blocks)); - if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM) && - memcmp(ei, &ei_zero, EXT2_INODE_SIZE(fs))) - return (ext2_ei_csum_verify(ip, ei)); - - return (0); + return (ext2_ei_csum_verify(ip, ei)); } /* |