]> git.sur5r.net Git - u-boot/blobdiff - fs/ext4/ext4_write.c
Merge git://git.denx.de/u-boot-imx
[u-boot] / fs / ext4 / ext4_write.c
index 1e1924c80626f4835f61e7f6dc9aa6f9b4682a7e..d710a86d59c263eb0e2492b920b7f4917db1d9f8 100644 (file)
 
 
 #include <common.h>
+#include <memalign.h>
 #include <linux/stat.h>
 #include <div64.h>
 #include "ext4_common.h"
 
+static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb)
+{
+       sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1);
+}
+
+static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb)
+{
+       sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1);
+}
+
+static inline void ext4fs_bg_free_inodes_inc
+       (struct ext2_block_group *bg, const struct ext_filesystem *fs)
+{
+       uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
+       if (fs->gdsize == 64)
+               free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
+       free_inodes++;
+
+       bg->free_inodes = cpu_to_le16(free_inodes & 0xffff);
+       if (fs->gdsize == 64)
+               bg->free_inodes_high = cpu_to_le16(free_inodes >> 16);
+}
+
+static inline void ext4fs_bg_free_blocks_inc
+       (struct ext2_block_group *bg, const struct ext_filesystem *fs)
+{
+       uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
+       if (fs->gdsize == 64)
+               free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
+       free_blocks++;
+
+       bg->free_blocks = cpu_to_le16(free_blocks & 0xffff);
+       if (fs->gdsize == 64)
+               bg->free_blocks_high = cpu_to_le16(free_blocks >> 16);
+}
+
 static void ext4fs_update(void)
 {
        short i;
        ext4fs_update_journal();
        struct ext_filesystem *fs = get_fs();
+       struct ext2_block_group *bgd = NULL;
 
        /* update  super block */
        put_ext4((uint64_t)(SUPERBLOCK_SIZE),
                 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
 
-       /* update block groups */
+       /* update block bitmaps */
        for (i = 0; i < fs->no_blkgrp; i++) {
-               fs->bgd[i].bg_checksum = ext4fs_checksum_update(i);
-               put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz),
+               bgd = ext4fs_get_group_descriptor(fs, i);
+               bgd->bg_checksum = cpu_to_le16(ext4fs_checksum_update(i));
+               uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
+               put_ext4(b_bitmap_blk * fs->blksz,
                         fs->blk_bmaps[i], fs->blksz);
        }
 
-       /* update inode table groups */
+       /* update inode bitmaps */
        for (i = 0; i < fs->no_blkgrp; i++) {
-               put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz),
+               bgd = ext4fs_get_group_descriptor(fs, i);
+               uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs);
+               put_ext4(i_bitmap_blk * fs->blksz,
                         fs->inode_bmaps[i], fs->blksz);
        }
 
        /* update the block group descriptor table */
-       put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
+       put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
                 (struct ext2_block_group *)fs->gdtable,
                 (fs->blksz * fs->no_blk_pergdt));
 
@@ -64,15 +106,12 @@ static void ext4fs_update(void)
 int ext4fs_get_bgdtable(void)
 {
        int status;
-       int grp_desc_size;
        struct ext_filesystem *fs = get_fs();
-       grp_desc_size = sizeof(struct ext2_block_group);
-       fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
-       if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
-               fs->no_blk_pergdt++;
+       int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz);
+       fs->no_blk_pergdt = gdsize_total / fs->blksz;
 
        /* allocate memory for gdtable */
-       fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
+       fs->gdtable = zalloc(gdsize_total);
        if (!fs->gdtable)
                return -ENOMEM;
        /* read the group descriptor table */
@@ -98,45 +137,42 @@ static void delete_single_indirect_block(struct ext2_inode *inode)
 {
        struct ext2_block_group *bgd = NULL;
        static int prev_bg_bmap_idx = -1;
-       long int blknr;
+       uint32_t blknr;
        int remainder;
        int bg_idx;
        int status;
-       unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+       uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
        struct ext_filesystem *fs = get_fs();
        char *journal_buffer = zalloc(fs->blksz);
        if (!journal_buffer) {
                printf("No memory\n");
                return;
        }
-       /* get  block group descriptor table */
-       bgd = (struct ext2_block_group *)fs->gdtable;
 
        /* deleting the single indirect block associated with inode */
        if (inode->b.blocks.indir_block != 0) {
-               debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
-               blknr = inode->b.blocks.indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               blknr = le32_to_cpu(inode->b.blocks.indir_block);
+               debug("SIPB releasing %u\n", blknr);
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
                }
                ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
-               bgd[bg_idx].free_blocks++;
-               fs->sb->free_blocks++;
+               /* get  block group descriptor table */
+               bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+               ext4fs_bg_free_blocks_inc(bgd, fs);
+               ext4fs_sb_free_blocks_inc(fs->sb);
                /* journal backup */
                if (prev_bg_bmap_idx != bg_idx) {
-                       status =
-                           ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
-                                          fs->sect_perblk, 0, fs->blksz,
-                                          journal_buffer);
+                       uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
+                       status = ext4fs_devread(
+                                          b_bitmap_blk * fs->sect_perblk,
+                                          0, fs->blksz, journal_buffer);
                        if (status == 0)
                                goto fail;
-                       if (ext4fs_log_journal
-                           (journal_buffer, bgd[bg_idx].block_id))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
@@ -150,12 +186,12 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
        int i;
        short status;
        static int prev_bg_bmap_idx = -1;
-       long int blknr;
+       uint32_t blknr;
        int remainder;
        int bg_idx;
-       unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
-       unsigned int *di_buffer = NULL;
-       unsigned int *DIB_start_addr = NULL;
+       uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
+       __le32 *di_buffer = NULL;
+       void *dib_start_addr = NULL;
        struct ext2_block_group *bgd = NULL;
        struct ext_filesystem *fs = get_fs();
        char *journal_buffer = zalloc(fs->blksz);
@@ -163,8 +199,6 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                printf("No memory\n");
                return;
        }
-       /* get the block group descriptor table */
-       bgd = (struct ext2_block_group *)fs->gdtable;
 
        if (inode->b.blocks.double_indir_block != 0) {
                di_buffer = zalloc(fs->blksz);
@@ -172,8 +206,8 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                        printf("No memory\n");
                        return;
                }
-               DIB_start_addr = (unsigned int *)di_buffer;
-               blknr = inode->b.blocks.double_indir_block;
+               dib_start_addr = di_buffer;
+               blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
                status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
                                        fs->blksz, (char *)di_buffer);
                for (i = 0; i < fs->blksz / sizeof(int); i++) {
@@ -181,23 +215,24 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                                break;
 
                        debug("DICB releasing %u\n", *di_buffer);
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*di_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*di_buffer) / blk_per_grp;
-                               remainder = (*di_buffer) % blk_per_grp;
+                       bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp;
+                       if (fs->blksz == 1024) {
+                               remainder = le32_to_cpu(*di_buffer) % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
                        }
-                       ext4fs_reset_block_bmap(*di_buffer,
+                       /* get  block group descriptor table */
+                       bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+                       ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer),
                                        fs->blk_bmaps[bg_idx], bg_idx);
                        di_buffer++;
-                       bgd[bg_idx].free_blocks++;
-                       fs->sb->free_blocks++;
+                       ext4fs_bg_free_blocks_inc(bgd, fs);
+                       ext4fs_sb_free_blocks_inc(fs->sb);
                        /* journal backup */
                        if (prev_bg_bmap_idx != bg_idx) {
-                               status = ext4fs_devread((lbaint_t)
-                                                       bgd[bg_idx].block_id
+                               uint64_t b_bitmap_blk =
+                                       ext4fs_bg_get_block_id(bgd, fs);
+                               status = ext4fs_devread(b_bitmap_blk
                                                        * fs->sect_perblk, 0,
                                                        fs->blksz,
                                                        journal_buffer);
@@ -205,43 +240,41 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                                        goto fail;
 
                                if (ext4fs_log_journal(journal_buffer,
-                                                       bgd[bg_idx].block_id))
+                                                      b_bitmap_blk))
                                        goto fail;
                                prev_bg_bmap_idx = bg_idx;
                        }
                }
 
                /* removing the parent double indirect block */
-               blknr = inode->b.blocks.double_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
                }
+               /* get  block group descriptor table */
+               bgd = ext4fs_get_group_descriptor(fs, bg_idx);
                ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
-               bgd[bg_idx].free_blocks++;
-               fs->sb->free_blocks++;
+               ext4fs_bg_free_blocks_inc(bgd, fs);
+               ext4fs_sb_free_blocks_inc(fs->sb);
                /* journal backup */
                if (prev_bg_bmap_idx != bg_idx) {
-                       memset(journal_buffer, '\0', fs->blksz);
-                       status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
-                                               fs->sect_perblk, 0, fs->blksz,
-                                               journal_buffer);
+                       uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
+                       status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
+                                               0, fs->blksz, journal_buffer);
                        if (status == 0)
                                goto fail;
 
-                       if (ext4fs_log_journal(journal_buffer,
-                                               bgd[bg_idx].block_id))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
-               debug("DIPB releasing %ld\n", blknr);
+               debug("DIPB releasing %d\n", blknr);
        }
 fail:
-       free(DIB_start_addr);
+       free(dib_start_addr);
        free(journal_buffer);
 }
 
@@ -250,14 +283,14 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
        int i, j;
        short status;
        static int prev_bg_bmap_idx = -1;
-       long int blknr;
+       uint32_t blknr;
        int remainder;
        int bg_idx;
-       unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
-       unsigned int *tigp_buffer = NULL;
-       unsigned int *tib_start_addr = NULL;
-       unsigned int *tip_buffer = NULL;
-       unsigned int *tipb_start_addr = NULL;
+       uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
+       __le32 *tigp_buffer = NULL;
+       void *tib_start_addr = NULL;
+       __le32 *tip_buffer = NULL;
+       void *tipb_start_addr = NULL;
        struct ext2_block_group *bgd = NULL;
        struct ext_filesystem *fs = get_fs();
        char *journal_buffer = zalloc(fs->blksz);
@@ -265,8 +298,6 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                printf("No memory\n");
                return;
        }
-       /* get block group descriptor table */
-       bgd = (struct ext2_block_group *)fs->gdtable;
 
        if (inode->b.blocks.triple_indir_block != 0) {
                tigp_buffer = zalloc(fs->blksz);
@@ -274,8 +305,8 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                        printf("No memory\n");
                        return;
                }
-               tib_start_addr = (unsigned int *)tigp_buffer;
-               blknr = inode->b.blocks.triple_indir_block;
+               tib_start_addr = tigp_buffer;
+               blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
                status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
                                        fs->blksz, (char *)tigp_buffer);
                for (i = 0; i < fs->blksz / sizeof(int); i++) {
@@ -286,36 +317,36 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                        tip_buffer = zalloc(fs->blksz);
                        if (!tip_buffer)
                                goto fail;
-                       tipb_start_addr = (unsigned int *)tip_buffer;
-                       status = ext4fs_devread((lbaint_t)(*tigp_buffer) *
+                       tipb_start_addr = tip_buffer;
+                       status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) *
                                                fs->sect_perblk, 0, fs->blksz,
                                                (char *)tip_buffer);
                        for (j = 0; j < fs->blksz / sizeof(int); j++) {
-                               if (*tip_buffer == 0)
+                               if (le32_to_cpu(*tip_buffer) == 0)
                                        break;
-                               if (fs->blksz != 1024) {
-                                       bg_idx = (*tip_buffer) / blk_per_grp;
-                               } else {
-                                       bg_idx = (*tip_buffer) / blk_per_grp;
-
-                                       remainder = (*tip_buffer) % blk_per_grp;
+                               bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp;
+                               if (fs->blksz == 1024) {
+                                       remainder = le32_to_cpu(*tip_buffer) % blk_per_grp;
                                        if (!remainder)
                                                bg_idx--;
                                }
 
-                               ext4fs_reset_block_bmap(*tip_buffer,
+                               ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer),
                                                        fs->blk_bmaps[bg_idx],
                                                        bg_idx);
 
                                tip_buffer++;
-                               bgd[bg_idx].free_blocks++;
-                               fs->sb->free_blocks++;
+                               /* get  block group descriptor table */
+                               bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+                               ext4fs_bg_free_blocks_inc(bgd, fs);
+                               ext4fs_sb_free_blocks_inc(fs->sb);
                                /* journal backup */
                                if (prev_bg_bmap_idx != bg_idx) {
+                                       uint64_t b_bitmap_blk =
+                                               ext4fs_bg_get_block_id(bgd, fs);
                                        status =
                                            ext4fs_devread(
-                                                       (lbaint_t)
-                                                       bgd[bg_idx].block_id *
+                                                       b_bitmap_blk *
                                                        fs->sect_perblk, 0,
                                                        fs->blksz,
                                                        journal_buffer);
@@ -323,8 +354,7 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                                                goto fail;
 
                                        if (ext4fs_log_journal(journal_buffer,
-                                                              bgd[bg_idx].
-                                                              block_id))
+                                                              b_bitmap_blk))
                                                goto fail;
                                        prev_bg_bmap_idx = bg_idx;
                                }
@@ -336,67 +366,65 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                         * removing the grand parent blocks
                         * which is connected to inode
                         */
-                       if (fs->blksz != 1024) {
-                               bg_idx = (*tigp_buffer) / blk_per_grp;
-                       } else {
-                               bg_idx = (*tigp_buffer) / blk_per_grp;
-
-                               remainder = (*tigp_buffer) % blk_per_grp;
+                       bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp;
+                       if (fs->blksz == 1024) {
+                               remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp;
                                if (!remainder)
                                        bg_idx--;
                        }
-                       ext4fs_reset_block_bmap(*tigp_buffer,
+                       ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer),
                                                fs->blk_bmaps[bg_idx], bg_idx);
 
                        tigp_buffer++;
-                       bgd[bg_idx].free_blocks++;
-                       fs->sb->free_blocks++;
+                       /* get  block group descriptor table */
+                       bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+                       ext4fs_bg_free_blocks_inc(bgd, fs);
+                       ext4fs_sb_free_blocks_inc(fs->sb);
                        /* journal backup */
                        if (prev_bg_bmap_idx != bg_idx) {
+                               uint64_t b_bitmap_blk =
+                                       ext4fs_bg_get_block_id(bgd, fs);
                                memset(journal_buffer, '\0', fs->blksz);
-                               status =
-                                   ext4fs_devread((lbaint_t)
-                                                  bgd[bg_idx].block_id *
-                                                  fs->sect_perblk, 0,
-                                                  fs->blksz, journal_buffer);
+                               status = ext4fs_devread(b_bitmap_blk *
+                                                       fs->sect_perblk, 0,
+                                                       fs->blksz,
+                                                       journal_buffer);
                                if (status == 0)
                                        goto fail;
 
                                if (ext4fs_log_journal(journal_buffer,
-                                                       bgd[bg_idx].block_id))
+                                                      b_bitmap_blk))
                                        goto fail;
                                prev_bg_bmap_idx = bg_idx;
                        }
                }
 
                /* removing the grand parent triple indirect block */
-               blknr = inode->b.blocks.triple_indir_block;
-               if (fs->blksz != 1024) {
-                       bg_idx = blknr / blk_per_grp;
-               } else {
-                       bg_idx = blknr / blk_per_grp;
+               blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
                        remainder = blknr % blk_per_grp;
                        if (!remainder)
                                bg_idx--;
                }
                ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
-               bgd[bg_idx].free_blocks++;
-               fs->sb->free_blocks++;
+               /* get  block group descriptor table */
+               bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+               ext4fs_bg_free_blocks_inc(bgd, fs);
+               ext4fs_sb_free_blocks_inc(fs->sb);
                /* journal backup */
                if (prev_bg_bmap_idx != bg_idx) {
-                       memset(journal_buffer, '\0', fs->blksz);
-                       status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
-                                               fs->sect_perblk, 0, fs->blksz,
-                                               journal_buffer);
+                       uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
+                       status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
+                                               0, fs->blksz, journal_buffer);
                        if (status == 0)
                                goto fail;
 
-                       if (ext4fs_log_journal(journal_buffer,
-                                               bgd[bg_idx].block_id))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
-               debug("tigp buffer itself releasing %ld\n", blknr);
+               debug("tigp buffer itself releasing %d\n", blknr);
        }
 fail:
        free(tib_start_addr);
@@ -415,130 +443,87 @@ static int ext4fs_delete_file(int inodeno)
        int ibmap_idx;
        char *read_buffer = NULL;
        char *start_block_address = NULL;
-       unsigned int no_blocks;
+       uint32_t no_blocks;
 
        static int prev_bg_bmap_idx = -1;
        unsigned int inodes_per_block;
-       long int blkno;
+       uint32_t blkno;
        unsigned int blkoff;
-       unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
-       unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
+       uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
+       uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
        struct ext2_inode *inode_buffer = NULL;
        struct ext2_block_group *bgd = NULL;
        struct ext_filesystem *fs = get_fs();
        char *journal_buffer = zalloc(fs->blksz);
        if (!journal_buffer)
                return -ENOMEM;
-       /* get the block group descriptor table */
-       bgd = (struct ext2_block_group *)fs->gdtable;
        status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
        if (status == 0)
                goto fail;
 
        /* read the block no allocated to a file */
-       no_blocks = inode.size / fs->blksz;
-       if (inode.size % fs->blksz)
+       no_blocks = le32_to_cpu(inode.size) / fs->blksz;
+       if (le32_to_cpu(inode.size) % fs->blksz)
                no_blocks++;
 
        if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
-               struct ext2fs_node *node_inode =
-                   zalloc(sizeof(struct ext2fs_node));
-               if (!node_inode)
-                       goto fail;
-               node_inode->data = ext4fs_root;
-               node_inode->ino = inodeno;
-               node_inode->inode_read = 0;
-               memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
-
-               for (i = 0; i < no_blocks; i++) {
-                       blknr = read_allocated_block(&(node_inode->inode), i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
-                               remainder = blknr % blk_per_grp;
-                               if (!remainder)
-                                       bg_idx--;
-                       }
-                       ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
-                                               bg_idx);
-                       debug("EXT4_EXTENTS Block releasing %ld: %d\n",
-                             blknr, bg_idx);
-
-                       bgd[bg_idx].free_blocks++;
-                       fs->sb->free_blocks++;
-
-                       /* journal backup */
-                       if (prev_bg_bmap_idx != bg_idx) {
-                               status =
-                                   ext4fs_devread((lbaint_t)
-                                                  bgd[bg_idx].block_id *
-                                                  fs->sect_perblk, 0,
-                                                  fs->blksz, journal_buffer);
-                               if (status == 0)
-                                       goto fail;
-                               if (ext4fs_log_journal(journal_buffer,
-                                                       bgd[bg_idx].block_id))
-                                       goto fail;
-                               prev_bg_bmap_idx = bg_idx;
-                       }
-               }
-               if (node_inode) {
-                       free(node_inode);
-                       node_inode = NULL;
-               }
+               /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
+               struct ext4_extent_header *eh =
+                       (struct ext4_extent_header *)
+                               inode.b.blocks.dir_blocks;
+               debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries);
        } else {
-
                delete_single_indirect_block(&inode);
                delete_double_indirect_block(&inode);
                delete_triple_indirect_block(&inode);
+       }
 
-               /* read the block no allocated to a file */
-               no_blocks = inode.size / fs->blksz;
-               if (inode.size % fs->blksz)
-                       no_blocks++;
-               for (i = 0; i < no_blocks; i++) {
-                       blknr = read_allocated_block(&inode, i);
-                       if (fs->blksz != 1024) {
-                               bg_idx = blknr / blk_per_grp;
-                       } else {
-                               bg_idx = blknr / blk_per_grp;
-                               remainder = blknr % blk_per_grp;
-                               if (!remainder)
-                                       bg_idx--;
-                       }
-                       ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
-                                               bg_idx);
-                       debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
-
-                       bgd[bg_idx].free_blocks++;
-                       fs->sb->free_blocks++;
-                       /* journal backup */
-                       if (prev_bg_bmap_idx != bg_idx) {
-                               memset(journal_buffer, '\0', fs->blksz);
-                               status = ext4fs_devread((lbaint_t)
-                                                       bgd[bg_idx].block_id
-                                                       * fs->sect_perblk,
-                                                       0, fs->blksz,
-                                                       journal_buffer);
-                               if (status == 0)
-                                       goto fail;
-                               if (ext4fs_log_journal(journal_buffer,
-                                               bgd[bg_idx].block_id))
-                                       goto fail;
-                               prev_bg_bmap_idx = bg_idx;
-                       }
+       /* release data blocks */
+       for (i = 0; i < no_blocks; i++) {
+               blknr = read_allocated_block(&inode, i);
+               if (blknr == 0)
+                       continue;
+               if (blknr < 0)
+                       goto fail;
+               bg_idx = blknr / blk_per_grp;
+               if (fs->blksz == 1024) {
+                       remainder = blknr % blk_per_grp;
+                       if (!remainder)
+                               bg_idx--;
+               }
+               ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
+                                       bg_idx);
+               debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx);
+
+               /* get  block group descriptor table */
+               bgd = ext4fs_get_group_descriptor(fs, bg_idx);
+               ext4fs_bg_free_blocks_inc(bgd, fs);
+               ext4fs_sb_free_blocks_inc(fs->sb);
+               /* journal backup */
+               if (prev_bg_bmap_idx != bg_idx) {
+                       uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
+                       status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
+                                               0, fs->blksz,
+                                               journal_buffer);
+                       if (status == 0)
+                               goto fail;
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
+                               goto fail;
+                       prev_bg_bmap_idx = bg_idx;
                }
        }
 
+       /* release inode */
        /* from the inode no to blockno */
        inodes_per_block = fs->blksz / fs->inodesz;
        ibmap_idx = inodeno / inode_per_grp;
 
        /* get the block no */
        inodeno--;
-       blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
-               (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
+       /* get  block group descriptor table */
+       bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
+       blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
+               (inodeno % inode_per_grp) / inodes_per_block;
 
        /* get the offset of the inode */
        blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
@@ -558,7 +543,7 @@ static int ext4fs_delete_file(int inodeno)
 
        read_buffer = read_buffer + blkoff;
        inode_buffer = (struct ext2_inode *)read_buffer;
-       memset(inode_buffer, '\0', sizeof(struct ext2_inode));
+       memset(inode_buffer, '\0', fs->inodesz);
 
        /* write the inode to original position in inode table */
        if (ext4fs_put_metadata(start_block_address, blkno))
@@ -567,19 +552,20 @@ static int ext4fs_delete_file(int inodeno)
        /* update the respective inode bitmaps */
        inodeno++;
        ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
-       bgd[ibmap_idx].free_inodes++;
-       fs->sb->free_inodes++;
+       ext4fs_bg_free_inodes_inc(bgd, fs);
+       ext4fs_sb_free_inodes_inc(fs->sb);
        /* journal backup */
        memset(journal_buffer, '\0', fs->blksz);
-       status = ext4fs_devread((lbaint_t)bgd[ibmap_idx].inode_id *
+       status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
                                fs->sect_perblk, 0, fs->blksz, journal_buffer);
        if (status == 0)
                goto fail;
-       if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id))
+       if (ext4fs_log_journal(journal_buffer, ext4fs_bg_get_inode_id(bgd, fs)))
                goto fail;
 
        ext4fs_update();
        ext4fs_deinit();
+       ext4fs_reinit_global();
 
        if (ext4fs_init() != 0) {
                printf("error in File System init\n");
@@ -601,12 +587,11 @@ int ext4fs_init(void)
 {
        short status;
        int i;
-       unsigned int real_free_blocks = 0;
+       uint32_t real_free_blocks = 0;
        struct ext_filesystem *fs = get_fs();
 
        /* populate fs */
        fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
-       fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
        fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
 
        /* get the superblock */
@@ -622,9 +607,9 @@ int ext4fs_init(void)
 
        /* get total no of blockgroups */
        fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
-                       (ext4fs_root->sblock.total_blocks -
-                       ext4fs_root->sblock.first_data_block),
-                       ext4fs_root->sblock.blocks_per_group);
+                       le32_to_cpu(ext4fs_root->sblock.total_blocks)
+                       - le32_to_cpu(ext4fs_root->sblock.first_data_block),
+                       le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
 
        /* get the block group descriptor table */
        fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
@@ -632,7 +617,6 @@ int ext4fs_init(void)
                printf("Error in getting the block group descriptor table\n");
                goto fail;
        }
-       fs->bgd = (struct ext2_block_group *)fs->gdtable;
 
        /* load all the available bitmap block of the partition */
        fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
@@ -645,8 +629,9 @@ int ext4fs_init(void)
        }
 
        for (i = 0; i < fs->no_blkgrp; i++) {
-               status =
-                   ext4fs_devread((lbaint_t)fs->bgd[i].block_id *
+               struct ext2_block_group *bgd =
+                       ext4fs_get_group_descriptor(fs, i);
+               status = ext4fs_devread(ext4fs_bg_get_block_id(bgd, fs) *
                                   fs->sect_perblk, 0,
                                   fs->blksz, (char *)fs->blk_bmaps[i]);
                if (status == 0)
@@ -664,7 +649,9 @@ int ext4fs_init(void)
        }
 
        for (i = 0; i < fs->no_blkgrp; i++) {
-               status = ext4fs_devread((lbaint_t)fs->bgd[i].inode_id *
+               struct ext2_block_group *bgd =
+                       ext4fs_get_group_descriptor(fs, i);
+               status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) *
                                        fs->sect_perblk,
                                        0, fs->blksz,
                                        (char *)fs->inode_bmaps[i]);
@@ -678,10 +665,14 @@ int ext4fs_init(void)
         * with the  blockgroups freeblocks when improper
         * reboot of a linux kernel
         */
-       for (i = 0; i < fs->no_blkgrp; i++)
-               real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
-       if (real_free_blocks != fs->sb->free_blocks)
-               fs->sb->free_blocks = real_free_blocks;
+       for (i = 0; i < fs->no_blkgrp; i++) {
+               struct ext2_block_group *bgd =
+                       ext4fs_get_group_descriptor(fs, i);
+               real_free_blocks = real_free_blocks +
+                       ext4fs_bg_get_free_blocks(bgd, fs);
+       }
+       if (real_free_blocks != ext4fs_sb_get_free_blocks(fs->sb))
+               ext4fs_sb_set_free_blocks(fs->sb, real_free_blocks);
 
        return 0;
 fail:
@@ -695,8 +686,9 @@ void ext4fs_deinit(void)
        int i;
        struct ext2_inode inode_journal;
        struct journal_superblock_t *jsb;
-       long int blknr;
+       uint32_t blknr;
        struct ext_filesystem *fs = get_fs();
+       uint32_t new_feature_incompat;
 
        /* free journal */
        char *temp_buff = zalloc(fs->blksz);
@@ -708,8 +700,8 @@ void ext4fs_deinit(void)
                ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
                               temp_buff);
                jsb = (struct journal_superblock_t *)temp_buff;
-               jsb->s_start = cpu_to_be32(0);
-               put_ext4((uint64_t) (blknr * fs->blksz),
+               jsb->s_start = 0;
+               put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
                         (struct journal_superblock_t *)temp_buff, fs->blksz);
                free(temp_buff);
        }
@@ -717,7 +709,9 @@ void ext4fs_deinit(void)
 
        /* get the superblock */
        ext4_read_superblock((char *)fs->sb);
-       fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+       new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
+       new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+       fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
        put_ext4((uint64_t)(SUPERBLOCK_SIZE),
                 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
        free(fs->sb);
@@ -744,7 +738,6 @@ void ext4fs_deinit(void)
 
        free(fs->gdtable);
        fs->gdtable = NULL;
-       fs->bgd = NULL;
        /*
         * reinitiliazed the global inode and
         * block bitmap first execution check variables
@@ -755,12 +748,16 @@ void ext4fs_deinit(void)
        fs->curr_blkno = 0;
 }
 
+/*
+ * Write data to filesystem blocks. Uses same optimization for
+ * contigous sectors as ext4fs_read_file
+ */
 static int ext4fs_write_file(struct ext2_inode *file_inode,
                             int pos, unsigned int len, char *buf)
 {
        int i;
        int blockcnt;
-       unsigned int filesize = __le32_to_cpu(file_inode->size);
+       uint32_t filesize = le32_to_cpu(file_inode->size);
        struct ext_filesystem *fs = get_fs();
        int log2blksz = fs->dev_desc->log2blksz;
        int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
@@ -781,7 +778,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                int blockend = fs->blksz;
                int skipfirst = 0;
                blknr = read_allocated_block(file_inode, i);
-               if (blknr < 0)
+               if (blknr <= 0)
                        return -1;
 
                blknr = blknr << log2_fs_blocksize;
@@ -793,7 +790,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                                        delayed_next += blockend >> log2blksz;
                                } else {        /* spill */
                                        put_ext4((uint64_t)
-                                                (delayed_start << log2blksz),
+                                                ((uint64_t)delayed_start << log2blksz),
                                                 delayed_buf,
                                                 (uint32_t) delayed_extent);
                                        previous_block_number = blknr;
@@ -814,7 +811,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
                } else {
                        if (previous_block_number != -1) {
                                /* spill */
-                               put_ext4((uint64_t) (delayed_start <<
+                               put_ext4((uint64_t) ((uint64_t)delayed_start <<
                                                     log2blksz),
                                         delayed_buf,
                                         (uint32_t) delayed_extent);
@@ -826,7 +823,7 @@ static int ext4fs_write_file(struct ext2_inode *file_inode,
        }
        if (previous_block_number != -1) {
                /* spill */
-               put_ext4((uint64_t) (delayed_start << log2blksz),
+               put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
                         delayed_buf, (uint32_t) delayed_extent);
                previous_block_number = -1;
        }
@@ -855,11 +852,12 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
        struct ext2_sblock *sblock = &(ext4fs_root->sblock);
        unsigned int inodes_per_block;
        unsigned int ibmap_idx;
+       struct ext2_block_group *bgd = NULL;
        struct ext_filesystem *fs = get_fs();
        ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
-       memset(filename, 0x00, sizeof(filename));
+       memset(filename, 0x00, 256);
 
-       g_parent_inode = zalloc(sizeof(struct ext2_inode));
+       g_parent_inode = zalloc(fs->inodesz);
        if (!g_parent_inode)
                goto fail;
 
@@ -873,8 +871,13 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
                goto fail;
        if (ext4fs_iget(parent_inodeno, g_parent_inode))
                goto fail;
+       /* do not mess up a directory using hash trees */
+       if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
+               printf("hash tree directory\n");
+               goto fail;
+       }
        /* check if the filename is already present in root */
-       existing_file_inodeno = ext4fs_filename_check(filename);
+       existing_file_inodeno = ext4fs_filename_unlink(filename);
        if (existing_file_inodeno != -1) {
                ret = ext4fs_delete_file(existing_file_inodeno);
                fs->first_pass_bbmap = 0;
@@ -894,39 +897,42 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
        }
        blocks_remaining = blks_reqd_for_file;
        /* test for available space in partition */
-       if (fs->sb->free_blocks < blks_reqd_for_file) {
+       if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
                printf("Not enough space on partition !!!\n");
                goto fail;
        }
 
-       ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+       inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
+       if (inodeno == -1)
+               goto fail;
        /* prepare file inode */
        inode_buffer = zalloc(fs->inodesz);
        if (!inode_buffer)
                goto fail;
        file_inode = (struct ext2_inode *)inode_buffer;
-       file_inode->mode = S_IFREG | S_IRWXU |
-           S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
+       file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
+           S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
        /* ToDo: Update correct time */
-       file_inode->mtime = timestamp;
-       file_inode->atime = timestamp;
-       file_inode->ctime = timestamp;
-       file_inode->nlinks = 1;
-       file_inode->size = sizebytes;
+       file_inode->mtime = cpu_to_le32(timestamp);
+       file_inode->atime = cpu_to_le32(timestamp);
+       file_inode->ctime = cpu_to_le32(timestamp);
+       file_inode->nlinks = cpu_to_le16(1);
+       file_inode->size = cpu_to_le32(sizebytes);
 
        /* Allocate data blocks */
        ext4fs_allocate_blocks(file_inode, blocks_remaining,
                               &blks_reqd_for_file);
-       file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) >>
-               fs->dev_desc->log2blksz;
+       file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
+               fs->dev_desc->log2blksz);
 
        temp_ptr = zalloc(fs->blksz);
        if (!temp_ptr)
                goto fail;
-       ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
+       ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
        inodeno--;
-       itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
-                       (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
+       bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
+       itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
+                       (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
                        inodes_per_block;
        blkoff = (inodeno % inodes_per_block) * fs->inodesz;
        ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
@@ -940,13 +946,15 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
        /* copy the file content into data blocks */
        if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
                printf("Error in copying content\n");
+               /* FIXME: Deallocate data blocks */
                goto fail;
        }
-       ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
+       ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
        parent_inodeno--;
-       parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
+       bgd = ext4fs_get_group_descriptor(fs, ibmap_idx);
+       parent_itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) +
            (parent_inodeno %
-            __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
+            le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
        blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
        if (parent_itable_blkno != itable_blkno) {
                memset(temp_ptr, '\0', fs->blksz);
@@ -955,22 +963,18 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
                if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
                        goto fail;
 
-               memcpy(temp_ptr + blkoff, g_parent_inode,
-                       sizeof(struct ext2_inode));
+               memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
                if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
                        goto fail;
-               free(temp_ptr);
        } else {
                /*
                 * If parent and child fall in same inode table block
                 * both should be kept in 1 buffer
                 */
-               memcpy(temp_ptr + blkoff, g_parent_inode,
-                      sizeof(struct ext2_inode));
+               memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
                gd_index--;
                if (ext4fs_put_metadata(temp_ptr, itable_blkno))
                        goto fail;
-               free(temp_ptr);
        }
        ext4fs_update();
        ext4fs_deinit();
@@ -981,6 +985,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
        fs->curr_inode_no = 0;
        free(inode_buffer);
        free(g_parent_inode);
+       free(temp_ptr);
        g_parent_inode = NULL;
 
        return 0;
@@ -988,7 +993,34 @@ fail:
        ext4fs_deinit();
        free(inode_buffer);
        free(g_parent_inode);
+       free(temp_ptr);
        g_parent_inode = NULL;
 
        return -1;
 }
+
+int ext4_write_file(const char *filename, void *buf, loff_t offset,
+                   loff_t len, loff_t *actwrite)
+{
+       int ret;
+
+       if (offset != 0) {
+               printf("** Cannot support non-zero offset **\n");
+               return -1;
+       }
+
+       ret = ext4fs_write(filename, buf, len);
+       if (ret) {
+               printf("** Error ext4fs_write() **\n");
+               goto fail;
+       }
+
+       *actwrite = len;
+
+       return 0;
+
+fail:
+       *actwrite = 0;
+
+       return -1;
+}