shithub: lwext4

Download patch

ref: e686e6cd460cc1767c1a6dcf19841d1d0df4bb7b
parent: 10dd1d4f9b5097a5b96523093caeb97181d78c76
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Wed Oct 28 09:54:37 EDT 2015

METADATA_CSUM: inode and block group descriptor checksum verification added

--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -489,76 +489,6 @@
 	return (has_super + ext4_fs_first_bg_block_no(s, bgid));
 }
 
-int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
-				struct ext4_block_group_ref *ref)
-{
-	/* Compute number of descriptors, that fits in one data block */
-	uint32_t dsc_per_block =
-	    ext4_sb_get_block_size(&fs->sb) / ext4_sb_get_desc_size(&fs->sb);
-
-	/* Block group descriptor table starts at the next block after
-	 * superblock */
-	uint64_t block_id =
-	    ext4_fs_get_descriptor_block(&fs->sb, bgid, dsc_per_block);
-
-	uint32_t offset =
-	    (bgid % dsc_per_block) * ext4_sb_get_desc_size(&fs->sb);
-
-	int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
-	if (rc != EOK)
-		return rc;
-
-	ref->block_group = (void *)(ref->block.data + offset);
-	ref->fs = fs;
-	ref->index = bgid;
-	ref->dirty = false;
-
-	if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
-		rc = ext4_fs_init_block_bitmap(ref);
-		if (rc != EOK) {
-			ext4_block_set(fs->bdev, &ref->block);
-			return rc;
-		}
-		ext4_bg_clear_flag(ref->block_group,
-				   EXT4_BLOCK_GROUP_BLOCK_UNINIT);
-
-		ref->dirty = true;
-	}
-
-	if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_INODE_UNINIT)) {
-		rc = ext4_fs_init_inode_bitmap(ref);
-		if (rc != EOK) {
-			ext4_block_set(ref->fs->bdev, &ref->block);
-			return rc;
-		}
-
-		ext4_bg_clear_flag(ref->block_group,
-				   EXT4_BLOCK_GROUP_INODE_UNINIT);
-
-		if (!ext4_bg_has_flag(ref->block_group,
-				      EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
-			rc = ext4_fs_init_inode_table(ref);
-			if (rc != EOK) {
-				ext4_block_set(fs->bdev, &ref->block);
-				return rc;
-			}
-
-			ext4_bg_set_flag(ref->block_group,
-					 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
-		}
-
-		ref->dirty = true;
-	}
-
-	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
@@ -629,6 +559,96 @@
 	return crc;
 }
 
+#if CONFIG_META_CSUM_ENABLE
+static bool ext4_fs_verify_bg_csum(struct ext4_sblock *sb,
+				   uint32_t bgid,
+				   struct ext4_bgroup *bg)
+{
+	if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
+		return true;
+
+	return ext4_fs_bg_checksum(sb,
+				   bgid,
+				   bg) ==
+		to_le16(bg->checksum);
+}
+#else
+#define ext4_fs_verify_bg_csum(...) true
+#endif
+
+int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
+				struct ext4_block_group_ref *ref)
+{
+	/* Compute number of descriptors, that fits in one data block */
+	uint32_t dsc_per_block =
+	    ext4_sb_get_block_size(&fs->sb) / ext4_sb_get_desc_size(&fs->sb);
+
+	/* Block group descriptor table starts at the next block after
+	 * superblock */
+	uint64_t block_id =
+	    ext4_fs_get_descriptor_block(&fs->sb, bgid, dsc_per_block);
+
+	uint32_t offset =
+	    (bgid % dsc_per_block) * ext4_sb_get_desc_size(&fs->sb);
+
+	int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+	if (rc != EOK)
+		return rc;
+
+	ref->block_group = (void *)(ref->block.data + offset);
+	ref->fs = fs;
+	ref->index = bgid;
+	ref->dirty = false;
+
+	if (!ext4_fs_verify_bg_csum(&fs->sb,
+				    bgid,
+				    ref->block_group)) {
+		ext4_dbg(DEBUG_FS,
+			 DBG_WARN "Block group descriptor checksum failed."
+			 "Block group index: %" PRIu32"\n",
+			 bgid);
+	}
+
+	if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
+		rc = ext4_fs_init_block_bitmap(ref);
+		if (rc != EOK) {
+			ext4_block_set(fs->bdev, &ref->block);
+			return rc;
+		}
+		ext4_bg_clear_flag(ref->block_group,
+				   EXT4_BLOCK_GROUP_BLOCK_UNINIT);
+
+		ref->dirty = true;
+	}
+
+	if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_INODE_UNINIT)) {
+		rc = ext4_fs_init_inode_bitmap(ref);
+		if (rc != EOK) {
+			ext4_block_set(ref->fs->bdev, &ref->block);
+			return rc;
+		}
+
+		ext4_bg_clear_flag(ref->block_group,
+				   EXT4_BLOCK_GROUP_INODE_UNINIT);
+
+		if (!ext4_bg_has_flag(ref->block_group,
+				      EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+			rc = ext4_fs_init_inode_table(ref);
+			if (rc != EOK) {
+				ext4_block_set(fs->bdev, &ref->block);
+				return rc;
+			}
+
+			ext4_bg_set_flag(ref->block_group,
+					 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
+		}
+
+		ref->dirty = true;
+	}
+
+	return EOK;
+}
+
 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
 {
 	/* Check if reference modified */
@@ -697,6 +717,20 @@
 				ext4_fs_inode_checksum(inode_ref));
 }
 
+#if CONFIG_META_CSUM_ENABLE
+static bool ext4_fs_verify_inode_csum(struct ext4_inode_ref *inode_ref)
+{
+	struct ext4_sblock *sb = &inode_ref->fs->sb;
+	if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
+		return true;
+
+	return ext4_inode_get_checksum(sb, inode_ref->inode) ==
+		ext4_fs_inode_checksum(inode_ref);
+}
+#else
+#define ext4_fs_verify_inode_csum(...) true
+#endif
+
 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
 			  struct ext4_inode_ref *ref)
 {
@@ -751,6 +785,13 @@
 	ref->index = index + 1;
 	ref->fs = fs;
 	ref->dirty = false;
+
+	if (!ext4_fs_verify_inode_csum(ref)) {
+		ext4_dbg(DEBUG_FS,
+			DBG_WARN "Inode checksum failed."
+			"Inode: %" PRIu32"\n",
+			ref->index);
+	}
 
 	return EOK;
 }