aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFedor Uporov <fsu@FreeBSD.org>2018-05-13 19:29:35 +0000
committerFedor Uporov <fsu@FreeBSD.org>2018-05-13 19:29:35 +0000
commitc4aa9a026d9fd685bb417ae172875ce6d1e01e1b (patch)
tree300da828b27342311937fb805e51b16d07838531
parente06e5241a067e3a3bc4756a3bb2674b55d764493 (diff)
downloadsrc-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.c62
-rw-r--r--sys/fs/ext2fs/ext2_inode_cnv.c9
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));
}
/*