shithub: lwext4

Download patch

ref: 76ccc5426eab8185b7e0bf43a35ebb7bcedda79c
parent: 1de45d8f0584b97a29b7e2655998891877eba6c6
author: ngkaho1234 <[email protected]>
date: Sat Oct 24 17:08:49 EDT 2015

METADATA_CSUM: inode added.

--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -546,6 +546,12 @@
 	return EOK;
 }
 
+/*
+ * BIG FAT NOTES:
+ *       Currently we do not verify the checksum of block_group_desc
+ *       and inode.
+ */
+
 /**@brief  Compute checksum of block group descriptor.
  * @param sb   Superblock
  * @param bgid Index of block group in the filesystem
@@ -633,10 +639,53 @@
 	return ext4_block_set(ref->fs->bdev, &ref->block);
 }
 
-/*
- * BIG FAT NOTES:
- *       Currently we do not verify the checksum of block_group_desc.
- */
+static uint32_t ext4_fs_inode_checksum(struct ext4_inode_ref *inode_ref)
+{
+	uint32_t checksum = 0;
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+	uint16_t inode_size = ext4_get16(sb, inode_size);
+
+	if (ext4_sb_has_feature_read_only(sb,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+		uint32_t orig_checksum;
+
+		uint32_t ino_index = to_le32(inode_ref->index);
+		uint32_t ino_gen =
+			to_le32(ext4_inode_get_generation(inode_ref->inode));
+
+		/* Preparation: temporarily set bg checksum to 0 */
+		orig_checksum = ext4_inode_get_checksum(sb, inode_ref->inode);
+		ext4_inode_set_checksum(sb, inode_ref->inode, 0);
+
+		/* First calculate crc32 checksum against fs uuid */
+		checksum = ext4_crc32c(~0, sb->uuid, sizeof(sb->uuid));
+		/* Then calculate crc32 checksum against inode number
+		 * and inode generation */
+		checksum = ext4_crc32c(checksum, &ino_index,
+				     sizeof(ino_index));
+		checksum = ext4_crc32c(checksum, &ino_gen,
+				     sizeof(ino_gen));
+		/* Finally calculate crc32 checksum against 
+		 * the entire inode */
+		checksum = ext4_crc32c(checksum, inode_ref->inode,
+				inode_size);
+		ext4_inode_set_checksum(sb, inode_ref->inode,
+				orig_checksum);
+	}
+	return checksum;
+}
+
+static void ext4_fs_set_inode_checksum(struct ext4_inode_ref *inode_ref)
+{
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+	if (!ext4_sb_has_feature_read_only(sb,
+				EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+		return;
+
+	ext4_inode_set_checksum(sb, inode_ref->inode,
+				ext4_fs_inode_checksum(inode_ref));
+}
+
 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
 			  struct ext4_inode_ref *ref)
 {
@@ -700,6 +749,7 @@
 	/* Check if reference modified */
 	if (ref->dirty) {
 		/* Mark block dirty for writing changes to physical device */
+		ext4_fs_set_inode_checksum(ref);
 		ref->block.dirty = true;
 	}
 
--- a/lwext4/ext4_inode.c
+++ b/lwext4/ext4_inode.c
@@ -108,6 +108,31 @@
 	inode->size_hi = to_le32(size >> 32);
 }
 
+uint32_t
+ext4_inode_get_checksum(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+	uint16_t inode_size = ext4_get16(sb, inode_size);
+	uint32_t v = to_le16(inode->osd2.linux2.checksum_lo);
+
+	if (inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+		v |= ((uint32_t)to_le16(inode->checksum_hi)) << 16;
+
+	return v;
+}
+
+void
+ext4_inode_set_checksum(struct ext4_sblock *sb, struct ext4_inode *inode,
+			uint32_t checksum)
+{
+	uint16_t inode_size = ext4_get16(sb, inode_size);
+	inode->osd2.linux2.checksum_lo =
+		to_le16((checksum << 16) >> 16);
+
+	if (inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+		inode->checksum_hi = to_le16(checksum >> 16);
+
+}
+
 uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)
 {
 	return to_le32(inode->access_time);
--- a/lwext4/ext4_inode.h
+++ b/lwext4/ext4_inode.h
@@ -280,6 +280,21 @@
  */
 void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
 
+/**@brief Get inode checksum(crc32)
+ * @param sb    Superblock
+ * @param inode I-node to get checksum value from
+ */
+uint32_t
+ext4_inode_get_checksum(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+/**@brief Get inode checksum(crc32)
+ * @param sb    Superblock
+ * @param inode I-node to get checksum value from
+ */
+void
+ext4_inode_set_checksum(struct ext4_sblock *sb, struct ext4_inode *inode,
+			uint32_t checksum);
+
 /**@brief Check if i-node can be truncated.
  * @param sb    Superblock
  * @param inode I-node to check
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -393,7 +393,8 @@
 			uint16_t file_acl_high;
 			uint16_t uid_high;
 			uint16_t gid_high;
-			uint32_t reserved2;
+			uint16_t checksum_lo; /* crc32c(uuid+inum+inode) LE */
+			uint16_t reserved2;
 		} linux2;
 		struct {
 			uint16_t reserved1;
@@ -405,7 +406,7 @@
 	} __attribute__((packed)) osd2;
 
 	uint16_t extra_isize;
-	uint16_t pad1;
+	uint16_t checksum_hi;	/* crc32c(uuid+inum+inode) BE */
 	uint32_t ctime_extra; /* Extra change time (nsec << 2 | epoch) */
 	uint32_t mtime_extra; /* Extra Modification time (nsec << 2 | epoch) */
 	uint32_t atime_extra; /* Extra Access time (nsec << 2 | epoch) */