ext4_extent_full.c: print warning messages when extent block checksum verification...
[lwext4.git] / lwext4 / ext4_fs.c
index 0e7335bfe403b9f27ffb85a8ee97e4806c187ebc..7b2d40455dfc26b6eaf8f3fcee044105553fd06d 100644 (file)
@@ -300,8 +300,7 @@ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
            ext4_sb_get_desc_size(&bg_ref->fs->sb);
 
        bool flex_bg =
-               ext4_sb_has_feature_incompatible(&bg_ref->fs->sb,
-                                                EXT4_FINCOM_FLEX_BG);
+               ext4_sb_feature_incom(&bg_ref->fs->sb, EXT4_FINCOM_FLEX_BG);
 
        uint32_t inode_table_bcnt = inodes_per_group * inode_size / block_size;
 
@@ -314,8 +313,7 @@ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
        memset(block_bitmap.data, 0, block_size);
 
        bit_max = ext4_sb_is_super_in_bg(&bg_ref->fs->sb, bg_ref->index);
-       if (!ext4_sb_has_feature_incompatible(&bg_ref->fs->sb,
-                                             EXT4_FINCOM_META_BG) ||
+       if (!ext4_sb_feature_incom(&bg_ref->fs->sb, EXT4_FINCOM_META_BG) ||
                        bg_ref->index < ext4_sb_first_meta_bg(&bg_ref->fs->sb) *
                        dsc_per_block) {
                if (bit_max) {
@@ -481,8 +479,7 @@ static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
        dsc_id = bgid / dsc_per_block;
        first_meta_bg = ext4_sb_first_meta_bg(s);
 
-       if (!ext4_sb_has_feature_incompatible(s,
-                                             EXT4_FINCOM_META_BG) ||
+       if (!ext4_sb_feature_incom(s, EXT4_FINCOM_META_BG) ||
            dsc_id < first_meta_bg)
                return ext4_get32(s, first_data_block) + dsc_id + 1;
 
@@ -492,6 +489,93 @@ static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
        return (has_super + ext4_fs_first_bg_block_no(s, bgid));
 }
 
+/**@brief  Compute checksum of block group descriptor.
+ * @param sb   Superblock
+ * @param bgid Index of block group in the filesystem
+ * @param bg   Block group to compute checksum for
+ * @return Checksum value
+ */
+static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
+                                   struct ext4_bgroup *bg)
+{
+       /* If checksum not supported, 0 will be returned */
+       uint16_t crc = 0;
+#if CONFIG_META_CSUM_ENABLE
+       /* Compute the checksum only if the filesystem supports it */
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
+               /* Use metadata_csum algorithm instead */
+               uint32_t le32_bgid = to_le32(bgid);
+               uint32_t orig_checksum, checksum;
+
+               /* Preparation: temporarily set bg checksum to 0 */
+               orig_checksum = bg->checksum;
+               bg->checksum = 0;
+
+               /* First calculate crc32 checksum against fs uuid */
+               checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid,
+                               sizeof(sb->uuid));
+               /* Then calculate crc32 checksum against bgid */
+               checksum = ext4_crc32c(checksum, &le32_bgid,
+                                    sizeof(bgid));
+               /* Finally calculate crc32 checksum against block_group_desc */
+               checksum = ext4_crc32c(checksum, bg,
+                                    ext4_sb_get_desc_size(sb));
+               bg->checksum = orig_checksum;
+
+               crc = checksum & 0xFFFF;
+               return crc;
+       }
+#endif
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_GDT_CSUM)) {
+               uint8_t *base = (uint8_t *)bg;
+               uint8_t *checksum = (uint8_t *)&bg->checksum;
+
+               uint32_t offset = (uint32_t)(checksum - base);
+
+               /* Convert block group index to little endian */
+               uint32_t le_group = to_le32(bgid);
+
+               /* Initialization */
+               crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
+
+               /* Include index of block group */
+               crc =
+                   ext4_bg_crc16(crc, (uint8_t *)&le_group, sizeof(le_group));
+
+               /* Compute crc from the first part (stop before checksum field)
+                */
+               crc = ext4_bg_crc16(crc, (uint8_t *)bg, offset);
+
+               /* Skip checksum */
+               offset += sizeof(bg->checksum);
+
+               /* Checksum of the rest of block group descriptor */
+               if ((ext4_sb_feature_incom(sb, EXT4_FINCOM_64BIT)) &&
+                   (offset < ext4_sb_get_desc_size(sb)))
+
+                       crc = ext4_bg_crc16(crc, ((uint8_t *)bg) + offset,
+                                           ext4_sb_get_desc_size(sb) - offset);
+       }
+       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)
 {
@@ -516,6 +600,15 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
        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) {
@@ -556,81 +649,6 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
        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
- * @param bg   Block group to compute checksum for
- * @return Checksum value
- */
-static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
-                                   struct ext4_bgroup *bg)
-{
-       /* If checksum not supported, 0 will be returned */
-       uint16_t crc = 0;
-
-       /* Compute the checksum only if the filesystem supports it */
-       if (ext4_sb_has_feature_read_only(sb,
-                               EXT4_FRO_COM_METADATA_CSUM)) {
-               /* Use metadata_csum algorithm instead */
-               uint32_t le32_bgid = to_le32(bgid);
-               uint32_t orig_checksum, checksum;
-
-               /* Preparation: temporarily set bg checksum to 0 */
-               orig_checksum = bg->checksum;
-               bg->checksum = 0;
-
-               /* First calculate crc32 checksum against fs uuid */
-               checksum = ext4_crc32c(~0, sb->uuid, sizeof(sb->uuid));
-               /* Then calculate crc32 checksum against bgid */
-               checksum = ext4_crc32c(checksum, &le32_bgid,
-                                    sizeof(bgid));
-               /* Finally calculate crc32 checksum against block_group_desc */
-               checksum = ext4_crc32c(checksum, bg,
-                                    ext4_sb_get_desc_size(sb));
-               bg->checksum = orig_checksum;
-
-               crc = checksum & 0xFFFF;
-       } else if (ext4_sb_has_feature_read_only(sb,
-                                       EXT4_FRO_COM_GDT_CSUM)) {
-               uint8_t *base = (uint8_t *)bg;
-               uint8_t *checksum = (uint8_t *)&bg->checksum;
-
-               uint32_t offset = (uint32_t)(checksum - base);
-
-               /* Convert block group index to little endian */
-               uint32_t le_group = to_le32(bgid);
-
-               /* Initialization */
-               crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
-
-               /* Include index of block group */
-               crc =
-                   ext4_bg_crc16(crc, (uint8_t *)&le_group, sizeof(le_group));
-
-               /* Compute crc from the first part (stop before checksum field)
-                */
-               crc = ext4_bg_crc16(crc, (uint8_t *)bg, offset);
-
-               /* Skip checksum */
-               offset += sizeof(bg->checksum);
-
-               /* Checksum of the rest of block group descriptor */
-               if ((ext4_sb_has_feature_incompatible(
-                       sb, EXT4_FINCOM_64BIT)) &&
-                   (offset < ext4_sb_get_desc_size(sb)))
-
-                       crc = ext4_bg_crc16(crc, ((uint8_t *)bg) + offset,
-                                           ext4_sb_get_desc_size(sb) - offset);
-       }
-       return crc;
-}
-
 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
 {
        /* Check if reference modified */
@@ -649,14 +667,14 @@ int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
        return ext4_block_set(ref->fs->bdev, &ref->block);
 }
 
+#if CONFIG_META_CSUM_ENABLE
 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_FRO_COM_METADATA_CSUM)) {
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                uint32_t orig_checksum;
 
                uint32_t ino_index = to_le32(inode_ref->index);
@@ -668,7 +686,8 @@ static uint32_t ext4_fs_inode_checksum(struct ext4_inode_ref *inode_ref)
                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));
+               checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid,
+                               sizeof(sb->uuid));
                /* Then calculate crc32 checksum against inode number
                 * and inode generation */
                checksum = ext4_crc32c(checksum, &ino_index,
@@ -684,18 +703,34 @@ static uint32_t ext4_fs_inode_checksum(struct ext4_inode_ref *inode_ref)
        }
        return checksum;
 }
+#else
+#define ext4_fs_inode_checksum(...) 0
+#endif
 
 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_FRO_COM_METADATA_CSUM))
+       if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
                return;
 
        ext4_inode_set_checksum(sb, inode_ref->inode,
                                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 +786,13 @@ int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
        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;
 }
 
@@ -778,8 +820,7 @@ void ext4_fs_inode_blocks_init(struct ext4_fs *fs, struct ext4_inode_ref *inode_
        (void)fs;
 #if CONFIG_EXTENT_ENABLE
        /* Initialize extents if needed */
-       if (ext4_sb_has_feature_incompatible(&fs->sb,
-                               EXT4_FINCOM_EXTENTS)) {
+       if (ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) {
                ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
 
                /* Initialize extent root header */
@@ -864,7 +905,7 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
        if (inode_size > EXT4_GOOD_OLD_INODE_SIZE)
                ext4_inode_set_extra_isize(inode,
                                sizeof(struct ext4_inode) -
-                               ext4_offsetof(struct ext4_inode,
+                               offsetof(struct ext4_inode,
                                        extra_isize));
 
        /* Reset blocks array. For symbolic link inode, just
@@ -889,8 +930,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
        int rc;
 #if CONFIG_EXTENT_ENABLE
        /* For extents must be data block destroyed by other way */
-       if ((ext4_sb_has_feature_incompatible(&fs->sb,
-                                             EXT4_FINCOM_EXTENTS)) &&
+       if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
                /* Data structures are released during truncate operation... */
                goto finish;
@@ -1037,8 +1077,7 @@ static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
        /* Extents are handled otherwise = there is not support in this function
         */
        ext4_assert(!(
-           ext4_sb_has_feature_incompatible(&fs->sb,
-                                            EXT4_FINCOM_EXTENTS) &&
+           ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
 
        struct ext4_inode *inode = inode_ref->inode;
@@ -1166,8 +1205,7 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size)
                                    block_size;
        uint32_t diff_blocks_count = old_blocks_count - new_blocks_count;
 #if CONFIG_EXTENT_ENABLE
-       if ((ext4_sb_has_feature_incompatible(sb,
-                                             EXT4_FINCOM_EXTENTS)) &&
+       if ((ext4_sb_feature_incom(sb, EXT4_FINCOM_EXTENTS)) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
 
                /* Extents require special operation */
@@ -1290,7 +1328,7 @@ int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref,
 static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref,
                                       uint64_t iblock, ext4_fsblk_t *fblock,
                                       bool extent_create,
-                                      bool support_unwritten)
+                                      bool support_unwritten __unused)
 {
        struct ext4_fs *fs = inode_ref->fs;
 
@@ -1305,8 +1343,7 @@ static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref,
        (void)extent_create;
 #if CONFIG_EXTENT_ENABLE
        /* Handle i-node using extents */
-       if ((ext4_sb_has_feature_incompatible(&fs->sb,
-                                             EXT4_FINCOM_EXTENTS)) &&
+       if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
 
                ext4_fsblk_t current_fsblk;
@@ -1428,8 +1465,7 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
 
 #if CONFIG_EXTENT_ENABLE
        /* Handle inode using extents */
-       if ((ext4_sb_has_feature_incompatible(&fs->sb,
-                                             EXT4_FINCOM_EXTENTS)) &&
+       if ((ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
                /* Not reachable */
                return ENOTSUP;
@@ -1600,8 +1636,7 @@ int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
 {
 #if CONFIG_EXTENT_ENABLE
        /* Handle extents separately */
-       if ((ext4_sb_has_feature_incompatible(&inode_ref->fs->sb,
-                                             EXT4_FINCOM_EXTENTS)) &&
+       if ((ext4_sb_feature_incom(&inode_ref->fs->sb, EXT4_FINCOM_EXTENTS)) &&
            (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
                int rc;
                ext4_fsblk_t current_fsblk;
@@ -1676,8 +1711,7 @@ void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref)
        ext4_inode_set_links_count(inode_ref->inode, link);
 
        bool is_dx =
-           ext4_sb_has_feature_compatible(&inode_ref->fs->sb,
-                                          EXT4_FCOM_DIR_INDEX) &&
+           ext4_sb_feature_com(&inode_ref->fs->sb, EXT4_FCOM_DIR_INDEX) &&
            ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX);
 
        if (is_dx && link > 1) {