X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=lwext4%2Fext4_fs.c;h=1d807f2821dd002814e71eeef404c990d783dfba;hb=809b27e9dcf7f7120b98b03b13ceb624302e8183;hp=880268ee0c0f37cecf6e07011cba643efa0f95b6;hpb=76ccc5426eab8185b7e0bf43a35ebb7bcedda79c;p=lwext4.git diff --git a/lwext4/ext4_fs.c b/lwext4/ext4_fs.c index 880268e..1d807f2 100644 --- a/lwext4/ext4_fs.c +++ b/lwext4/ext4_fs.c @@ -44,7 +44,7 @@ #include "ext4_errno.h" #include "ext4_blockdev.h" #include "ext4_super.h" -#include "ext4_crc32c.h" +#include "ext4_crc32.h" #include "ext4_debug.h" #include "ext4_block_group.h" #include "ext4_balloc.h" @@ -128,72 +128,72 @@ int ext4_fs_fini(struct ext4_fs *fs) static void ext4_fs_debug_features_inc(uint32_t features_incompatible) { - if (features_incompatible & EXT4_FEATURE_INCOMPAT_COMPRESSION) + if (features_incompatible & EXT4_FINCOM_COMPRESSION) ext4_dbg(DEBUG_FS, DBG_NONE "compression\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_FILETYPE) + if (features_incompatible & EXT4_FINCOM_FILETYPE) ext4_dbg(DEBUG_FS, DBG_NONE "filetype\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_RECOVER) + if (features_incompatible & EXT4_FINCOM_RECOVER) ext4_dbg(DEBUG_FS, DBG_NONE "recover\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_JOURNAL_DEV) + if (features_incompatible & EXT4_FINCOM_JOURNAL_DEV) ext4_dbg(DEBUG_FS, DBG_NONE "journal_dev\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_META_BG) + if (features_incompatible & EXT4_FINCOM_META_BG) ext4_dbg(DEBUG_FS, DBG_NONE "meta_bg\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_EXTENTS) + if (features_incompatible & EXT4_FINCOM_EXTENTS) ext4_dbg(DEBUG_FS, DBG_NONE "extents\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_64BIT) + if (features_incompatible & EXT4_FINCOM_64BIT) ext4_dbg(DEBUG_FS, DBG_NONE "64bit\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_MMP) + if (features_incompatible & EXT4_FINCOM_MMP) ext4_dbg(DEBUG_FS, DBG_NONE "mnp\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_FLEX_BG) + if (features_incompatible & EXT4_FINCOM_FLEX_BG) ext4_dbg(DEBUG_FS, DBG_NONE "flex_bg\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_EA_INODE) + if (features_incompatible & EXT4_FINCOM_EA_INODE) ext4_dbg(DEBUG_FS, DBG_NONE "ea_inode\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_DIRDATA) + if (features_incompatible & EXT4_FINCOM_DIRDATA) ext4_dbg(DEBUG_FS, DBG_NONE "dirdata\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM) + if (features_incompatible & EXT4_FINCOM_BG_USE_META_CSUM) ext4_dbg(DEBUG_FS, DBG_NONE "meta_csum\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_LARGEDIR) + if (features_incompatible & EXT4_FINCOM_LARGEDIR) ext4_dbg(DEBUG_FS, DBG_NONE "largedir\n"); - if (features_incompatible & EXT4_FEATURE_INCOMPAT_INLINE_DATA) + if (features_incompatible & EXT4_FINCOM_INLINE_DATA) ext4_dbg(DEBUG_FS, DBG_NONE "inline_data\n"); } static void ext4_fs_debug_features_comp(uint32_t features_compatible) { - if (features_compatible & EXT4_FEATURE_COMPAT_DIR_PREALLOC) + if (features_compatible & EXT4_FCOM_DIR_PREALLOC) ext4_dbg(DEBUG_FS, DBG_NONE "dir_prealloc\n"); - if (features_compatible & EXT4_FEATURE_COMPAT_IMAGIC_INODES) + if (features_compatible & EXT4_FCOM_IMAGIC_INODES) ext4_dbg(DEBUG_FS, DBG_NONE "imagic_inodes\n"); - if (features_compatible & EXT4_FEATURE_COMPAT_HAS_JOURNAL) + if (features_compatible & EXT4_FCOM_HAS_JOURNAL) ext4_dbg(DEBUG_FS, DBG_NONE "has_journal\n"); - if (features_compatible & EXT4_FEATURE_COMPAT_EXT_ATTR) + if (features_compatible & EXT4_FCOM_EXT_ATTR) ext4_dbg(DEBUG_FS, DBG_NONE "ext_attr\n"); - if (features_compatible & EXT4_FEATURE_COMPAT_RESIZE_INODE) + if (features_compatible & EXT4_FCOM_RESIZE_INODE) ext4_dbg(DEBUG_FS, DBG_NONE "resize_inode\n"); - if (features_compatible & EXT4_FEATURE_COMPAT_DIR_INDEX) + if (features_compatible & EXT4_FCOM_DIR_INDEX) ext4_dbg(DEBUG_FS, DBG_NONE "dir_index\n"); } static void ext4_fs_debug_features_ro(uint32_t features_ro) { - if (features_ro & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) + if (features_ro & EXT4_FRO_COM_SPARSE_SUPER) ext4_dbg(DEBUG_FS, DBG_NONE "sparse_super\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_LARGE_FILE) + if (features_ro & EXT4_FRO_COM_LARGE_FILE) ext4_dbg(DEBUG_FS, DBG_NONE "large_file\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_BTREE_DIR) + if (features_ro & EXT4_FRO_COM_BTREE_DIR) ext4_dbg(DEBUG_FS, DBG_NONE "btree_dir\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) + if (features_ro & EXT4_FRO_COM_HUGE_FILE) ext4_dbg(DEBUG_FS, DBG_NONE "huge_file\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) + if (features_ro & EXT4_FRO_COM_GDT_CSUM) ext4_dbg(DEBUG_FS, DBG_NONE "gtd_csum\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) + if (features_ro & EXT4_FRO_COM_DIR_NLINK) ext4_dbg(DEBUG_FS, DBG_NONE "dir_nlink\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) + if (features_ro & EXT4_FRO_COM_EXTRA_ISIZE) ext4_dbg(DEBUG_FS, DBG_NONE "extra_isize\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_QUOTA) + if (features_ro & EXT4_FRO_COM_QUOTA) ext4_dbg(DEBUG_FS, DBG_NONE "quota\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_BIGALLOC) + if (features_ro & EXT4_FRO_COM_BIGALLOC) ext4_dbg(DEBUG_FS, DBG_NONE "bigalloc\n"); - if (features_ro & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) + if (features_ro & EXT4_FRO_COM_METADATA_CSUM) ext4_dbg(DEBUG_FS, DBG_NONE "metadata_csum\n"); } @@ -217,7 +217,7 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only) /*Check features_incompatible*/ v = (ext4_get32(&fs->sb, features_incompatible) & - (~CONFIG_FEATURE_INCOMPAT_SUPP)); + (~CONFIG_SUPPORTED_FINCOM)); if (v) { ext4_dbg(DEBUG_FS, DBG_ERROR "sblock has unsupported features incompatible:\n"); @@ -226,11 +226,11 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only) } /*Check features_read_only*/ - v = (ext4_get32(&fs->sb, features_read_only) & - (~CONFIG_FEATURE_RO_COMPAT_SUPP)); + v = ext4_get32(&fs->sb, features_read_only); + v &= ~CONFIG_SUPPORTED_FRO_COM; if (v) { ext4_dbg(DEBUG_FS, DBG_WARN - "sblock has unsupported features read only:\n"); + "sblock has unsupported features read only:\n"); ext4_fs_debug_features_ro(v); *read_only = true; return EOK; @@ -245,15 +245,14 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only) * @param bgid block group id * @return Error code */ -static int ext4_block_in_group(struct ext4_sblock *s, - ext4_fsblk_t baddr, - uint32_t bgid) +static bool ext4_block_in_group(struct ext4_sblock *s, ext4_fsblk_t baddr, + uint32_t bgid) { uint32_t actual_bgid; actual_bgid = ext4_balloc_get_bgid_of_block(s, baddr); if (actual_bgid == bgid) - return 1; - return 0; + return true; + return false; } /**@brief To avoid calling the atomic setbit hundreds or thousands of times, we only @@ -280,91 +279,76 @@ static void ext4_fs_mark_bitmap_end(int start_bit, int end_bit, void *bitmap) */ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref) { + struct ext4_sblock *sb = &bg_ref->fs->sb; + struct ext4_bgroup *bg = bg_ref->block_group; + int rc; + uint32_t i, bit, bit_max; uint32_t group_blocks; - uint16_t inode_size = ext4_get16(&bg_ref->fs->sb, inode_size); - uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb); - uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group); - ext4_fsblk_t bitmap_block_addr = - ext4_bg_get_block_bitmap(bg_ref->block_group, &bg_ref->fs->sb); - ext4_fsblk_t bitmap_inode_addr = - ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb); - ext4_fsblk_t inode_table_addr = - ext4_bg_get_inode_table_first_block(bg_ref->block_group, - &bg_ref->fs->sb); - ext4_fsblk_t first_group_addr = - ext4_balloc_get_block_of_bgid(&bg_ref->fs->sb, bg_ref->index); - - uint32_t dsc_per_block = - ext4_sb_get_block_size(&bg_ref->fs->sb) / - ext4_sb_get_desc_size(&bg_ref->fs->sb); - - bool flex_bg = - ext4_sb_has_feature_incompatible(&bg_ref->fs->sb, - EXT4_FEATURE_INCOMPAT_FLEX_BG); + uint16_t inode_size = ext4_get16(sb, inode_size); + uint32_t block_size = ext4_sb_get_block_size(sb); + uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); + + ext4_fsblk_t bmp_blk = ext4_bg_get_block_bitmap(bg, sb); + ext4_fsblk_t bmp_inode = ext4_bg_get_inode_bitmap(bg, sb); + ext4_fsblk_t inode_table = ext4_bg_get_inode_table_first_block(bg, sb); + ext4_fsblk_t first_bg = ext4_balloc_get_block_of_bgid(sb, bg_ref->index); + + uint32_t dsc_per_block = block_size / ext4_sb_get_desc_size(sb); + + bool flex_bg = ext4_sb_feature_incom(sb, EXT4_FINCOM_FLEX_BG); + bool meta_bg = ext4_sb_feature_incom(sb, EXT4_FINCOM_META_BG); uint32_t inode_table_bcnt = inodes_per_group * inode_size / block_size; struct ext4_block block_bitmap; - int rc = - ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr); + rc = ext4_trans_block_get_noread(bg_ref->fs->bdev, &block_bitmap, bmp_blk); if (rc != EOK) return rc; memset(block_bitmap.data, 0, block_size); + bit_max = ext4_sb_is_super_in_bg(sb, bg_ref->index); - 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_FEATURE_INCOMPAT_META_BG) || - bg_ref->index < ext4_sb_first_meta_bg(&bg_ref->fs->sb) * - dsc_per_block) { + uint32_t count = ext4_sb_first_meta_bg(sb) * dsc_per_block; + if (!meta_bg || bg_ref->index < count) { if (bit_max) { - bit_max += ext4_bg_num_gdb(&bg_ref->fs->sb, - bg_ref->index); - bit_max += - ext4_get16(&bg_ref->fs->sb, - s_reserved_gdt_blocks); + bit_max += ext4_bg_num_gdb(sb, bg_ref->index); + bit_max += ext4_get16(sb, s_reserved_gdt_blocks); } } else { /* For META_BG_BLOCK_GROUPS */ - bit_max += ext4_bg_num_gdb(&bg_ref->fs->sb, - bg_ref->index); + bit_max += ext4_bg_num_gdb(sb, bg_ref->index); } for (bit = 0; bit < bit_max; bit++) ext4_bmap_bit_set(block_bitmap.data, bit); - if (bg_ref->index == ext4_block_group_cnt(&bg_ref->fs->sb) - 1) { + if (bg_ref->index == ext4_block_group_cnt(sb) - 1) { /* * Even though mke2fs always initialize first and last group * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need * to make sure we calculate the right free blocks */ - group_blocks = (ext4_sb_get_blocks_cnt(&bg_ref->fs->sb) - - ext4_get32(&bg_ref->fs->sb, first_data_block) - - (ext4_get32(&bg_ref->fs->sb, blocks_per_group) * - (ext4_block_group_cnt(&bg_ref->fs->sb) - 1))); + + group_blocks = ext4_sb_get_blocks_cnt(sb); + group_blocks -= ext4_get32(sb, first_data_block); + group_blocks -= ext4_get32(sb, blocks_per_group) * + (ext4_block_group_cnt(sb) - 1); } else { - group_blocks = ext4_get32(&bg_ref->fs->sb, blocks_per_group); + group_blocks = ext4_get32(sb, blocks_per_group); } - if (!flex_bg || - ext4_block_in_group(&bg_ref->fs->sb, - bitmap_block_addr, bg_ref->index)) - ext4_bmap_bit_set(block_bitmap.data, - bitmap_block_addr - first_group_addr); - - if (!flex_bg || - ext4_block_in_group(&bg_ref->fs->sb, - bitmap_inode_addr, bg_ref->index)) - ext4_bmap_bit_set(block_bitmap.data, - bitmap_inode_addr - first_group_addr); - - for (i = inode_table_addr; - i < inode_table_addr + inode_table_bcnt; i++) { - if (!flex_bg || - ext4_block_in_group(&bg_ref->fs->sb, - i, - bg_ref->index)) - ext4_bmap_bit_set(block_bitmap.data, - i - first_group_addr); + + bool in_bg; + in_bg = ext4_block_in_group(sb, bmp_blk, bg_ref->index); + if (!flex_bg || in_bg) + ext4_bmap_bit_set(block_bitmap.data, bmp_blk - first_bg); + + in_bg = ext4_block_in_group(sb, bmp_inode, bg_ref->index); + if (!flex_bg || in_bg) + ext4_bmap_bit_set(block_bitmap.data, bmp_inode - first_bg); + + for (i = inode_table; i < inode_table + inode_table_bcnt; i++) { + in_bg = ext4_block_in_group(sb, i, bg_ref->index); + if (!flex_bg || in_bg) + ext4_bmap_bit_set(block_bitmap.data, i - first_bg); } /* * Also if the number of blocks within the group is @@ -372,7 +356,10 @@ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref) * of bitmap ), set rest of the block bitmap to 1 */ ext4_fs_mark_bitmap_end(group_blocks, block_size * 8, block_bitmap.data); - block_bitmap.dirty = true; + ext4_trans_set_block_dirty(block_bitmap.buf); + + ext4_balloc_set_bitmap_csum(sb, bg_ref->block_group, block_bitmap.data); + bg_ref->dirty = true; /* Save bitmap */ return ext4_block_set(bg_ref->fs->bdev, &block_bitmap); @@ -384,37 +371,41 @@ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref) */ static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref) { + int rc; + struct ext4_sblock *sb = &bg_ref->fs->sb; + struct ext4_bgroup *bg = bg_ref->block_group; + /* Load bitmap */ - ext4_fsblk_t bitmap_block_addr = - ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb); + ext4_fsblk_t bitmap_block_addr = ext4_bg_get_inode_bitmap(bg, sb); - struct ext4_block block_bitmap; - int rc = - ext4_block_get(bg_ref->fs->bdev, &block_bitmap, bitmap_block_addr); + struct ext4_block b; + rc = ext4_trans_block_get_noread(bg_ref->fs->bdev, &b, bitmap_block_addr); if (rc != EOK) return rc; /* Initialize all bitmap bits to zero */ - uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb); - uint32_t inodes_per_group = - ext4_get32(&bg_ref->fs->sb, inodes_per_group); + uint32_t block_size = ext4_sb_get_block_size(sb); + uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); - memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8); + memset(b.data, 0, (inodes_per_group + 7) / 8); uint32_t start_bit = inodes_per_group; uint32_t end_bit = block_size * 8; uint32_t i; for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) - ext4_bmap_bit_set(block_bitmap.data, i); + ext4_bmap_bit_set(b.data, i); if (i < end_bit) - memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3); + memset(b.data + (i >> 3), 0xff, (end_bit - i) >> 3); + + ext4_trans_set_block_dirty(b.buf); - block_bitmap.dirty = true; + ext4_ialloc_set_bitmap_csum(sb, bg, b.data); + bg_ref->dirty = true; /* Save bitmap */ - return ext4_block_set(bg_ref->fs->bdev, &block_bitmap); + return ext4_block_set(bg_ref->fs->bdev, &b); } /**@brief Initialize i-node table in block group. @@ -424,6 +415,7 @@ static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref) static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref) { struct ext4_sblock *sb = &bg_ref->fs->sb; + struct ext4_bgroup *bg = bg_ref->block_group; uint32_t inode_size = ext4_get32(sb, inode_size); uint32_t block_size = ext4_sb_get_block_size(sb); @@ -436,23 +428,21 @@ static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref) table_blocks++; /* Compute initialization bounds */ - ext4_fsblk_t first_block = - ext4_bg_get_inode_table_first_block(bg_ref->block_group, sb); + ext4_fsblk_t first_block = ext4_bg_get_inode_table_first_block(bg, sb); ext4_fsblk_t last_block = first_block + table_blocks - 1; /* Initialization of all itable blocks */ for (fblock = first_block; fblock <= last_block; ++fblock) { - - struct ext4_block block; - int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock); + struct ext4_block b; + int rc = ext4_trans_block_get_noread(bg_ref->fs->bdev, &b, fblock); if (rc != EOK) return rc; - memset(block.data, 0, block_size); - block.dirty = true; + memset(b.data, 0, block_size); + ext4_trans_set_block_dirty(b.buf); - ext4_block_set(bg_ref->fs->bdev, &block); + ext4_block_set(bg_ref->fs->bdev, &b); if (rc != EOK) return rc; } @@ -465,15 +455,13 @@ static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s, uint32_t dsc_per_block) { uint32_t first_meta_bg, dsc_id; - int has_super = 0; - dsc_id = bgid / dsc_per_block; first_meta_bg = ext4_sb_first_meta_bg(s); - if (!ext4_sb_has_feature_incompatible(s, - EXT4_FEATURE_INCOMPAT_META_BG) || - dsc_id < first_meta_bg) + bool meta_bg = ext4_sb_feature_incom(s, EXT4_FINCOM_META_BG); + + if (!meta_bg || dsc_id < first_meta_bg) return ext4_get32(s, first_data_block) + dsc_id + 1; if (ext4_sb_is_super_in_bg(s, bgid)) @@ -482,76 +470,6 @@ static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s, 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 @@ -563,10 +481,9 @@ static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid, { /* 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_has_feature_read_only(sb, - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { + 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; @@ -576,32 +493,32 @@ static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid, bg->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 bgid */ - checksum = ext4_crc32c(checksum, &le32_bgid, - sizeof(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)); + 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_FEATURE_RO_COMPAT_GDT_CSUM)) { + 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); + uint32_t 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)); + crc = ext4_bg_crc16(crc, (uint8_t *)&group, sizeof(group)); /* Compute crc from the first part (stop before checksum field) */ @@ -611,42 +528,122 @@ static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid, offset += sizeof(bg->checksum); /* Checksum of the rest of block group descriptor */ - if ((ext4_sb_has_feature_incompatible( - sb, EXT4_FEATURE_INCOMPAT_64BIT)) && - (offset < ext4_sb_get_desc_size(sb))) + 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); + const uint8_t *start = ((uint8_t *)bg) + offset; + size_t len = ext4_sb_get_desc_size(sb) - offset; + crc = ext4_bg_crc16(crc, start, len); + } } 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 block_size = ext4_sb_get_block_size(&fs->sb); + uint32_t dsc_cnt = block_size / 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_cnt); + + uint32_t offset = (bgid % dsc_cnt) * ext4_sb_get_desc_size(&fs->sb); + + int rc = ext4_trans_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; + struct ext4_bgroup *bg = ref->block_group; + + if (!ext4_fs_verify_bg_csum(&fs->sb, bgid, bg)) { + ext4_dbg(DEBUG_FS, + DBG_WARN "Block group descriptor checksum failed." + "Block group index: %" PRIu32"\n", + bgid); + } + + if (ext4_bg_has_flag(bg, 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(bg, EXT4_BLOCK_GROUP_BLOCK_UNINIT); + ref->dirty = true; + } + + if (ext4_bg_has_flag(bg, 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(bg, EXT4_BLOCK_GROUP_INODE_UNINIT); + + if (!ext4_bg_has_flag(bg, 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(bg, 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 */ if (ref->dirty) { /* Compute new checksum of block group */ - uint16_t checksum = ext4_fs_bg_checksum( - &ref->fs->sb, ref->index, ref->block_group); - - ref->block_group->checksum = to_le16(checksum); + uint16_t cs; + cs = ext4_fs_bg_checksum(&ref->fs->sb, ref->index, + ref->block_group); + ref->block_group->checksum = to_le16(cs); /* Mark block dirty for writing changes to physical device */ - ref->block.dirty = true; + ext4_trans_set_block_dirty(ref->block.buf); } /* Put back block, that contains block group descriptor */ 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_FEATURE_RO_COMPAT_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); @@ -654,40 +651,61 @@ static uint32_t ext4_fs_inode_checksum(struct ext4_inode_ref *inode_ref) 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); + orig_checksum = ext4_inode_get_csum(sb, inode_ref->inode); + ext4_inode_set_csum(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, - sizeof(ino_index)); - checksum = ext4_crc32c(checksum, &ino_gen, - sizeof(ino_gen)); - /* Finally calculate crc32 checksum against + 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); + checksum = ext4_crc32c(checksum, inode_ref->inode, inode_size); + ext4_inode_set_csum(sb, inode_ref->inode, orig_checksum); + + /* If inode size is not large enough to hold the + * upper 16bit of the checksum */ + if (inode_size == EXT4_GOOD_OLD_INODE_SIZE) + checksum &= 0xFFFF; + } 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_FEATURE_RO_COMPAT_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)); + uint32_t csum = ext4_fs_inode_checksum(inode_ref); + ext4_inode_set_csum(sb, inode_ref->inode, csum); } -int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index, - struct ext4_inode_ref *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_csum(sb, inode_ref->inode) == + ext4_fs_inode_checksum(inode_ref); +} +#else +#define ext4_fs_verify_inode_csum(...) true +#endif + +static int +__ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index, + struct ext4_inode_ref *ref, + bool initialized) { /* Compute number of i-nodes, that fits in one data block */ uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group); @@ -727,7 +745,7 @@ int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index, ext4_fsblk_t block_id = inode_table_start + (byte_offset_in_group / block_size); - rc = ext4_block_get(fs->bdev, &ref->block, block_id); + rc = ext4_trans_block_get(fs->bdev, &ref->block, block_id); if (rc != EOK) { return rc; } @@ -741,23 +759,37 @@ int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index, ref->fs = fs; ref->dirty = false; + if (initialized && !ext4_fs_verify_inode_csum(ref)) { + ext4_dbg(DEBUG_FS, + DBG_WARN "Inode checksum failed." + "Inode: %" PRIu32"\n", + ref->index); + } + return EOK; } +int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index, + struct ext4_inode_ref *ref) +{ + return __ext4_fs_get_inode_ref(fs, index, ref, true); +} + int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref) { /* 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; + ext4_trans_set_block_dirty(ref->block.buf); } /* Put back block, that contains i-node */ return ext4_block_set(ref->fs->bdev, &ref->block); } -void ext4_fs_inode_blocks_init(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref) +void ext4_fs_inode_blocks_init(struct ext4_fs *fs, + struct ext4_inode_ref *inode_ref) { int i; struct ext4_inode *inode = inode_ref->inode; @@ -768,8 +800,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_FEATURE_INCOMPAT_EXTENTS)) { + if (ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) { ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS); /* Initialize extent root header */ @@ -778,14 +809,14 @@ void ext4_fs_inode_blocks_init(struct ext4_fs *fs, struct ext4_inode_ref *inode_ #endif } -static uint32_t ext4_fs_correspond_inode_mode(int filetype) +uint32_t ext4_fs_correspond_inode_mode(int filetype) { switch (filetype) { - case EXT4_DIRENTRY_DIR: + case EXT4_DE_DIR: return EXT4_INODE_MODE_DIRECTORY; - case EXT4_DIRENTRY_REG_FILE: + case EXT4_DE_REG_FILE: return EXT4_INODE_MODE_FILE; - case EXT4_DIRENTRY_SYMLINK: + case EXT4_DE_SYMLINK: return EXT4_INODE_MODE_SOFTLINK; default: /* FIXME: right now we only support 3 file type. */ @@ -799,8 +830,9 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, { /* Check if newly allocated i-node will be a directory */ bool is_dir; + uint16_t inode_size = ext4_get16(&fs->sb, inode_size); - is_dir = (filetype == EXT4_DIRENTRY_DIR); + is_dir = (filetype == EXT4_DE_DIR); /* Allocate inode by allocation algorithm */ uint32_t index; @@ -809,7 +841,7 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, return rc; /* Load i-node from on-disk i-node table */ - rc = ext4_fs_get_inode_ref(fs, index, inode_ref); + rc = __ext4_fs_get_inode_ref(fs, index, inode_ref, false); if (rc != EOK) { ext4_ialloc_free_inode(fs, index, is_dir); return rc; @@ -839,17 +871,22 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, } ext4_inode_set_mode(&fs->sb, inode, mode); - ext4_inode_set_links_count(inode, 0); + ext4_inode_set_links_cnt(inode, 0); ext4_inode_set_uid(inode, 0); ext4_inode_set_gid(inode, 0); ext4_inode_set_size(inode, 0); ext4_inode_set_access_time(inode, 0); ext4_inode_set_change_inode_time(inode, 0); - ext4_inode_set_modification_time(inode, 0); - ext4_inode_set_deletion_time(inode, 0); + ext4_inode_set_modif_time(inode, 0); + ext4_inode_set_del_time(inode, 0); ext4_inode_set_blocks_count(&fs->sb, inode, 0); ext4_inode_set_flags(inode, 0); ext4_inode_set_generation(inode, 0); + if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + uint16_t off = offsetof(struct ext4_inode, extra_isize); + uint16_t size = sizeof(struct ext4_inode) - off; + ext4_inode_set_extra_isize(inode, size); + } /* Reset blocks array. For symbolic link inode, just * fill in blocks with 0 */ @@ -857,8 +894,9 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, for (int i = 0; i < EXT4_INODE_BLOCKS; i++) inode->blocks[i] = 0; - } else + } else { ext4_fs_inode_blocks_init(fs, inode_ref); + } inode_ref->dirty = true; @@ -873,8 +911,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_FEATURE_INCOMPAT_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; @@ -900,7 +937,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref) /* 2) Double indirect */ fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1); if (fblock != 0) { - int rc = ext4_block_get(fs->bdev, &block, fblock); + int rc = ext4_trans_block_get(fs->bdev, &block, fblock); if (rc != EOK) return rc; @@ -931,7 +968,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref) fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2); if (fblock == 0) goto finish; - rc = ext4_block_get(fs->bdev, &block, fblock); + rc = ext4_trans_block_get(fs->bdev, &block, fblock); if (rc != EOK) return rc; @@ -941,7 +978,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref) if (ind_block == 0) continue; - rc = ext4_block_get(fs->bdev, &subblock, + rc = ext4_trans_block_get(fs->bdev, &subblock, ind_block); if (rc != EOK) { ext4_block_set(fs->bdev, &block); @@ -1021,8 +1058,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_FEATURE_INCOMPAT_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; @@ -1072,7 +1108,7 @@ static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref, if (current_block == 0) return EOK; - int rc = ext4_block_get(fs->bdev, &block, current_block); + int rc = ext4_trans_block_get(fs->bdev, &block, current_block); if (rc != EOK) return rc; @@ -1082,7 +1118,7 @@ static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref, /* Set zero if physical data block address found */ if (level == 1) { ((uint32_t *)block.data)[offset_in_block] = to_le32(0); - block.dirty = true; + ext4_trans_set_block_dirty(block.buf); } rc = ext4_block_set(fs->bdev, &block); @@ -1116,6 +1152,7 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) { struct ext4_sblock *sb = &inode_ref->fs->sb; uint32_t i; + int r; /* Check flags, if i-node can be truncated */ if (!ext4_inode_can_truncate(sb, inode_ref->inode)) @@ -1130,12 +1167,12 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) if (old_size < new_size) return EINVAL; - if (ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK) - && old_size < sizeof(inode_ref->inode->blocks) - && !ext4_inode_get_blocks_count(sb, inode_ref->inode)) { - char *content = (char *)inode_ref->inode->blocks; - memset(content + new_size, 0, - sizeof(inode_ref->inode->blocks) - new_size); + bool v; + v = ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK); + if (v && old_size < sizeof(inode_ref->inode->blocks) && + !ext4_inode_get_blocks_count(sb, inode_ref->inode)) { + char *content = (char *)inode_ref->inode->blocks + new_size; + memset(content , 0, sizeof(inode_ref->inode->blocks) - new_size); ext4_inode_set_size(inode_ref->inode, new_size); inode_ref->dirty = true; @@ -1144,22 +1181,19 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) /* Compute how many blocks will be released */ uint32_t block_size = ext4_sb_get_block_size(sb); - uint32_t new_blocks_count = (new_size + block_size - 1) / - block_size; - uint32_t old_blocks_count = (old_size + block_size - 1) / - block_size; - uint32_t diff_blocks_count = old_blocks_count - new_blocks_count; + uint32_t new_blocks_cnt = (new_size + block_size - 1) / block_size; + uint32_t old_blocks_cnt = (old_size + block_size - 1) / block_size; + uint32_t diff_blocks_cnt = old_blocks_cnt - new_blocks_cnt; #if CONFIG_EXTENT_ENABLE - if ((ext4_sb_has_feature_incompatible(sb, - EXT4_FEATURE_INCOMPAT_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 */ - if (diff_blocks_count) { - int rc = ext4_extent_remove_space(inode_ref, - new_blocks_count, EXT_MAX_BLOCKS); - if (rc != EOK) - return rc; + if (diff_blocks_cnt) { + r = ext4_extent_remove_space(inode_ref, new_blocks_cnt, + EXT_MAX_BLOCKS); + if (r != EOK) + return r; } } else @@ -1169,11 +1203,11 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) /* Starting from 1 because of logical blocks are numbered from 0 */ - for (i = 0; i < diff_blocks_count; ++i) { - int rc = ext4_fs_release_inode_block( - inode_ref, new_blocks_count + i); - if (rc != EOK) - return rc; + for (i = 0; i < diff_blocks_cnt; ++i) { + r = ext4_fs_release_inode_block(inode_ref, + new_blocks_cnt + i); + if (r != EOK) + return r; } } @@ -1190,9 +1224,8 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) */ ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref) { - uint32_t group_inodes = - ext4_get32(&inode_ref->fs->sb, inodes_per_group); - return (inode_ref->index - 1) / group_inodes; + uint32_t grp_inodes = ext4_get32(&inode_ref->fs->sb, inodes_per_group); + return (inode_ref->index - 1) / grp_inodes; } /**@brief Compute 'goal' for allocation algorithm (For blockmap). @@ -1201,28 +1234,29 @@ ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref) * @return error code */ int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref, - ext4_fsblk_t *goal) + ext4_fsblk_t *goal) { + int r; struct ext4_sblock *sb = &inode_ref->fs->sb; *goal = 0; uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); uint32_t block_size = ext4_sb_get_block_size(sb); - uint32_t inode_block_count = inode_size / block_size; + uint32_t iblock_cnt = inode_size / block_size; if (inode_size % block_size != 0) - inode_block_count++; + iblock_cnt++; /* If inode has some blocks, get last block address + 1 */ - if (inode_block_count > 0) { - int rc = ext4_fs_get_inode_data_block_index( - inode_ref, inode_block_count - 1, goal, false); - if (rc != EOK) - return rc; + if (iblock_cnt > 0) { + r = ext4_fs_get_inode_dblk_idx(inode_ref, iblock_cnt - 1, + goal, false); + if (r != EOK) + return r; if (*goal != 0) { (*goal)++; - return rc; + return r; } /* If goal == 0, sparse file -> continue */ @@ -1230,51 +1264,49 @@ int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref, /* Identify block group of inode */ - uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group); - uint32_t block_group = (inode_ref->index - 1) / inodes_per_group; + uint32_t inodes_per_bg = ext4_get32(sb, inodes_per_group); + uint32_t block_group = (inode_ref->index - 1) / inodes_per_bg; block_size = ext4_sb_get_block_size(sb); /* Load block group reference */ struct ext4_block_group_ref bg_ref; - int rc = - ext4_fs_get_block_group_ref(inode_ref->fs, block_group, &bg_ref); - if (rc != EOK) - return rc; + r = ext4_fs_get_block_group_ref(inode_ref->fs, block_group, &bg_ref); + if (r != EOK) + return r; + + struct ext4_bgroup *bg = bg_ref.block_group; /* Compute indexes */ - uint32_t block_group_count = ext4_block_group_cnt(sb); - ext4_fsblk_t inode_table_first_block = - ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb); - uint16_t inode_table_item_size = ext4_get16(sb, inode_size); - uint32_t inode_table_bytes; + uint32_t bg_count = ext4_block_group_cnt(sb); + ext4_fsblk_t itab_first_block = ext4_bg_get_inode_table_first_block(bg, sb); + uint16_t itab_item_size = ext4_get16(sb, inode_size); + uint32_t itab_bytes; /* Check for last block group */ - if (block_group < block_group_count - 1) { - inode_table_bytes = inodes_per_group * inode_table_item_size; + if (block_group < bg_count - 1) { + itab_bytes = inodes_per_bg * itab_item_size; } else { /* Last block group could be smaller */ - uint32_t inodes_count_total = ext4_get32(sb, inodes_count); + uint32_t inodes_cnt = ext4_get32(sb, inodes_count); - inode_table_bytes = - (inodes_count_total - - ((block_group_count - 1) * inodes_per_group)) * - inode_table_item_size; + itab_bytes = (inodes_cnt - ((bg_count - 1) * inodes_per_bg)); + itab_bytes *= itab_item_size; } - ext4_fsblk_t inode_table_blocks = inode_table_bytes / block_size; + ext4_fsblk_t inode_table_blocks = itab_bytes / block_size; - if (inode_table_bytes % block_size) + if (itab_bytes % block_size) inode_table_blocks++; - *goal = inode_table_first_block + inode_table_blocks; + *goal = itab_first_block + inode_table_blocks; return ext4_fs_put_block_group_ref(&bg_ref); } -static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref, +static int ext4_fs_get_inode_dblk_idx_internal(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; @@ -1289,13 +1321,12 @@ 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_FEATURE_INCOMPAT_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; int rc = ext4_extent_get_blocks(inode_ref, iblock, 1, - ¤t_fsblk, extent_create, NULL); + ¤t_fsblk, extent_create, NULL); if (rc != EOK) return rc; @@ -1318,24 +1349,22 @@ static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref, } /* Determine indirection level of the target block */ - unsigned int level = 0; + unsigned int l = 0; unsigned int i; for (i = 1; i < 4; i++) { if (iblock < fs->inode_block_limits[i]) { - level = i; + l = i; break; } } - if (level == 0) + if (l == 0) return EIO; /* Compute offsets for the topmost level */ - uint64_t block_offset_in_level = - iblock - fs->inode_block_limits[level - 1]; - current_block = ext4_inode_get_indirect_block(inode, level - 1); - uint32_t offset_in_block = - block_offset_in_level / fs->inode_blocks_per_level[level - 1]; + uint64_t blk_off_in_lvl = iblock - fs->inode_block_limits[l - 1]; + current_block = ext4_inode_get_indirect_block(inode, l - 1); + uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]; /* Sparse file */ if (current_block == 0) { @@ -1349,15 +1378,15 @@ static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref, * Navigate through other levels, until we find the block number * or find null reference meaning we are dealing with sparse file */ - while (level > 0) { + while (l > 0) { /* Load indirect block */ - int rc = ext4_block_get(fs->bdev, &block, current_block); + int rc = ext4_trans_block_get(fs->bdev, &block, current_block); if (rc != EOK) return rc; /* Read block address from indirect block */ current_block = - to_le32(((uint32_t *)block.data)[offset_in_block]); + to_le32(((uint32_t *)block.data)[off_in_blk]); /* Put back indirect block untouched */ rc = ext4_block_set(fs->bdev, &block); @@ -1371,17 +1400,16 @@ static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref, } /* Jump to the next level */ - level--; + l--; /* Termination condition - we have address of data block loaded */ - if (level == 0) + if (l == 0) break; /* Visit the next level */ - block_offset_in_level %= fs->inode_blocks_per_level[level]; - offset_in_block = block_offset_in_level / - fs->inode_blocks_per_level[level - 1]; + blk_off_in_lvl %= fs->inode_blocks_per_level[l]; + off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]; } *fblock = current_block; @@ -1390,19 +1418,19 @@ static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref, } -int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref, - uint64_t iblock, ext4_fsblk_t *fblock, - bool support_unwritten) +int ext4_fs_get_inode_dblk_idx(struct ext4_inode_ref *inode_ref, + uint64_t iblock, ext4_fsblk_t *fblock, + bool support_unwritten) { - return ext4_fs_get_inode_data_block_idx(inode_ref, iblock, fblock, - false, support_unwritten); + return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock, + false, support_unwritten); } -int ext4_fs_init_inode_data_block_index(struct ext4_inode_ref *inode_ref, - uint64_t iblock, ext4_fsblk_t *fblock) +int ext4_fs_init_inode_dblk_idx(struct ext4_inode_ref *inode_ref, + uint64_t iblock, ext4_fsblk_t *fblock) { - return ext4_fs_get_inode_data_block_idx(inode_ref, iblock, fblock, - true, true); + return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock, + true, true); } static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, @@ -1412,8 +1440,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_FEATURE_INCOMPAT_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; @@ -1430,29 +1457,27 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, } /* Determine the indirection level needed to get the desired block */ - unsigned int level = 0; + unsigned int l = 0; unsigned int i; for (i = 1; i < 4; i++) { if (iblock < fs->inode_block_limits[i]) { - level = i; + l = i; break; } } - if (level == 0) + if (l == 0) return EIO; uint32_t block_size = ext4_sb_get_block_size(&fs->sb); /* Compute offsets for the topmost level */ - uint64_t block_offset_in_level = - iblock - fs->inode_block_limits[level - 1]; + uint64_t blk_off_in_lvl = iblock - fs->inode_block_limits[l - 1]; ext4_fsblk_t current_block = - ext4_inode_get_indirect_block(inode_ref->inode, level - 1); - uint32_t offset_in_block = - block_offset_in_level / fs->inode_blocks_per_level[level - 1]; + ext4_inode_get_indirect_block(inode_ref->inode, l - 1); + uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]; - ext4_fsblk_t new_block_addr; + ext4_fsblk_t new_blk; struct ext4_block block; struct ext4_block new_block; @@ -1465,49 +1490,44 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, if (rc != EOK) return rc; - rc = ext4_balloc_alloc_block(inode_ref, - goal, - &new_block_addr); + rc = ext4_balloc_alloc_block(inode_ref, goal, &new_blk); if (rc != EOK) return rc; /* Update i-node */ - ext4_inode_set_indirect_block(inode_ref->inode, level - 1, - (uint32_t)new_block_addr); + ext4_inode_set_indirect_block(inode_ref->inode, l - 1, new_blk); inode_ref->dirty = true; /* Load newly allocated block */ - rc = ext4_block_get(fs->bdev, &new_block, new_block_addr); + rc = ext4_trans_block_get_noread(fs->bdev, &new_block, new_blk); if (rc != EOK) { - ext4_balloc_free_block(inode_ref, new_block_addr); + ext4_balloc_free_block(inode_ref, new_blk); return rc; } /* Initialize new block */ memset(new_block.data, 0, block_size); - new_block.dirty = true; + ext4_trans_set_block_dirty(new_block.buf); /* Put back the allocated block */ rc = ext4_block_set(fs->bdev, &new_block); if (rc != EOK) return rc; - current_block = new_block_addr; + current_block = new_blk; } /* * Navigate through other levels, until we find the block number * or find null reference meaning we are dealing with sparse file */ - while (level > 0) { - int rc = ext4_block_get(fs->bdev, &block, current_block); + while (l > 0) { + int rc = ext4_trans_block_get(fs->bdev, &block, current_block); if (rc != EOK) return rc; - current_block = - to_le32(((uint32_t *)block.data)[offset_in_block]); - - if ((level > 1) && (current_block == 0)) { + current_block = to_le32(((uint32_t *)block.data)[off_in_blk]); + if ((l > 1) && (current_block == 0)) { ext4_fsblk_t goal; rc = ext4_fs_indirect_find_goal(inode_ref, &goal); if (rc != EOK) { @@ -1517,15 +1537,15 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, /* Allocate new block */ rc = - ext4_balloc_alloc_block(inode_ref, goal, &new_block_addr); + ext4_balloc_alloc_block(inode_ref, goal, &new_blk); if (rc != EOK) { ext4_block_set(fs->bdev, &block); return rc; } /* Load newly allocated block */ - rc = ext4_block_get(fs->bdev, &new_block, - new_block_addr); + rc = ext4_trans_block_get_noread(fs->bdev, &new_block, + new_blk); if (rc != EOK) { ext4_block_set(fs->bdev, &block); @@ -1534,7 +1554,7 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, /* Initialize allocated block */ memset(new_block.data, 0, block_size); - new_block.dirty = true; + ext4_trans_set_block_dirty(new_block.buf); rc = ext4_block_set(fs->bdev, &new_block); if (rc != EOK) { @@ -1543,67 +1563,62 @@ static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref, } /* Write block address to the parent */ - ((uint32_t *)block.data)[offset_in_block] = - to_le32((uint32_t)new_block_addr); - block.dirty = true; - current_block = new_block_addr; + uint32_t * p = (uint32_t * )block.data; + p[off_in_blk] = to_le32((uint32_t)new_blk); + ext4_trans_set_block_dirty(block.buf); + current_block = new_blk; } /* Will be finished, write the fblock address */ - if (level == 1) { - ((uint32_t *)block.data)[offset_in_block] = - to_le32((uint32_t)fblock); - block.dirty = true; + if (l == 1) { + uint32_t * p = (uint32_t * )block.data; + p[off_in_blk] = to_le32((uint32_t)fblock); + ext4_trans_set_block_dirty(block.buf); } rc = ext4_block_set(fs->bdev, &block); if (rc != EOK) return rc; - level--; + l--; /* * If we are on the last level, break here as * there is no next level to visit */ - if (level == 0) + if (l == 0) break; /* Visit the next level */ - block_offset_in_level %= fs->inode_blocks_per_level[level]; - offset_in_block = block_offset_in_level / - fs->inode_blocks_per_level[level - 1]; + blk_off_in_lvl %= fs->inode_blocks_per_level[l]; + off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]; } return EOK; } -int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref, - ext4_fsblk_t *fblock, uint32_t *iblock) +int ext4_fs_append_inode_dblk(struct ext4_inode_ref *inode_ref, + ext4_fsblk_t *fblock, uint32_t *iblock) { #if CONFIG_EXTENT_ENABLE /* Handle extents separately */ - if ((ext4_sb_has_feature_incompatible(&inode_ref->fs->sb, - EXT4_FEATURE_INCOMPAT_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; struct ext4_sblock *sb = &inode_ref->fs->sb; uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); uint32_t block_size = ext4_sb_get_block_size(sb); - *iblock = (inode_size + block_size - 1) / - block_size; + *iblock = (inode_size + block_size - 1) / block_size; rc = ext4_extent_get_blocks(inode_ref, *iblock, 1, - ¤t_fsblk, true, NULL); - + ¤t_fsblk, true, NULL); *fblock = current_fsblk; ext4_assert(*fblock); - ext4_inode_set_size(inode_ref->inode, - inode_size + block_size); + ext4_inode_set_size(inode_ref->inode, inode_size + block_size); inode_ref->dirty = true; @@ -1654,23 +1669,21 @@ int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref, void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref) { uint16_t link; - - link = ext4_inode_get_links_count(inode_ref->inode); + bool is_dx; + link = ext4_inode_get_links_cnt(inode_ref->inode); link++; - ext4_inode_set_links_count(inode_ref->inode, link); + ext4_inode_set_links_cnt(inode_ref->inode, link); - bool is_dx = - ext4_sb_has_feature_compatible(&inode_ref->fs->sb, - EXT4_FEATURE_COMPAT_DIR_INDEX) && - ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX); + is_dx = 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) { if (link >= EXT4_LINK_MAX || link == 2) { - ext4_inode_set_links_count(inode_ref->inode, 1); + ext4_inode_set_links_cnt(inode_ref->inode, 1); - uint32_t v = - ext4_get32(&inode_ref->fs->sb, features_read_only); - v |= EXT4_FEATURE_RO_COMPAT_DIR_NLINK; + uint32_t v; + v = ext4_get32(&inode_ref->fs->sb, features_read_only); + v |= EXT4_FRO_COM_DIR_NLINK; ext4_set32(&inode_ref->fs->sb, features_read_only, v); } } @@ -1678,16 +1691,16 @@ void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref) void ext4_fs_inode_links_count_dec(struct ext4_inode_ref *inode_ref) { - uint16_t links = ext4_inode_get_links_count(inode_ref->inode); + uint16_t links = ext4_inode_get_links_cnt(inode_ref->inode); if (!ext4_inode_is_type(&inode_ref->fs->sb, inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) { if (links > 0) - ext4_inode_set_links_count(inode_ref->inode, links - 1); + ext4_inode_set_links_cnt(inode_ref->inode, links - 1); return; } if (links > 2) - ext4_inode_set_links_count(inode_ref->inode, links - 1); + ext4_inode_set_links_cnt(inode_ref->inode, links - 1); } /**