ext4_mkfs: improve block group init performance
[lwext4.git] / src / ext4_mkfs.c
index e331c0dd1bec718a7a610eb244a54a7ad92d6fb8..e047d46f10bbd5beed71373f234dc74d3fd8d77a 100644 (file)
  */
 
 #include "ext4_config.h"
+#include "ext4_types.h"
+#include "ext4_misc.h"
+#include "ext4_errno.h"
+#include "ext4_debug.h"
+
 #include "ext4_super.h"
 #include "ext4_block_group.h"
 #include "ext4_dir.h"
 #include "ext4_dir_idx.h"
 #include "ext4_fs.h"
 #include "ext4_inode.h"
-#include "ext4_debug.h"
 #include "ext4_ialloc.h"
 #include "ext4_mkfs.h"
 
 #include <string.h>
 #include <stdlib.h>
 
-#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
-#define EXT4_ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
-
 struct fs_aux_info {
        struct ext4_sblock *sb;
-       struct ext4_bgroup *bg_desc;
+       uint8_t *bg_desc_blk;
        struct xattr_list_element *xattrs;
        uint32_t first_data_block;
        uint64_t len_blocks;
@@ -105,14 +106,14 @@ static uint32_t compute_blocks_per_group(struct ext4_mkfs_info *info)
 
 static uint32_t compute_inodes(struct ext4_mkfs_info *info)
 {
-       return (uint32_t)DIV_ROUND_UP(info->len, info->block_size) / 4;
+       return (uint32_t)EXT4_DIV_ROUND_UP(info->len, info->block_size) / 4;
 }
 
 static uint32_t compute_inodes_per_group(struct ext4_mkfs_info *info)
 {
-       uint32_t blocks = (uint32_t)DIV_ROUND_UP(info->len, info->block_size);
-       uint32_t block_groups = DIV_ROUND_UP(blocks, info->blocks_per_group);
-       uint32_t inodes = DIV_ROUND_UP(info->inodes, block_groups);
+       uint32_t blocks = (uint32_t)EXT4_DIV_ROUND_UP(info->len, info->block_size);
+       uint32_t block_groups = EXT4_DIV_ROUND_UP(blocks, info->blocks_per_group);
+       uint32_t inodes = EXT4_DIV_ROUND_UP(info->inodes, block_groups);
        inodes = EXT4_ALIGN(inodes, (info->block_size / info->inode_size));
 
        /* After properly rounding up the number of inodes/group,
@@ -126,7 +127,7 @@ static uint32_t compute_inodes_per_group(struct ext4_mkfs_info *info)
 
 static uint32_t compute_journal_blocks(struct ext4_mkfs_info *info)
 {
-       uint32_t journal_blocks = (uint32_t)DIV_ROUND_UP(info->len,
+       uint32_t journal_blocks = (uint32_t)EXT4_DIV_ROUND_UP(info->len,
                                                 info->block_size) / 64;
        if (journal_blocks < 1024)
                journal_blocks = 1024;
@@ -148,9 +149,9 @@ static int create_fs_aux_info(struct fs_aux_info *aux_info,
 {
        aux_info->first_data_block = (info->block_size > 1024) ? 0 : 1;
        aux_info->len_blocks = info->len / info->block_size;
-       aux_info->inode_table_blocks = DIV_ROUND_UP(info->inodes_per_group *
+       aux_info->inode_table_blocks = EXT4_DIV_ROUND_UP(info->inodes_per_group *
                        info->inode_size, info->block_size);
-       aux_info->groups = (uint32_t)DIV_ROUND_UP(aux_info->len_blocks -
+       aux_info->groups = (uint32_t)EXT4_DIV_ROUND_UP(aux_info->len_blocks -
                        aux_info->first_data_block, info->blocks_per_group);
        aux_info->blocks_per_ind = info->block_size / sizeof(uint32_t);
        aux_info->blocks_per_dind =
@@ -159,7 +160,7 @@ static int create_fs_aux_info(struct fs_aux_info *aux_info,
                        aux_info->blocks_per_dind * aux_info->blocks_per_dind;
 
        aux_info->bg_desc_blocks =
-               DIV_ROUND_UP(aux_info->groups * info->dsc_size,
+               EXT4_DIV_ROUND_UP(aux_info->groups * info->dsc_size,
                        info->block_size);
 
        aux_info->default_i_flags = EXT4_INODE_FLAG_NOATIME;
@@ -179,8 +180,8 @@ static int create_fs_aux_info(struct fs_aux_info *aux_info,
        if (!aux_info->sb)
                return ENOMEM;
 
-       aux_info->bg_desc = calloc(aux_info->groups, sizeof(struct ext4_bgroup));
-       if (!aux_info->bg_desc)
+       aux_info->bg_desc_blk = calloc(1, info->block_size);
+       if (!aux_info->bg_desc_blk)
                return ENOMEM;
 
        aux_info->xattrs = NULL;
@@ -213,8 +214,8 @@ static void release_fs_aux_info(struct fs_aux_info *aux_info)
 {
        if (aux_info->sb)
                free(aux_info->sb);
-       if (aux_info->bg_desc)
-               free(aux_info->bg_desc);
+       if (aux_info->bg_desc_blk)
+               free(aux_info->bg_desc_blk);
 }
 
 
@@ -293,116 +294,107 @@ static void fill_in_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info
        sb->flags = to_le32(EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH);
 }
 
-static void fill_bgroups(struct fs_aux_info *aux_info,
-                        struct ext4_mkfs_info *info)
-{
-       uint32_t i;
 
-       uint32_t bg_free_blk = 0;
-       uint64_t sb_free_blk = 0;
+static int write_bgroup_block(struct ext4_blockdev *bd,
+                             struct fs_aux_info *aux_info,
+                             struct ext4_mkfs_info *info,
+                             uint32_t blk)
+{
+       int r = EOK;
+       uint32_t j;
+       struct ext4_block b;
 
-       for (i = 0; i < aux_info->groups; i++) {
+       uint32_t block_size = ext4_sb_get_block_size(aux_info->sb);
 
+       for (j = 0; j < aux_info->groups; j++) {
                uint64_t bg_start_block = aux_info->first_data_block +
-                       aux_info->first_data_block + i * info->blocks_per_group;
+                                         j * info->blocks_per_group;
                uint32_t blk_off = 0;
 
-               bg_free_blk = info->blocks_per_group -
-                               aux_info->inode_table_blocks;
-
-               bg_free_blk -= 2;
                blk_off += aux_info->bg_desc_blocks;
-
-               if (i == (aux_info->groups - 1))
-                       bg_free_blk -= aux_info->first_data_block;
-
-               if (has_superblock(info, i)) {
+               if (has_superblock(info, j)) {
                        bg_start_block++;
                        blk_off += info->bg_desc_reserve_blocks;
-                       bg_free_blk -= info->bg_desc_reserve_blocks + 1;
-                       bg_free_blk -= aux_info->bg_desc_blocks;
                }
 
-               ext4_bg_set_block_bitmap(&aux_info->bg_desc[i], aux_info->sb,
-                               bg_start_block + blk_off + 1);
-
-               ext4_bg_set_inode_bitmap(&aux_info->bg_desc[i], aux_info->sb,
-                               bg_start_block + blk_off + 2);
-
-               ext4_bg_set_inode_table_first_block(&aux_info->bg_desc[i],
-                               aux_info->sb,
-                               bg_start_block + blk_off + 3);
-
-               ext4_bg_set_free_blocks_count(&aux_info->bg_desc[i],
-                               aux_info->sb, bg_free_blk);
-
-               ext4_bg_set_free_inodes_count(&aux_info->bg_desc[i],
-                               aux_info->sb, aux_info->sb->inodes_per_group);
+               uint64_t dsc_blk = bg_start_block + blk;
 
-               ext4_bg_set_used_dirs_count(&aux_info->bg_desc[i], aux_info->sb,
-                                           0);
+               r = ext4_block_get_noread(bd, &b, dsc_blk);
+               if (r != EOK)
+                       return r;
 
-               ext4_bg_set_flag(&aux_info->bg_desc[i],
-                               EXT4_BLOCK_GROUP_BLOCK_UNINIT |
-                               EXT4_BLOCK_GROUP_INODE_UNINIT);
+               memcpy(b.data, aux_info->bg_desc_blk, block_size);
 
-               sb_free_blk += bg_free_blk;
+               ext4_bcache_set_dirty(b.buf);
+               r = ext4_block_set(bd, &b);
+               if (r != EOK)
+                       return r;
        }
 
-       ext4_sb_set_free_blocks_cnt(aux_info->sb, sb_free_blk);
+       return r;
 }
 
-
 static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
                         struct ext4_mkfs_info *info)
 {
-       int r;
-       uint32_t i;
+       int r = EOK;
+
        struct ext4_block b;
+       struct ext4_bgroup *bg_desc;
+
+       uint32_t i;
+       uint32_t bg_free_blk = 0;
+       uint64_t sb_free_blk = 0;
+       uint32_t block_size = ext4_sb_get_block_size(aux_info->sb);
+       uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb);
+       uint32_t dsc_per_block = block_size / dsc_size;
+       uint32_t k = 0;
+
        for (i = 0; i < aux_info->groups; i++) {
                uint64_t bg_start_block = aux_info->first_data_block +
-                       + i * info->blocks_per_group;
+                       aux_info->first_data_block + i * info->blocks_per_group;
                uint32_t blk_off = 0;
 
+               bg_desc = (void *)(aux_info->bg_desc_blk + k * dsc_size);
+               bg_free_blk = info->blocks_per_group -
+                               aux_info->inode_table_blocks;
+
+               bg_free_blk -= 2;
                blk_off += aux_info->bg_desc_blocks;
+
+               if (i == (aux_info->groups - 1))
+                       bg_free_blk -= aux_info->first_data_block;
+
                if (has_superblock(info, i)) {
                        bg_start_block++;
                        blk_off += info->bg_desc_reserve_blocks;
+                       bg_free_blk -= info->bg_desc_reserve_blocks + 1;
+                       bg_free_blk -= aux_info->bg_desc_blocks;
                }
 
-               uint32_t block_size = ext4_sb_get_block_size(aux_info->sb);
-               uint32_t dsc_pos = 0;
-               uint32_t dsc_id = 0;
-               uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb);
-               uint32_t dsc_blk_cnt = aux_info->bg_desc_blocks;
-               uint64_t dsc_blk = bg_start_block;
+               ext4_bg_set_block_bitmap(bg_desc, aux_info->sb,
+                                        bg_start_block + blk_off + 1);
 
-               while (dsc_blk_cnt--) {
-                       r = ext4_block_get(bd, &b, dsc_blk++);
-                       if (r != EOK)
-                               return r;
+               ext4_bg_set_inode_bitmap(bg_desc, aux_info->sb,
+                                        bg_start_block + blk_off + 2);
+
+               ext4_bg_set_inode_table_first_block(bg_desc,
+                                               aux_info->sb,
+                                               bg_start_block + blk_off + 3);
 
-                       dsc_pos = 0;
-                       while (dsc_pos + dsc_size <= block_size) {
-                               memcpy(b.data + dsc_pos,
-                                      &aux_info->bg_desc[dsc_id],
-                                      dsc_size);
+               ext4_bg_set_free_blocks_count(bg_desc, aux_info->sb,
+                                             bg_free_blk);
 
-                               dsc_pos += dsc_size;
-                               dsc_id++;
+               ext4_bg_set_free_inodes_count(bg_desc,
+                               aux_info->sb, aux_info->sb->inodes_per_group);
 
-                               if (dsc_id == aux_info->groups)
-                                       break;
-                       }
+               ext4_bg_set_used_dirs_count(bg_desc, aux_info->sb, 0);
 
-                       ext4_bcache_set_dirty(b.buf);
-                       r = ext4_block_set(bd, &b);
-                       if (r != EOK)
-                               return r;
+               ext4_bg_set_flag(bg_desc,
+                                EXT4_BLOCK_GROUP_BLOCK_UNINIT |
+                                EXT4_BLOCK_GROUP_INODE_UNINIT);
 
-                       if (dsc_id == aux_info->groups)
-                               break;
-               }
+               sb_free_blk += bg_free_blk;
 
                r = ext4_block_get_noread(bd, &b, bg_start_block + blk_off + 1);
                if (r != EOK)
@@ -420,9 +412,22 @@ static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
                r = ext4_block_set(bd, &b);
                if (r != EOK)
                        return r;
+
+               if (++k != dsc_per_block)
+                       continue;
+
+               k = 0;
+               r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block);
+               if (r != EOK)
+                       return r;
+
        }
 
+       r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block);
+       if (r != EOK)
+               return r;
 
+       ext4_sb_set_free_blocks_cnt(aux_info->sb, sb_free_blk);
        return r;
 }
 
@@ -491,8 +496,6 @@ static int mkfs_initial(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
                goto Finish;
 
        fill_in_sb(&aux_info, info);
-       fill_bgroups(&aux_info, info);
-
 
        r = write_bgroups(bd, &aux_info, info);
        if (r != EOK)