Do not verify checksum upon seeking in the directory.
[lwext4.git] / lwext4 / ext4_dir_idx.c
index 12fb03c6ee713bb0df4146451ed387ff02945e75..59f0c5675298efb199ef58b227be5501bd9af1ee 100644 (file)
@@ -204,6 +204,7 @@ static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
                               &hinfo->hash, &hinfo->minor_hash);
 }
 
+#if CONFIG_META_CSUM_ENABLE
 static uint32_t
 ext4_dir_dx_checksum(struct ext4_inode_ref *inode_ref,
                 void *dirent,
@@ -214,8 +215,7 @@ ext4_dir_dx_checksum(struct ext4_inode_ref *inode_ref,
        int size;
 
        /* Compute the checksum only if the filesystem supports it */
-       if (ext4_sb_has_feature_read_only(sb,
-                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                uint32_t ino_index = to_le32(inode_ref->index);
                uint32_t ino_gen =
                        to_le32(ext4_inode_get_generation(inode_ref->inode));
@@ -225,7 +225,8 @@ ext4_dir_dx_checksum(struct ext4_inode_ref *inode_ref,
                orig_checksum = t->checksum;
                t->checksum = 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,
@@ -277,20 +278,19 @@ ext4_dir_dx_get_countlimit(struct ext4_inode_ref *inode_ref,
  * BIG FAT NOTES:
  *       Currently we do not verify the checksum of HTree node.
  */
-__unused static int
+static bool
 ext4_dir_dx_checksum_verify(struct ext4_inode_ref *inode_ref,
                                struct ext4_directory_entry_ll *dirent)
 {
        struct ext4_sblock *sb = &inode_ref->fs->sb;
        int count_offset, limit, count;
 
-       if (ext4_sb_has_feature_read_only(sb,
-                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                struct ext4_directory_dx_countlimit *countlimit =
                        ext4_dir_dx_get_countlimit(inode_ref, dirent, &count_offset);
                if (!countlimit) {
                        /* Directory seems corrupted. */
-                       return 1;
+                       return true;
                }
                struct ext4_directory_dx_tail *t;
                limit = ext4_dir_dx_countlimit_get_limit(countlimit);
@@ -299,7 +299,7 @@ ext4_dir_dx_checksum_verify(struct ext4_inode_ref *inode_ref,
                                ext4_sb_get_block_size(sb) -
                                sizeof(struct ext4_directory_dx_tail)) {
                        /* There is no space to hold the checksum */
-                       return 1;
+                       return true;
                }
                t = (struct ext4_directory_dx_tail *)
                        (((struct ext4_directory_dx_entry *)countlimit) + limit);
@@ -308,11 +308,12 @@ ext4_dir_dx_checksum_verify(struct ext4_inode_ref *inode_ref,
                                                                dirent,
                                                                count_offset,
                                                                count, t)))
-                       return 0;
+                       return false;
        }
-       return 1;
+       return true;
 }
 
+
 static void
 ext4_dir_set_dx_checksum(struct ext4_inode_ref *inode_ref,
                        struct ext4_directory_entry_ll *dirent)
@@ -320,8 +321,7 @@ ext4_dir_set_dx_checksum(struct ext4_inode_ref *inode_ref,
        int count_offset, limit, count;
        struct ext4_sblock *sb = &inode_ref->fs->sb;
 
-       if (ext4_sb_has_feature_read_only(sb,
-                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                struct ext4_directory_dx_countlimit *countlimit =
                        ext4_dir_dx_get_countlimit(inode_ref, dirent, &count_offset);
                if (!countlimit) {
@@ -344,6 +344,9 @@ ext4_dir_set_dx_checksum(struct ext4_inode_ref *inode_ref,
                        to_le32(ext4_dir_dx_checksum(inode_ref, dirent, count_offset, count, t));
        }
 }
+#else
+#define ext4_dir_set_dx_checksum(...)
+#endif
 
 /****************************************************************************/
 
@@ -398,9 +401,9 @@ int ext4_dir_dx_init(struct ext4_inode_ref *dir, struct ext4_inode_ref *parent)
        uint32_t entry_space = block_size -
                               2 * sizeof(struct ext4_directory_dx_dot_entry) -
                               sizeof(struct ext4_directory_dx_root_info);
-       if (ext4_sb_has_feature_read_only(sb,
-                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
                entry_space -= sizeof(struct ext4_directory_dx_tail);
+
        uint16_t root_limit =
            entry_space / sizeof(struct ext4_directory_dx_entry);
 
@@ -424,8 +427,7 @@ int ext4_dir_dx_init(struct ext4_inode_ref *dir, struct ext4_inode_ref *parent)
        /* Fill the whole block with empty entry */
        struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
 
-       if (ext4_sb_has_feature_read_only(sb,
-                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                ext4_dir_entry_ll_set_entry_length(block_entry,
                                block_size -
                                sizeof(struct ext4_directory_entry_tail));
@@ -498,6 +500,8 @@ static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
        uint32_t entry_space = block_size;
        entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
        entry_space -= sizeof(struct ext4_directory_dx_root_info);
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
+               entry_space -= sizeof(struct ext4_directory_dx_tail);
        entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
 
        uint16_t limit = ext4_dir_dx_countlimit_get_limit(
@@ -614,6 +618,10 @@ static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
                    ext4_sb_get_block_size(&inode_ref->fs->sb) -
                    sizeof(struct ext4_fake_directory_entry);
 
+               if (ext4_sb_feature_ro_com(&inode_ref->fs->sb,
+                               EXT4_FRO_COM_METADATA_CSUM))
+                       entry_space -= sizeof(struct ext4_directory_dx_tail);
+
                entry_space =
                    entry_space / sizeof(struct ext4_directory_dx_entry);
 
@@ -622,6 +630,16 @@ static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
                        return EXT4_ERR_BAD_DX_DIR;
                }
 
+               if (!ext4_dir_dx_checksum_verify(inode_ref,
+                                       (struct ext4_directory_entry_ll *)tmp_block->data)) {
+                       ext4_dbg(DEBUG_DIR_IDX,
+                                       DBG_WARN "HTree checksum failed."
+                                       "Inode: %" PRIu32", "
+                                       "Block: %" PRIu32"\n",
+                                       inode_ref->index,
+                                       next_block);
+               }
+
                ++tmp_dx_block;
        }
 
@@ -683,6 +701,16 @@ static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
                if (rc != EOK)
                        return rc;
 
+               if (!ext4_dir_dx_checksum_verify(inode_ref,
+                                       (struct ext4_directory_entry_ll *)block.data)) {
+                       ext4_dbg(DEBUG_DIR_IDX,
+                                       DBG_WARN "HTree checksum failed."
+                                       "Inode: %" PRIu32", "
+                                       "Block: %" PRIu32"\n",
+                                       inode_ref->index,
+                                       block_idx);
+               }
+
                p++;
 
                /* Don't forget to put old block (prevent memory leak) */
@@ -719,6 +747,16 @@ int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
        if (rc != EOK)
                return rc;
 
+       if (!ext4_dir_dx_checksum_verify(inode_ref,
+                               (struct ext4_directory_entry_ll *)root_block.data)) {
+               ext4_dbg(DEBUG_DIR_IDX,
+                        DBG_WARN "HTree root checksum failed."
+                        "Inode: %" PRIu32", "
+                        "Block: %" PRIu32"\n",
+                        inode_ref->index,
+                        0);
+       }
+
        /* Initialize hash info (compute hash value) */
        struct ext4_hash_info hinfo;
        rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
@@ -759,6 +797,16 @@ int ext4_dir_dx_find_entry(struct ext4_directory_search_result *result,
                if (rc != EOK)
                        goto cleanup;
 
+               if (!ext4_dir_checksum_verify(inode_ref,
+                               (struct ext4_directory_entry_ll *)leaf_block.data)) {
+                       ext4_dbg(DEBUG_DIR_IDX,
+                                DBG_WARN "HTree leaf block checksum failed."
+                                "Inode: %" PRIu32", "
+                                "Block: %" PRIu32"\n",
+                                inode_ref->index,
+                                leaf_block_idx);
+               }
+
                /* Linear search inside block */
                struct ext4_directory_entry_ll *res_dentry;
                rc = ext4_dir_find_in_block(&leaf_block, &fs->sb, name_len,
@@ -872,7 +920,7 @@ static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
  *
  */
 static void
-ext4_dir_dx_insert_entry(struct ext4_inode_ref *inode_ref,
+ext4_dir_dx_insert_entry(struct ext4_inode_ref *inode_ref __unused,
                         struct ext4_directory_dx_block *index_block,
                         uint32_t hash, uint32_t iblock)
 {
@@ -1031,9 +1079,8 @@ static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
 
        uint32_t offset = 0;
        void *ptr;
-
-       if (ext4_sb_has_feature_read_only(&inode_ref->fs->sb,
-                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+       struct ext4_sblock *sb = &inode_ref->fs->sb;
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
                block_size -= sizeof(struct ext4_directory_entry_tail);
 
        /* First part - to the old block */
@@ -1072,8 +1119,8 @@ static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
        block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
 
        /* Do some steps to finish operation */
-       if (ext4_sb_has_feature_read_only(&inode_ref->fs->sb,
-                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       sb = &inode_ref->fs->sb;
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
                initialize_dir_tail(EXT4_DIRENT_TAIL(old_data_block->data,
                                        block_size));
                initialize_dir_tail(EXT4_DIRENT_TAIL(new_data_block_tmp.data,
@@ -1201,12 +1248,11 @@ ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
                        uint32_t entry_space =
                            block_size -
                            sizeof(struct ext4_fake_directory_entry);
-                       if (ext4_sb_has_feature_read_only(sb,
-                                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+                       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
                                entry_space -= sizeof(struct ext4_directory_dx_tail);
+
                        uint32_t node_limit =
-                           entry_space /
-                           sizeof(struct ext4_directory_dx_entry);
+                           entry_space / sizeof(struct ext4_directory_dx_entry);
 
                        ext4_dir_dx_countlimit_set_limit(right_countlimit,
                                                         node_limit);
@@ -1264,12 +1310,11 @@ ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
                        uint32_t entry_space =
                            block_size -
                            sizeof(struct ext4_fake_directory_entry);
-                       if (ext4_sb_has_feature_read_only(sb,
-                                                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+                       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
                                entry_space -= sizeof(struct ext4_directory_dx_tail);
+
                        uint32_t node_limit =
-                           entry_space /
-                           sizeof(struct ext4_directory_dx_entry);
+                           entry_space / sizeof(struct ext4_directory_dx_entry);
                        ext4_dir_dx_countlimit_set_limit(new_countlimit,
                                                         node_limit);
 
@@ -1330,6 +1375,16 @@ int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
        if (rc != EOK)
                return rc;
 
+       if (!ext4_dir_dx_checksum_verify(parent,
+                       (struct ext4_directory_entry_ll *)root_block.data)) {
+               ext4_dbg(DEBUG_DIR_IDX,
+                        DBG_WARN "HTree root checksum failed."
+                        "Inode: %" PRIu32", "
+                        "Block: %" PRIu32"\n",
+                        parent->index,
+                        0);
+       }
+
        /* Initialize hinfo structure (mainly compute hash) */
        uint32_t name_len = strlen(name);
        struct ext4_hash_info hinfo;
@@ -1377,6 +1432,16 @@ int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
        if (rc != EOK)
                goto release_index;
 
+       if (!ext4_dir_checksum_verify(parent,
+                       (struct ext4_directory_entry_ll *)target_block.data)) {
+               ext4_dbg(DEBUG_DIR_IDX,
+                               DBG_WARN "HTree leaf block checksum failed."
+                               "Inode: %" PRIu32", "
+                               "Block: %" PRIu32"\n",
+                               parent->index,
+                               leaf_block_idx);
+       }
+
        /* Check if insert operation passed */
        rc = ext4_dir_try_insert_entry(&fs->sb, parent, &target_block, child, name,
                                       name_len);
@@ -1447,6 +1512,16 @@ int ext4_dir_dx_reset_parent_inode(struct ext4_inode_ref *dir,
        if (rc != EOK)
                return rc;
 
+       if (!ext4_dir_dx_checksum_verify(dir,
+                       (struct ext4_directory_entry_ll *)block.data)) {
+               ext4_dbg(DEBUG_DIR_IDX,
+                        DBG_WARN "HTree root checksum failed."
+                        "Inode: %" PRIu32", "
+                        "Block: %" PRIu32"\n",
+                        dir->index,
+                        0);
+       }
+
        /* Initialize pointers to data structures */
        struct ext4_directory_dx_root *root = (void *)block.data;