]> 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 c55e2528e344264a01d96c6232a4a96701d476d3..d710a86d59c263eb0e2492b920b7f4917db1d9f8 100644 (file)
@@ -38,14 +38,30 @@ 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)
+static inline void ext4fs_bg_free_inodes_inc
+       (struct ext2_block_group *bg, const struct ext_filesystem *fs)
 {
-       bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) + 1);
+       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)
+static inline void ext4fs_bg_free_blocks_inc
+       (struct ext2_block_group *bg, const struct ext_filesystem *fs)
 {
-       bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) + 1);
+       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)
@@ -53,21 +69,26 @@ 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 = cpu_to_le16(ext4fs_checksum_update(i));
-               put_ext4((uint64_t)le32_to_cpu(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)le32_to_cpu(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);
        }
 
@@ -85,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 */
@@ -130,8 +148,6 @@ static void delete_single_indirect_block(struct ext2_inode *inode)
                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) {
@@ -144,18 +160,19 @@ static void delete_single_indirect_block(struct ext2_inode *inode)
                                bg_idx--;
                }
                ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
-               ext4fs_bg_free_blocks_inc(&bgd[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(
-                                          (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
-                                          fs->sect_perblk, 0, fs->blksz,
-                                          journal_buffer);
+                                          b_bitmap_blk * fs->sect_perblk,
+                                          0, fs->blksz, journal_buffer);
                        if (status == 0)
                                goto fail;
-                       if (ext4fs_log_journal
-                           (journal_buffer, le32_to_cpu(bgd[bg_idx].block_id)))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
@@ -182,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);
@@ -206,15 +221,18 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                                if (!remainder)
                                        bg_idx--;
                        }
+                       /* 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++;
-                       ext4fs_bg_free_blocks_inc(&bgd[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)le32_to_cpu(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);
@@ -222,7 +240,7 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                                        goto fail;
 
                                if (ext4fs_log_journal(journal_buffer,
-                                                       le32_to_cpu(bgd[bg_idx].block_id)))
+                                                      b_bitmap_blk))
                                        goto fail;
                                prev_bg_bmap_idx = bg_idx;
                        }
@@ -236,20 +254,20 @@ static void delete_double_indirect_block(struct ext2_inode *inode)
                        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);
-               ext4fs_bg_free_blocks_inc(&bgd[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)le32_to_cpu(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,
-                                               le32_to_cpu(bgd[bg_idx].block_id)))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
@@ -280,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);
@@ -320,13 +336,17 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                                                        bg_idx);
 
                                tip_buffer++;
-                               ext4fs_bg_free_blocks_inc(&bgd[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(
-                                                       (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
+                                                       b_bitmap_blk *
                                                        fs->sect_perblk, 0,
                                                        fs->blksz,
                                                        journal_buffer);
@@ -334,7 +354,7 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                                                goto fail;
 
                                        if (ext4fs_log_journal(journal_buffer,
-                                                              le32_to_cpu(bgd[bg_idx].block_id)))
+                                                              b_bitmap_blk))
                                                goto fail;
                                        prev_bg_bmap_idx = bg_idx;
                                }
@@ -356,21 +376,24 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                                                fs->blk_bmaps[bg_idx], bg_idx);
 
                        tigp_buffer++;
-                       ext4fs_bg_free_blocks_inc(&bgd[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);
                                memset(journal_buffer, '\0', fs->blksz);
-                               status =
-                                   ext4fs_devread(
-                                                  (lbaint_t)le32_to_cpu(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,
-                                                       le32_to_cpu(bgd[bg_idx].block_id)))
+                                                      b_bitmap_blk))
                                        goto fail;
                                prev_bg_bmap_idx = bg_idx;
                        }
@@ -385,20 +408,19 @@ static void delete_triple_indirect_block(struct ext2_inode *inode)
                                bg_idx--;
                }
                ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
-               ext4fs_bg_free_blocks_inc(&bgd[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) {
-                       memset(journal_buffer, '\0', fs->blksz);
-                       status = ext4fs_devread(
-                                               (lbaint_t)le32_to_cpu(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,
-                                               le32_to_cpu(bgd[bg_idx].block_id)))
+                       if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
                                goto fail;
                        prev_bg_bmap_idx = bg_idx;
                }
@@ -435,8 +457,6 @@ static int ext4fs_delete_file(int inodeno)
        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;
@@ -447,99 +467,62 @@ static int ext4fs_delete_file(int inodeno)
                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);
-                       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_EXTENTS Block releasing %ld: %d\n",
-                             blknr, bg_idx);
-
-                       ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
-                       ext4fs_sb_free_blocks_inc(fs->sb);
-
-                       /* journal backup */
-                       if (prev_bg_bmap_idx != bg_idx) {
-                               status =
-                                   ext4fs_devread(
-                                                  (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
-                                                  fs->sect_perblk, 0,
-                                                  fs->blksz, journal_buffer);
-                               if (status == 0)
-                                       goto fail;
-                               if (ext4fs_log_journal(journal_buffer,
-                                                       le32_to_cpu(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 = le32_to_cpu(inode.size) / fs->blksz;
-               if (le32_to_cpu(inode.size) % fs->blksz)
-                       no_blocks++;
-               for (i = 0; i < no_blocks; i++) {
-                       blknr = read_allocated_block(&inode, i);
-                       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("ActualB releasing %ld: %d\n", blknr, 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);
 
-                       ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
-                       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)le32_to_cpu(bgd[bg_idx].block_id)
-                                                       * fs->sect_perblk,
-                                                       0, fs->blksz,
-                                                       journal_buffer);
-                               if (status == 0)
-                                       goto fail;
-                               if (ext4fs_log_journal(journal_buffer,
-                                               le32_to_cpu(bgd[bg_idx].block_id)))
-                                       goto fail;
-                               prev_bg_bmap_idx = 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) +
+       /* 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 */
@@ -560,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))
@@ -569,15 +552,15 @@ 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);
-       ext4fs_bg_free_inodes_inc(&bgd[ibmap_idx]);
+       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)le32_to_cpu(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, le32_to_cpu(bgd[ibmap_idx].inode_id)))
+       if (ext4fs_log_journal(journal_buffer, ext4fs_bg_get_inode_id(bgd, fs)))
                goto fail;
 
        ext4fs_update();
@@ -609,7 +592,6 @@ int ext4fs_init(void)
 
        /* 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 */
@@ -635,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 *));
@@ -648,9 +629,9 @@ int ext4fs_init(void)
        }
 
        for (i = 0; i < fs->no_blkgrp; i++) {
-               status =
-                   ext4fs_devread(
-                                  (lbaint_t)le32_to_cpu(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)
@@ -668,8 +649,9 @@ int ext4fs_init(void)
        }
 
        for (i = 0; i < fs->no_blkgrp; i++) {
-               status = ext4fs_devread(
-                                       (lbaint_t)le32_to_cpu(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]);
@@ -683,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 + le16_to_cpu(fs->bgd[i].free_blocks);
-       if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks))
-               fs->sb->free_blocks = cpu_to_le32(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:
@@ -752,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
@@ -763,6 +748,10 @@ 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)
 {
@@ -789,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;
@@ -863,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, 256);
 
-       g_parent_inode = zalloc(sizeof(struct ext2_inode));
+       g_parent_inode = zalloc(fs->inodesz);
        if (!g_parent_inode)
                goto fail;
 
@@ -940,7 +930,8 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
                goto fail;
        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) +
+       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;
@@ -955,11 +946,13 @@ 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 / 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;
        blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
@@ -970,8 +963,7 @@ 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;
        } else {
@@ -979,8 +971,7 @@ int ext4fs_write(const char *fname, unsigned char *buffer,
                 * 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;