ext4_debug: eliminate warning messages when assert is disabled.
[lwext4.git] / lwext4 / ext4_fs.c
index 28102d1075a9540cedf63deac83f13d3605de327..1d807f2821dd002814e71eeef404c990d783dfba 100644 (file)
@@ -44,6 +44,7 @@
 #include "ext4_errno.h"
 #include "ext4_blockdev.h"
 #include "ext4_super.h"
+#include "ext4_crc32.h"
 #include "ext4_debug.h"
 #include "ext4_block_group.h"
 #include "ext4_balloc.h"
@@ -98,9 +99,10 @@ int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
 
        /*Validate FS*/
        tmp = ext4_get16(&fs->sb, state);
-       if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
-               ext4_dprintf(EXT4_DEBUG_FS, "last umount error\n");
-       }
+       if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS)
+               ext4_dbg(DEBUG_FS, DBG_WARN
+                               "last umount error: superblock fs_error flag\n");
+
 
        /* Mark system as mounted */
        ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
@@ -124,106 +126,75 @@ int ext4_fs_fini(struct ext4_fs *fs)
        return ext4_sb_write(fs->bdev, &fs->sb);
 }
 
-static void ext4_fs_debug_features_incomp(uint32_t features_incompatible)
+static void ext4_fs_debug_features_inc(uint32_t features_incompatible)
 {
-
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_COMPRESSION) {
-               ext4_dprintf(EXT4_DEBUG_FS, "compression\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_FILETYPE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "filetype\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_RECOVER) {
-               ext4_dprintf(EXT4_DEBUG_FS, "recover\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_JOURNAL_DEV) {
-               ext4_dprintf(EXT4_DEBUG_FS, "journal_dev\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_META_BG) {
-               ext4_dprintf(EXT4_DEBUG_FS, "meta_bg\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_EXTENTS) {
-               ext4_dprintf(EXT4_DEBUG_FS, "extents\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_64BIT) {
-               ext4_dprintf(EXT4_DEBUG_FS, "64bit\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_MMP) {
-               ext4_dprintf(EXT4_DEBUG_FS, "mnp\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
-               ext4_dprintf(EXT4_DEBUG_FS, "flex_bg\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_EA_INODE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "ea_inode\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_DIRDATA) {
-               ext4_dprintf(EXT4_DEBUG_FS, "dirdata\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM) {
-               ext4_dprintf(EXT4_DEBUG_FS, "meta_csum\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_LARGEDIR) {
-               ext4_dprintf(EXT4_DEBUG_FS, "largedir\n");
-       }
-       if (features_incompatible & EXT4_FEATURE_INCOMPAT_INLINE_DATA) {
-               ext4_dprintf(EXT4_DEBUG_FS, "inline_data\n");
-       }
+       if (features_incompatible & EXT4_FINCOM_COMPRESSION)
+               ext4_dbg(DEBUG_FS, DBG_NONE "compression\n");
+       if (features_incompatible & EXT4_FINCOM_FILETYPE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "filetype\n");
+       if (features_incompatible & EXT4_FINCOM_RECOVER)
+               ext4_dbg(DEBUG_FS, DBG_NONE "recover\n");
+       if (features_incompatible & EXT4_FINCOM_JOURNAL_DEV)
+               ext4_dbg(DEBUG_FS, DBG_NONE "journal_dev\n");
+       if (features_incompatible & EXT4_FINCOM_META_BG)
+               ext4_dbg(DEBUG_FS, DBG_NONE "meta_bg\n");
+       if (features_incompatible & EXT4_FINCOM_EXTENTS)
+               ext4_dbg(DEBUG_FS, DBG_NONE "extents\n");
+       if (features_incompatible & EXT4_FINCOM_64BIT)
+               ext4_dbg(DEBUG_FS, DBG_NONE "64bit\n");
+       if (features_incompatible & EXT4_FINCOM_MMP)
+               ext4_dbg(DEBUG_FS, DBG_NONE "mnp\n");
+       if (features_incompatible & EXT4_FINCOM_FLEX_BG)
+               ext4_dbg(DEBUG_FS, DBG_NONE "flex_bg\n");
+       if (features_incompatible & EXT4_FINCOM_EA_INODE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "ea_inode\n");
+       if (features_incompatible & EXT4_FINCOM_DIRDATA)
+               ext4_dbg(DEBUG_FS, DBG_NONE "dirdata\n");
+       if (features_incompatible & EXT4_FINCOM_BG_USE_META_CSUM)
+               ext4_dbg(DEBUG_FS, DBG_NONE "meta_csum\n");
+       if (features_incompatible & EXT4_FINCOM_LARGEDIR)
+               ext4_dbg(DEBUG_FS, DBG_NONE "largedir\n");
+       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) {
-               ext4_dprintf(EXT4_DEBUG_FS, " dir_prealloc\n");
-       }
-       if (features_compatible & EXT4_FEATURE_COMPAT_IMAGIC_INODES) {
-               ext4_dprintf(EXT4_DEBUG_FS, "imagic_inodes\n");
-       }
-       if (features_compatible & EXT4_FEATURE_COMPAT_HAS_JOURNAL) {
-               ext4_dprintf(EXT4_DEBUG_FS, "has_journal\n");
-       }
-       if (features_compatible & EXT4_FEATURE_COMPAT_EXT_ATTR) {
-               ext4_dprintf(EXT4_DEBUG_FS, "ext_attr\n");
-       }
-       if (features_compatible & EXT4_FEATURE_COMPAT_RESIZE_INODE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "resize_inode\n");
-       }
-       if (features_compatible & EXT4_FEATURE_COMPAT_DIR_INDEX) {
-               ext4_dprintf(EXT4_DEBUG_FS, "dir_index\n");
-       }
+       if (features_compatible & EXT4_FCOM_DIR_PREALLOC)
+               ext4_dbg(DEBUG_FS, DBG_NONE "dir_prealloc\n");
+       if (features_compatible & EXT4_FCOM_IMAGIC_INODES)
+               ext4_dbg(DEBUG_FS, DBG_NONE "imagic_inodes\n");
+       if (features_compatible & EXT4_FCOM_HAS_JOURNAL)
+               ext4_dbg(DEBUG_FS, DBG_NONE "has_journal\n");
+       if (features_compatible & EXT4_FCOM_EXT_ATTR)
+               ext4_dbg(DEBUG_FS, DBG_NONE "ext_attr\n");
+       if (features_compatible & EXT4_FCOM_RESIZE_INODE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "resize_inode\n");
+       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) {
-               ext4_dprintf(EXT4_DEBUG_FS, "sparse_super\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_LARGE_FILE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "large_file\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_BTREE_DIR) {
-               ext4_dprintf(EXT4_DEBUG_FS, "btree_dir\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "huge_file\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
-               ext4_dprintf(EXT4_DEBUG_FS, "gtd_csum\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) {
-               ext4_dprintf(EXT4_DEBUG_FS, "dir_nlink\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) {
-               ext4_dprintf(EXT4_DEBUG_FS, "extra_isize\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_QUOTA) {
-               ext4_dprintf(EXT4_DEBUG_FS, "quota\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_BIGALLOC) {
-               ext4_dprintf(EXT4_DEBUG_FS, "bigalloc\n");
-       }
-       if (features_ro & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
-               ext4_dprintf(EXT4_DEBUG_FS, "metadata_csum\n");
-       }
+       if (features_ro & EXT4_FRO_COM_SPARSE_SUPER)
+               ext4_dbg(DEBUG_FS, DBG_NONE "sparse_super\n");
+       if (features_ro & EXT4_FRO_COM_LARGE_FILE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "large_file\n");
+       if (features_ro & EXT4_FRO_COM_BTREE_DIR)
+               ext4_dbg(DEBUG_FS, DBG_NONE "btree_dir\n");
+       if (features_ro & EXT4_FRO_COM_HUGE_FILE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "huge_file\n");
+       if (features_ro & EXT4_FRO_COM_GDT_CSUM)
+               ext4_dbg(DEBUG_FS, DBG_NONE "gtd_csum\n");
+       if (features_ro & EXT4_FRO_COM_DIR_NLINK)
+               ext4_dbg(DEBUG_FS, DBG_NONE "dir_nlink\n");
+       if (features_ro & EXT4_FRO_COM_EXTRA_ISIZE)
+               ext4_dbg(DEBUG_FS, DBG_NONE "extra_isize\n");
+       if (features_ro & EXT4_FRO_COM_QUOTA)
+               ext4_dbg(DEBUG_FS, DBG_NONE "quota\n");
+       if (features_ro & EXT4_FRO_COM_BIGALLOC)
+               ext4_dbg(DEBUG_FS, DBG_NONE "bigalloc\n");
+       if (features_ro & EXT4_FRO_COM_METADATA_CSUM)
+               ext4_dbg(DEBUG_FS, DBG_NONE "metadata_csum\n");
 }
 
 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
@@ -235,34 +206,32 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
                return EOK;
        }
 
-       ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_incompatible:\n");
-       ext4_fs_debug_features_incomp(
-           ext4_get32(&fs->sb, features_incompatible));
+       ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_incompatible:\n");
+       ext4_fs_debug_features_inc(ext4_get32(&fs->sb, features_incompatible));
 
-       ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_compatible:\n");
+       ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_compatible:\n");
        ext4_fs_debug_features_comp(ext4_get32(&fs->sb, features_compatible));
 
-       ext4_dprintf(EXT4_DEBUG_FS, "\nSB features_read_only:\n");
+       ext4_dbg(DEBUG_FS, DBG_INFO "sblock features_read_only:\n");
        ext4_fs_debug_features_ro(ext4_get32(&fs->sb, features_read_only));
 
        /*Check features_incompatible*/
        v = (ext4_get32(&fs->sb, features_incompatible) &
-            (~CONFIG_FEATURE_INCOMPAT_SUPP));
+            (~CONFIG_SUPPORTED_FINCOM));
        if (v) {
-               ext4_dprintf(EXT4_DEBUG_FS, "SB features_incompatible: fail\n");
-               ext4_fs_debug_features_incomp(v);
+               ext4_dbg(DEBUG_FS, DBG_ERROR
+                               "sblock has unsupported features incompatible:\n");
+               ext4_fs_debug_features_inc(v);
                return ENOTSUP;
        }
 
        /*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_dprintf(
-                   EXT4_DEBUG_FS,
-                   "\nERROR sblock features_read_only . Unsupported:\n");
-               ext4_fs_debug_features_incomp(v);
-
+               ext4_dbg(DEBUG_FS, DBG_WARN
+                       "sblock has unsupported features read only:\n");
+               ext4_fs_debug_features_ro(v);
                *read_only = true;
                return EOK;
        }
@@ -271,39 +240,126 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
        return EOK;
 }
 
+/**@brief Determine whether the block is inside the group.
+ * @param baddr   block address
+ * @param bgid    block group id
+ * @return Error code
+ */
+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 true;
+       return false;
+}
+
+/**@brief   To avoid calling the atomic setbit hundreds or thousands of times, we only
+ *          need to use it within a single byte (to ensure we get endianness right).
+ *          We can use memset for the rest of the bitmap as there are no other users.
+ */
+static void ext4_fs_mark_bitmap_end(int start_bit, int end_bit, void *bitmap)
+{
+       int i;
+
+       if (start_bit >= end_bit)
+               return;
+
+       for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
+               ext4_bmap_bit_set(bitmap, i);
+
+       if (i < end_bit)
+               memset((char *)bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
+}
+
 /**@brief Initialize block bitmap in block group.
  * @param bg_ref Reference to block group
  * @return Error code
  */
 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
 {
-       uint32_t i;
-       uint32_t bitmap_block_addr =
-           ext4_bg_get_block_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
+       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(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, ext4_sb_get_block_size(&bg_ref->fs->sb));
+       memset(block_bitmap.data, 0, block_size);
+       bit_max = ext4_sb_is_super_in_bg(sb, bg_ref->index);
+
+       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(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(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(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(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(sb, blocks_per_group);
+       }
 
-       /* Determine first block and first data block in group */
-       uint32_t first_idx = 0;
+       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);
 
-       uint32_t first_data =
-           ext4_balloc_get_first_data_block_in_group(&bg_ref->fs->sb, bg_ref);
-       uint32_t first_data_idx =
-           ext4_fs_baddr2_index_in_group(&bg_ref->fs->sb, first_data);
+       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);
 
-       /*Set bits from to first block to first data block - 1 to one
-        * (allocated)*/
-       /*TODO: Optimize it*/
-       for (i = first_idx; i < first_data_idx; ++i)
-               ext4_bmap_bit_set(block_bitmap.data, i);
+        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
+         * less than the blocksize * 8 ( which is the size
+         * of bitmap ), set rest of the block bitmap to 1
+         */
+        ext4_fs_mark_bitmap_end(group_blocks, block_size * 8, block_bitmap.data);
+       ext4_trans_set_block_dirty(block_bitmap.buf);
 
-       block_bitmap.dirty = true;
+       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);
@@ -315,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 */
-       uint32_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);
 
-       block_bitmap.dirty = true;
+       ext4_trans_set_block_dirty(b.buf);
+
+       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.
@@ -355,35 +415,34 @@ 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);
        uint32_t inodes_per_block = block_size / inode_size;
        uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
        uint32_t table_blocks = inodes_in_group / inodes_per_block;
-       uint32_t fblock;
+       ext4_fsblk_t fblock;
 
        if (inodes_in_group % inodes_per_block)
                table_blocks++;
 
        /* Compute initialization bounds */
-       uint32_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);
 
-       uint32_t last_block = first_block + table_blocks - 1;
+       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;
        }
@@ -391,20 +450,18 @@ static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
        return EOK;
 }
 
-static uint64_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
+static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
                                             uint32_t bgid,
                                             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))
@@ -413,22 +470,103 @@ static uint64_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 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 *)&group, sizeof(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))) {
+
+                       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 dsc_per_block =
-           ext4_sb_get_block_size(&fs->sb) / ext4_sb_get_desc_size(&fs->sb);
+       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_per_block);
+       uint64_t block_id = ext4_fs_get_descriptor_block(&fs->sb, bgid, dsc_cnt);
 
-       uint32_t offset =
-           (bgid % dsc_per_block) * ext4_sb_get_desc_size(&fs->sb);
+       uint32_t offset = (bgid % dsc_cnt) * ext4_sb_get_desc_size(&fs->sb);
 
-       int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+       int rc = ext4_trans_block_get(fs->bdev, &ref->block, block_id);
        if (rc != EOK)
                return rc;
 
@@ -436,39 +574,42 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
        ref->fs = fs;
        ref->index = bgid;
        ref->dirty = false;
+       struct ext4_bgroup *bg = ref->block_group;
 
-       if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
+       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(ref->block_group,
-                                  EXT4_BLOCK_GROUP_BLOCK_UNINIT);
-
+               ext4_bg_clear_flag(bg, EXT4_BLOCK_GROUP_BLOCK_UNINIT);
                ref->dirty = true;
        }
 
-       if (ext4_bg_has_flag(ref->block_group, EXT4_BLOCK_GROUP_INODE_UNINIT)) {
+       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(ref->block_group,
-                                  EXT4_BLOCK_GROUP_INODE_UNINIT);
+               ext4_bg_clear_flag(bg, EXT4_BLOCK_GROUP_INODE_UNINIT);
 
-               if (!ext4_bg_has_flag(ref->block_group,
-                                     EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+               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(ref->block_group,
-                                        EXT4_BLOCK_GROUP_ITABLE_ZEROED);
+                       ext4_bg_set_flag(bg, EXT4_BLOCK_GROUP_ITABLE_ZEROED);
                }
 
                ref->dirty = true;
@@ -477,74 +618,94 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
        return EOK;
 }
 
-/**@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_FEATURE_RO_COMPAT_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_FEATURE_INCOMPAT_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 */
        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);
 }
 
-int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
-                         struct ext4_inode_ref *ref)
+#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_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
+               uint32_t orig_checksum;
+
+               uint32_t ino_index = to_le32(inode_ref->index);
+               uint32_t ino_gen =
+                       to_le32(ext4_inode_get_generation(inode_ref->inode));
+
+               /* Preparation: temporarily set bg checksum to 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(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
+                * the entire inode */
+               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_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
+               return;
+
+       uint32_t csum = ext4_fs_inode_checksum(inode_ref);
+       ext4_inode_set_csum(sb, inode_ref->inode, csum);
+}
+
+#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);
@@ -581,10 +742,10 @@ int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
        uint32_t byte_offset_in_group = offset_in_group * inode_size;
 
        /* Compute block address */
-       uint64_t block_id =
+       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;
        }
@@ -598,29 +759,80 @@ 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 */
-               ref->block.dirty = true;
+               ext4_fs_set_inode_checksum(ref);
+               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)
+{
+       int i;
+       struct ext4_inode *inode = inode_ref->inode;
+
+       for (i = 0; i < EXT4_INODE_BLOCKS; i++)
+               inode->blocks[i] = 0;
+
+       (void)fs;
+#if CONFIG_EXTENT_ENABLE
+       /* Initialize extents if needed */
+       if (ext4_sb_feature_incom(&fs->sb, EXT4_FINCOM_EXTENTS)) {
+               ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
+
+               /* Initialize extent root header */
+               ext4_extent_tree_init(inode_ref);
+       }
+#endif
+}
+
+uint32_t ext4_fs_correspond_inode_mode(int filetype)
+{
+       switch (filetype) {
+       case EXT4_DE_DIR:
+               return EXT4_INODE_MODE_DIRECTORY;
+       case EXT4_DE_REG_FILE:
+               return EXT4_INODE_MODE_FILE;
+       case EXT4_DE_SYMLINK:
+               return EXT4_INODE_MODE_SOFTLINK;
+       default:
+               /* FIXME: right now we only support 3 file type. */
+               ext4_assert(0);
+       }
+       return 0;
+}
+
 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
-                       bool is_directory)
+                       int filetype)
 {
        /* Check if newly allocated i-node will be a directory */
-       uint32_t i;
        bool is_dir;
+       uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
 
-       is_dir = is_directory;
+       is_dir = (filetype == EXT4_DE_DIR);
 
        /* Allocate inode by allocation algorithm */
        uint32_t index;
@@ -629,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;
@@ -638,7 +850,7 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
        /* Initialize i-node */
        struct ext4_inode *inode = inode_ref->inode;
 
-       uint16_t mode;
+       uint32_t mode;
        if (is_dir) {
                /*
                 * Default directory permissions to be compatible with other
@@ -648,7 +860,6 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
 
                mode = 0777;
                mode |= EXT4_INODE_MODE_DIRECTORY;
-               ext4_inode_set_mode(&fs->sb, inode, mode);
        } else {
                /*
                 * Default file permissions to be compatible with other systems
@@ -656,47 +867,36 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
                 */
 
                mode = 0666;
-               mode |= EXT4_INODE_MODE_FILE;
-               ext4_inode_set_mode(&fs->sb, inode, mode);
+               mode |= ext4_fs_correspond_inode_mode(filetype);
        }
+       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 (i = 0; i < EXT4_INODE_BLOCKS; i++)
-               inode->blocks[i] = 0;
-
-#if CONFIG_EXTENT_ENABLE
-       /* Initialize extents if needed */
-       if (ext4_sb_has_feature_incompatible(&fs->sb,
-                                            EXT4_FEATURE_INCOMPAT_EXTENTS)) {
-               ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
+       /* Reset blocks array. For symbolic link inode, just
+        * fill in blocks with 0 */
+       if (ext4_inode_is_type(&fs->sb, inode, EXT4_INODE_MODE_SOFTLINK)) {
+               for (int i = 0; i < EXT4_INODE_BLOCKS; i++)
+                       inode->blocks[i] = 0;
 
-               /* Initialize extent root header */
-               struct ext4_extent_header *header =
-                   ext4_inode_get_extent_header(inode);
-               ext4_extent_header_set_depth(header, 0);
-               ext4_extent_header_set_entries_count(header, 0);
-               ext4_extent_header_set_generation(header, 0);
-               ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
-
-               uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
-                                       sizeof(struct ext4_extent_header)) /
-                                      sizeof(struct ext4_extent);
-
-               ext4_extent_header_set_max_entries_count(header, max_entries);
+       } else {
+               ext4_fs_inode_blocks_init(fs, inode_ref);
        }
-#endif
 
        inode_ref->dirty = true;
 
@@ -707,11 +907,11 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
 {
        struct ext4_fs *fs = inode_ref->fs;
        uint32_t offset;
-       uint32_t suboffset;
+       uint32_t suboff;
+       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;
@@ -720,7 +920,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
        /* Release all indirect (no data) blocks */
 
        /* 1) Single indirect */
-       uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
+       ext4_fsblk_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
        if (fblock != 0) {
                int rc = ext4_balloc_free_block(inode_ref, fblock);
                if (rc != EOK)
@@ -737,22 +937,22 @@ 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;
 
-               uint32_t ind_block;
+               ext4_fsblk_t ind_block;
                for (offset = 0; offset < count; ++offset) {
                        ind_block = to_le32(((uint32_t *)block.data)[offset]);
 
-                       if (ind_block != 0) {
-                               rc = ext4_balloc_free_block(inode_ref,
-                                                           ind_block);
-                               if (rc != EOK) {
-                                       ext4_block_set(fs->bdev, &block);
-                                       return rc;
-                               }
+                       if (ind_block == 0)
+                               continue;
+                       rc = ext4_balloc_free_block(inode_ref, ind_block);
+                       if (rc != EOK) {
+                               ext4_block_set(fs->bdev, &block);
+                               return rc;
                        }
+
                }
 
                ext4_block_set(fs->bdev, &block);
@@ -766,70 +966,63 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
        /* 3) Tripple indirect */
        struct ext4_block subblock;
        fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
-       if (fblock != 0) {
-               int rc = ext4_block_get(fs->bdev, &block, fblock);
-               if (rc != EOK)
-                       return rc;
+       if (fblock == 0)
+               goto finish;
+       rc = ext4_trans_block_get(fs->bdev, &block, fblock);
+       if (rc != EOK)
+               return rc;
 
-               uint32_t ind_block;
-               for (offset = 0; offset < count; ++offset) {
-                       ind_block = to_le32(((uint32_t *)block.data)[offset]);
+       ext4_fsblk_t ind_block;
+       for (offset = 0; offset < count; ++offset) {
+               ind_block = to_le32(((uint32_t *)block.data)[offset]);
 
-                       if (ind_block != 0) {
-                               rc = ext4_block_get(fs->bdev, &subblock,
-                                                   ind_block);
-                               if (rc != EOK) {
-                                       ext4_block_set(fs->bdev, &block);
-                                       return rc;
-                               }
-
-                               uint32_t ind_subblock;
-                               for (suboffset = 0; suboffset < count;
-                                    ++suboffset) {
-                                       ind_subblock = to_le32(
-                                           ((uint32_t *)
-                                                subblock.data)[suboffset]);
-
-                                       if (ind_subblock != 0) {
-                                               rc = ext4_balloc_free_block(
-                                                   inode_ref, ind_subblock);
-                                               if (rc != EOK) {
-                                                       ext4_block_set(
-                                                           fs->bdev,
-                                                           &subblock);
-                                                       ext4_block_set(fs->bdev,
-                                                                      &block);
-                                                       return rc;
-                                               }
-                                       }
-                               }
+               if (ind_block == 0)
+                       continue;
+               rc = ext4_trans_block_get(fs->bdev, &subblock,
+                               ind_block);
+               if (rc != EOK) {
+                       ext4_block_set(fs->bdev, &block);
+                       return rc;
+               }
 
-                               ext4_block_set(fs->bdev, &subblock);
+               ext4_fsblk_t ind_subblk;
+               for (suboff = 0; suboff < count; ++suboff) {
+                       ind_subblk = to_le32(((uint32_t *)subblock.data)[suboff]);
 
-                               rc = ext4_balloc_free_block(inode_ref,
-                                                           ind_block);
-                               if (rc != EOK) {
-                                       ext4_block_set(fs->bdev, &block);
-                                       return rc;
-                               }
+                       if (ind_subblk == 0)
+                               continue;
+                       rc = ext4_balloc_free_block(inode_ref, ind_subblk);
+                       if (rc != EOK) {
+                               ext4_block_set(fs->bdev, &subblock);
+                               ext4_block_set(fs->bdev, &block);
+                               return rc;
                        }
+
                }
 
-               ext4_block_set(fs->bdev, &block);
-               rc = ext4_balloc_free_block(inode_ref, fblock);
-               if (rc != EOK)
+               ext4_block_set(fs->bdev, &subblock);
+
+               rc = ext4_balloc_free_block(inode_ref,
+                               ind_block);
+               if (rc != EOK) {
+                       ext4_block_set(fs->bdev, &block);
                        return rc;
+               }
 
-               ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
        }
-#if CONFIG_EXTENT_ENABLE
-finish:
-#endif
-       /* Mark inode dirty for writing to the physical device */
-       inode_ref->dirty = true;
+
+       ext4_block_set(fs->bdev, &block);
+       rc = ext4_balloc_free_block(inode_ref, fblock);
+       if (rc != EOK)
+               return rc;
+
+       ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
+finish:
+       /* Mark inode dirty for writing to the physical device */
+       inode_ref->dirty = true;
 
        /* Free block with extended attributes if present */
-       uint32_t xattr_block =
+       ext4_fsblk_t xattr_block =
            ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
        if (xattr_block) {
                int rc = ext4_balloc_free_block(inode_ref, xattr_block);
@@ -840,7 +1033,6 @@ finish:
        }
 
        /* Free inode by allocator */
-       int rc;
        if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
                               EXT4_INODE_MODE_DIRECTORY))
                rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
@@ -850,10 +1042,117 @@ finish:
        return rc;
 }
 
+
+/**@brief Release data block from i-node
+ * @param inode_ref I-node to release block from
+ * @param iblock    Logical block to be released
+ * @return Error code
+ */
+static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
+                               uint32_t iblock)
+{
+       ext4_fsblk_t fblock;
+
+       struct ext4_fs *fs = inode_ref->fs;
+
+       /* Extents are handled otherwise = there is not support in this function
+        */
+       ext4_assert(!(
+           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;
+
+       /* Handle simple case when we are dealing with direct reference */
+       if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+               fblock = ext4_inode_get_direct_block(inode, iblock);
+
+               /* Sparse file */
+               if (fblock == 0)
+                       return EOK;
+
+               ext4_inode_set_direct_block(inode, iblock, 0);
+               return ext4_balloc_free_block(inode_ref, fblock);
+       }
+
+       /* Determine the indirection level needed to get the desired block */
+       unsigned int level = 0;
+       unsigned int i;
+       for (i = 1; i < 4; i++) {
+               if (iblock < fs->inode_block_limits[i]) {
+                       level = i;
+                       break;
+               }
+       }
+
+       if (level == 0)
+               return EIO;
+
+       /* Compute offsets for the topmost level */
+       uint64_t block_offset_in_level =
+           iblock - fs->inode_block_limits[level - 1];
+       ext4_fsblk_t 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];
+
+       /*
+        * Navigate through other levels, until we find the block number
+        * or find null reference meaning we are dealing with sparse file
+        */
+       struct ext4_block block;
+
+       while (level > 0) {
+
+               /* Sparse check */
+               if (current_block == 0)
+                       return EOK;
+
+               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]);
+
+               /* Set zero if physical data block address found */
+               if (level == 1) {
+                       ((uint32_t *)block.data)[offset_in_block] = to_le32(0);
+                       ext4_trans_set_block_dirty(block.buf);
+               }
+
+               rc = ext4_block_set(fs->bdev, &block);
+               if (rc != EOK)
+                       return rc;
+
+               level--;
+
+               /*
+                * If we are on the last level, break here as
+                * there is no next level to visit
+                */
+               if (level == 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];
+       }
+
+       fblock = current_block;
+       if (fblock == 0)
+               return EOK;
+
+       /* Physical block is not referenced, it can be released */
+       return ext4_balloc_free_block(inode_ref, fblock);
+}
+
 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))
@@ -868,26 +1167,35 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size)
        if (old_size < new_size)
                return EINVAL;
 
+       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;
+
+               return EOK;
+       }
+
        /* Compute how many blocks will be released */
-       uint64_t size_diff = old_size - new_size;
        uint32_t block_size = ext4_sb_get_block_size(sb);
-       uint32_t diff_blocks_count = size_diff / block_size;
-       if (size_diff % block_size != 0)
-               diff_blocks_count++;
-
-       uint32_t old_blocks_count = old_size / block_size;
-       if (old_size % block_size != 0)
-               old_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 */
-               int rc = ext4_extent_release_blocks_from(
-                   inode_ref, old_blocks_count - diff_blocks_count);
-               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
 #endif
        {
@@ -895,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 = 1; i <= diff_blocks_count; ++i) {
-                       int rc = ext4_fs_release_inode_block(
-                           inode_ref, old_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;
                }
        }
 
@@ -910,8 +1218,95 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size)
        return EOK;
 }
 
-int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
-                                      uint64_t iblock, uint32_t *fblock)
+/**@brief Compute 'goal' for inode index
+ * @param inode_ref Reference to inode, to allocate block for
+ * @return goal
+ */
+ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref)
+{
+       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).
+ * @param inode_ref Reference to inode, to allocate block for
+ * @param goal
+ * @return error code
+ */
+int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref,
+                              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 iblock_cnt = inode_size / block_size;
+
+       if (inode_size % block_size != 0)
+               iblock_cnt++;
+
+       /* If inode has some blocks, get last block address + 1 */
+       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 r;
+               }
+
+               /* If goal == 0, sparse file -> continue */
+       }
+
+       /* Identify block group of inode */
+
+       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;
+       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 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 < bg_count - 1) {
+               itab_bytes = inodes_per_bg * itab_item_size;
+       } else {
+               /* Last block group could be smaller */
+               uint32_t inodes_cnt = ext4_get32(sb, inodes_count);
+
+               itab_bytes = (inodes_cnt - ((bg_count - 1) * inodes_per_bg));
+               itab_bytes *= itab_item_size;
+       }
+
+       ext4_fsblk_t inode_table_blocks = itab_bytes / block_size;
+
+       if (itab_bytes % block_size)
+               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_dblk_idx_internal(struct ext4_inode_ref *inode_ref,
+                                      uint64_t iblock, ext4_fsblk_t *fblock,
+                                      bool extent_create,
+                                      bool support_unwritten __unused)
 {
        struct ext4_fs *fs = inode_ref->fs;
 
@@ -921,19 +1316,24 @@ int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
                return EOK;
        }
 
-       uint32_t current_block;
+       ext4_fsblk_t current_block;
+
+       (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))) {
 
-               int rc =
-                   ext4_extent_find_block(inode_ref, iblock, &current_block);
+               ext4_fsblk_t current_fsblk;
+               int rc = ext4_extent_get_blocks(inode_ref, iblock, 1,
+                               &current_fsblk, extent_create, NULL);
                if (rc != EOK)
                        return rc;
 
+               current_block = current_fsblk;
                *fblock = current_block;
+
+               ext4_assert(*fblock || support_unwritten);
                return EOK;
        }
 #endif
@@ -949,24 +1349,22 @@ int ext4_fs_get_inode_data_block_index(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) {
@@ -980,15 +1378,15 @@ int ext4_fs_get_inode_data_block_index(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);
@@ -1002,17 +1400,16 @@ int ext4_fs_get_inode_data_block_index(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;
@@ -1020,15 +1417,30 @@ int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
        return EOK;
 }
 
-int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
-                                      uint64_t iblock, uint32_t fblock)
+
+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_dblk_idx_internal(inode_ref, iblock, fblock,
+                                                  false, support_unwritten);
+}
+
+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_dblk_idx_internal(inode_ref, iblock, fblock,
+                                                  true, true);
+}
+
+static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+                                      uint64_t iblock, ext4_fsblk_t fblock)
 {
        struct ext4_fs *fs = inode_ref->fs;
 
 #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;
@@ -1038,36 +1450,34 @@ int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
        /* Handle simple case when we are dealing with direct reference */
        if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
                ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock,
-                                           fblock);
+                                           (uint32_t)fblock);
                inode_ref->dirty = true;
 
                return EOK;
        }
 
        /* 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];
-       uint32_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];
+       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, l - 1);
+       uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
 
-       uint32_t new_block_addr;
+       ext4_fsblk_t new_blk;
 
        struct ext4_block block;
        struct ext4_block new_block;
@@ -1075,58 +1485,67 @@ int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
        /* Is needed to allocate indirect block on the i-node level */
        if (current_block == 0) {
                /* Allocate new indirect block */
-               int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+               ext4_fsblk_t goal;
+               int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+               if (rc != EOK)
+                       return rc;
+
+               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,
-                                             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]);
+               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) {
+                               ext4_block_set(fs->bdev, &block);
+                               return rc;
+                       }
 
-               if ((level > 1) && (current_block == 0)) {
                        /* Allocate new block */
                        rc =
-                           ext4_balloc_alloc_block(inode_ref, &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);
@@ -1135,7 +1554,7 @@ 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) {
@@ -1144,152 +1563,66 @@ 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(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(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_release_inode_block(struct ext4_inode_ref *inode_ref,
-                               uint32_t iblock)
-{
-       uint32_t fblock;
-
-       struct ext4_fs *fs = inode_ref->fs;
 
-       /* 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_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
-
-       struct ext4_inode *inode = inode_ref->inode;
-
-       /* Handle simple case when we are dealing with direct reference */
-       if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
-               fblock = ext4_inode_get_direct_block(inode, iblock);
-
-               /* Sparse file */
-               if (fblock == 0)
-                       return EOK;
-
-               ext4_inode_set_direct_block(inode, iblock, 0);
-               return ext4_balloc_free_block(inode_ref, fblock);
-       }
-
-       /* Determine the indirection level needed to get the desired block */
-       unsigned int level = 0;
-       unsigned int i;
-       for (i = 1; i < 4; i++) {
-               if (iblock < fs->inode_block_limits[i]) {
-                       level = i;
-                       break;
-               }
-       }
-
-       if (level == 0)
-               return EIO;
-
-       /* Compute offsets for the topmost level */
-       uint64_t block_offset_in_level =
-           iblock - fs->inode_block_limits[level - 1];
-       uint32_t 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];
-
-       /*
-        * Navigate through other levels, until we find the block number
-        * or find null reference meaning we are dealing with sparse file
-        */
-       struct ext4_block block;
-
-       while (level > 0) {
-
-               /* Sparse check */
-               if (current_block == 0)
-                       return EOK;
-
-               int rc = ext4_block_get(fs->bdev, &block, current_block);
-               if (rc != EOK)
-                       return rc;
-
-               current_block =
-                   to_le32(((uint32_t *)block.data)[offset_in_block]);
-
-               /* Set zero if physical data block address found */
-               if (level == 1) {
-                       ((uint32_t *)block.data)[offset_in_block] = to_le32(0);
-                       block.dirty = true;
-               }
+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_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;
 
-               rc = ext4_block_set(fs->bdev, &block);
-               if (rc != EOK)
-                       return rc;
+               rc = ext4_extent_get_blocks(inode_ref, *iblock, 1,
+                                               &current_fsblk, true, NULL);
 
-               level--;
+               *fblock = current_fsblk;
+               ext4_assert(*fblock);
 
-               /*
-                * If we are on the last level, break here as
-                * there is no next level to visit
-                */
-               if (level == 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];
-       }
-
-       fblock = current_block;
-       if (fblock == 0)
-               return EOK;
+               ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
+               inode_ref->dirty = true;
 
-       /* Physical block is not referenced, it can be released */
-       return ext4_balloc_free_block(inode_ref, fblock);
-}
 
-int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
-                              uint32_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)) &&
-           (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
-               return ext4_extent_append_block(inode_ref, iblock, fblock,
-                                               true);
+               return rc;
        }
 #endif
        struct ext4_sblock *sb = &inode_ref->fs->sb;
@@ -1306,8 +1639,12 @@ int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
        uint32_t new_block_idx = inode_size / block_size;
 
        /* Allocate new physical block */
-       uint32_t phys_block;
-       int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+       ext4_fsblk_t goal, phys_block;
+       int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+       if (rc != EOK)
+               return rc;
+
+       rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
        if (rc != EOK)
                return rc;
 
@@ -1332,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);
                }
        }
@@ -1356,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);
 }
 
 /**