X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lwext4%2Fext4_ialloc.c;h=7f7b0d624579fa5dc9d40acba367a39e42e83012;hb=08c696765fb280e41b2637fa17b49d9272c8f865;hp=c8d2a52a26b01ed3f6f5b55413f3fa2cfbad396e;hpb=c897dc5a646527c2b87e4bc0399db59b46edbb1d;p=lwext4.git diff --git a/lwext4/ext4_ialloc.c b/lwext4/ext4_ialloc.c index c8d2a52..7f7b0d6 100644 --- a/lwext4/ext4_ialloc.c +++ b/lwext4/ext4_ialloc.c @@ -43,6 +43,7 @@ #include "ext4_types.h" #include "ext4_ialloc.h" #include "ext4_super.h" +#include "ext4_crc32c.h" #include "ext4_fs.h" #include "ext4_blockdev.h" #include "ext4_block_group.h" @@ -53,8 +54,8 @@ * @param inode I-node number to be converted * @return Index of the i-node in the block group */ -static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb, - uint32_t inode) +static uint32_t ext4_ialloc_inode_to_bgidx(struct ext4_sblock *sb, + uint32_t inode) { uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); return (inode - 1) % inodes_per_group; @@ -66,8 +67,8 @@ static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb, * @return Absolute number of the i-node * */ -static uint32_t ext4_ialloc_index_in_group2inode(struct ext4_sblock *sb, - uint32_t index, uint32_t bgid) +static uint32_t ext4_ialloc_bgidx_to_inode(struct ext4_sblock *sb, + uint32_t index, uint32_t bgid) { uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); return bgid * inodes_per_group + (index + 1); @@ -85,6 +86,70 @@ static uint32_t ext4_ialloc_get_bgid_of_inode(struct ext4_sblock *sb, return (inode - 1) / inodes_per_group; } +#if CONFIG_META_CSUM_ENABLE +static uint32_t ext4_ialloc_bitmap_csum(struct ext4_sblock *sb, void *bitmap) +{ + uint32_t csum = 0; + if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) { + uint32_t inodes_per_group = + ext4_get32(sb, inodes_per_group); + + /* First calculate crc32 checksum against fs uuid */ + csum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid, sizeof(sb->uuid)); + /* Then calculate crc32 checksum against inode bitmap */ + csum = ext4_crc32c(csum, bitmap, (inodes_per_group + 7) / 8); + } + return csum; +} +#else +#define ext4_ialloc_bitmap_csum(...) 0 +#endif + +void ext4_ialloc_set_bitmap_csum(struct ext4_sblock *sb, struct ext4_bgroup *bg, + void *bitmap __unused) +{ + int desc_size = ext4_sb_get_desc_size(sb); + uint32_t csum = ext4_ialloc_bitmap_csum(sb, bitmap); + uint16_t lo_csum = to_le16(csum & 0xFFFF), + hi_csum = to_le16(csum >> 16); + + if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) + return; + + /* See if we need to assign a 32bit checksum */ + bg->inode_bitmap_csum_lo = lo_csum; + if (desc_size == EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE) + bg->inode_bitmap_csum_hi = hi_csum; + +} + +#if CONFIG_META_CSUM_ENABLE +static bool +ext4_ialloc_verify_bitmap_csum(struct ext4_sblock *sb, struct ext4_bgroup *bg, + void *bitmap __unused) +{ + + int desc_size = ext4_sb_get_desc_size(sb); + uint32_t csum = ext4_ialloc_bitmap_csum(sb, bitmap); + uint16_t lo_csum = to_le16(csum & 0xFFFF), + hi_csum = to_le16(csum >> 16); + + if (!ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) + return true; + + if (bg->inode_bitmap_csum_lo != lo_csum) + return false; + + if (desc_size == EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE) + if (bg->inode_bitmap_csum_hi != hi_csum) + return false; + + return true; +} +#else +#define ext4_ialloc_verify_bitmap_csum(...) true +#endif + int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir) { struct ext4_sblock *sb = &fs->sb; @@ -97,22 +162,32 @@ int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir) if (rc != EOK) return rc; + struct ext4_bgroup *bg = bg_ref.block_group; + /* Load i-node bitmap */ uint32_t bitmap_block_addr = - ext4_bg_get_inode_bitmap(bg_ref.block_group, sb); + ext4_bg_get_inode_bitmap(bg, sb); - struct ext4_block bitmap_block; - rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr); + struct ext4_block b; + rc = ext4_block_get(fs->bdev, &b, bitmap_block_addr); if (rc != EOK) return rc; + if (!ext4_ialloc_verify_bitmap_csum(sb, bg, b.data)) { + ext4_dbg(DEBUG_IALLOC, + DBG_WARN "Bitmap checksum failed." + "Group: %" PRIu32"\n", + bg_ref.index); + } + /* Free i-node in the bitmap */ - uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index); - ext4_bmap_bit_clr(bitmap_block.data, index_in_group); - bitmap_block.dirty = true; + uint32_t index_in_group = ext4_ialloc_inode_to_bgidx(sb, index); + ext4_bmap_bit_clr(b.data, index_in_group); + ext4_ialloc_set_bitmap_csum(sb, bg, b.data); + b.dirty = true; /* Put back the block with bitmap */ - rc = ext4_block_set(fs->bdev, &bitmap_block); + rc = ext4_block_set(fs->bdev, &b); if (rc != EOK) { /* Error in saving bitmap */ ext4_fs_put_block_group_ref(&bg_ref); @@ -122,18 +197,15 @@ int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir) /* If released i-node is a directory, decrement used directories count */ if (is_dir) { - uint32_t bg_used_dirs = - ext4_bg_get_used_dirs_count(bg_ref.block_group, sb); + uint32_t bg_used_dirs = ext4_bg_get_used_dirs_count(bg, sb); bg_used_dirs--; - ext4_bg_set_used_dirs_count(bg_ref.block_group, sb, - bg_used_dirs); + ext4_bg_set_used_dirs_count(bg, sb, bg_used_dirs); } /* Update block group free inodes count */ - uint32_t free_inodes = - ext4_bg_get_free_inodes_count(bg_ref.block_group, sb); + uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb); free_inodes++; - ext4_bg_set_free_inodes_count(bg_ref.block_group, sb, free_inodes); + ext4_bg_set_free_inodes_count(bg, sb, free_inodes); bg_ref.dirty = true; @@ -149,7 +221,7 @@ int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir) return EOK; } -int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) +int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *idx, bool is_dir) { struct ext4_sblock *sb = &fs->sb; @@ -185,28 +257,32 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) /* Check if this block group is good candidate for allocation */ if (free_inodes > 0) { /* Load block with bitmap */ - uint32_t bitmap_block_addr = - ext4_bg_get_inode_bitmap(bg_ref.block_group, sb); + uint32_t bmp_blk_add = ext4_bg_get_inode_bitmap(bg, sb); - struct ext4_block bitmap_block; - rc = ext4_block_get(fs->bdev, &bitmap_block, - bitmap_block_addr); + struct ext4_block b; + rc = ext4_block_get(fs->bdev, &b, bmp_blk_add); if (rc != EOK) { ext4_fs_put_block_group_ref(&bg_ref); return rc; } + if (!ext4_ialloc_verify_bitmap_csum(sb, bg, b.data)) { + ext4_dbg(DEBUG_IALLOC, + DBG_WARN "Bitmap checksum failed." + "Group: %" PRIu32"\n", + bg_ref.index); + } + /* Try to allocate i-node in the bitmap */ - uint32_t inodes_in_group = - ext4_inodes_in_group_cnt(sb, bgid); - uint32_t index_in_group; + uint32_t inodes_in_bg; + uint32_t idx_in_bg; - rc = ext4_bmap_bit_find_clr(bitmap_block.data, 0, - inodes_in_group, - &index_in_group); + inodes_in_bg = ext4_inodes_in_group_cnt(sb, bgid); + rc = ext4_bmap_bit_find_clr(b.data, 0, inodes_in_bg, + &idx_in_bg); /* Block group has not any free i-node */ if (rc == ENOSPC) { - rc = ext4_block_set(fs->bdev, &bitmap_block); + rc = ext4_block_set(fs->bdev, &b); if (rc != EOK) { ext4_fs_put_block_group_ref(&bg_ref); return rc; @@ -219,12 +295,14 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) continue; } - ext4_bmap_bit_set(bitmap_block.data, index_in_group); + ext4_bmap_bit_set(b.data, idx_in_bg); /* Free i-node found, save the bitmap */ - bitmap_block.dirty = true; + ext4_ialloc_set_bitmap_csum(sb,bg, + b.data); + b.dirty = true; - ext4_block_set(fs->bdev, &bitmap_block); + ext4_block_set(fs->bdev, &b); if (rc != EOK) { ext4_fs_put_block_group_ref(&bg_ref); return rc; @@ -241,22 +319,14 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) } /* Decrease unused inodes count */ - if (ext4_bg_has_flag(bg, - EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { - uint32_t unused = - ext4_bg_get_itable_unused(bg, sb); + uint32_t unused = + ext4_bg_get_itable_unused(bg, sb); - uint32_t inodes_in_group = - ext4_inodes_in_group_cnt(sb, bgid); + uint32_t free = inodes_in_bg - unused; - uint32_t free = inodes_in_group - unused; - - if (index_in_group >= free) { - unused = inodes_in_group - - (index_in_group + 1); - ext4_bg_set_itable_unused(bg, sb, - unused); - } + if (idx_in_bg >= free) { + unused = inodes_in_bg - (idx_in_bg + 1); + ext4_bg_set_itable_unused(bg, sb, unused); } /* Save modified block group */ @@ -271,8 +341,7 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) ext4_set32(sb, free_inodes_count, sb_free_inodes); /* Compute the absolute i-nodex number */ - *index = ext4_ialloc_index_in_group2inode( - sb, index_in_group, bgid); + *idx = ext4_ialloc_bgidx_to_inode(sb, idx_in_bg, bgid); fs->last_inode_bg_id = bgid;