Add a little more logging to mkfs.
[lwext4.git] / src / ext4_mkfs.c
index c32193ad713fb35cdf3a59955a15a4ad880471fe..60346ef1b11f927bdf3cd7a13a464e95762cb49a 100644 (file)
  * @brief
  */
 
-#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_ialloc.h"
-#include "ext4_mkfs.h"
+#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_ialloc.h>
+#include <ext4_mkfs.h>
 
 #include <inttypes.h>
 #include <string.h>
@@ -55,7 +55,7 @@
 
 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;
@@ -95,6 +95,7 @@ static int sb2info(struct ext4_sblock *sb, struct ext4_mkfs_info *info)
        info->label = sb->volume_name;
        info->len = (uint64_t)info->block_size * ext4_sb_get_blocks_cnt(sb);
        info->dsc_size = to_le16(sb->desc_size);
+       memcpy(info->uuid, sb->uuid, UUID_SIZE);
 
        return EOK;
 }
@@ -176,12 +177,12 @@ static int create_fs_aux_info(struct fs_aux_info *aux_info,
                aux_info->len_blocks -= last_group_size;
        }
 
-       aux_info->sb = calloc(1, EXT4_SUPERBLOCK_SIZE);
+       aux_info->sb = ext4_calloc(1, EXT4_SUPERBLOCK_SIZE);
        if (!aux_info->sb)
                return ENOMEM;
 
-       aux_info->bg_desc = calloc(1, sizeof(struct ext4_bgroup));
-       if (!aux_info->bg_desc)
+       aux_info->bg_desc_blk = ext4_calloc(1, info->block_size);
+       if (!aux_info->bg_desc_blk)
                return ENOMEM;
 
        aux_info->xattrs = NULL;
@@ -213,14 +214,14 @@ static int create_fs_aux_info(struct fs_aux_info *aux_info,
 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);
+               ext4_free(aux_info->sb);
+       if (aux_info->bg_desc_blk)
+               ext4_free(aux_info->bg_desc_blk);
 }
 
 
 /* Fill in the superblock memory buffer based on the filesystem parameters */
-static void fill_in_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info)
+static void fill_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info)
 {
        struct ext4_sblock *sb = aux_info->sb;
 
@@ -260,10 +261,10 @@ static void fill_in_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info
        sb->features_incompatible = to_le32(info->feat_incompat);
        sb->features_read_only = to_le32(info->feat_ro_compat);
 
-       memset(sb->uuid, 0, sizeof(sb->uuid));
+       memcpy(sb->uuid, info->uuid, UUID_SIZE);
 
        memset(sb->volume_name, 0, sizeof(sb->volume_name));
-       strncpy(sb->volume_name, info->label, sizeof(sb->volume_name));
+       strncpy(sb->volume_name, info->label, sizeof(sb->volume_name) - 1);
        memset(sb->last_mounted, 0, sizeof(sb->last_mounted));
 
        sb->algorithm_usage_bitmap = to_le32(0);
@@ -273,6 +274,8 @@ static void fill_in_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info
 
        if (info->feat_compat & EXT4_FCOM_HAS_JOURNAL)
                sb->journal_inode_number = to_le32(EXT4_JOURNAL_INO);
+
+       sb->journal_backup_type = 1;
        sb->journal_dev = to_le32(0);
        sb->last_orphan = to_le32(0);
        sb->hash_seed[0] = to_le32(0x11111111);
@@ -295,31 +298,45 @@ static void fill_in_sb(struct fs_aux_info *aux_info, struct ext4_mkfs_info *info
 }
 
 
-
-static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
-                        struct ext4_mkfs_info *info)
+static int write_bgroups(struct ext4_fs *fs, struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
+                        struct ext4_mkfs_info *info, ext4_progress progress, void* progress_context)
 {
-       int r = EOK;
-       uint32_t i, j;
+       /* size of the group descriptor */
+       uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb);
+       uint32_t block_size = ext4_sb_get_block_size(aux_info->sb);
+
+       /* Calculate the group descriptors chunk that will be written to each block group */
+
+       /* The whole set of group descriptors */
+       void* all_bg_desc = ext4_calloc(1, aux_info->groups * dsc_size);
+       if (!all_bg_desc) {
+               return ENOMEM;
+       }
+
        uint32_t bg_free_blk = 0;
        uint64_t sb_free_blk = 0;
-       struct ext4_block b;
-
-       uint32_t block_size = ext4_sb_get_block_size(aux_info->sb);
 
-       for (i = 0; i < aux_info->groups; i++) {
+       for (uint32_t i = 0; i < aux_info->groups; i++) {
                uint64_t bg_start_block = aux_info->first_data_block +
                        aux_info->first_data_block + i * info->blocks_per_group;
                uint32_t blk_off = 0;
 
-               bg_free_blk = info->blocks_per_group -
-                               aux_info->inode_table_blocks;
+               struct ext4_bgroup* bg_desc = (struct ext4_bgroup *) (((char *) all_bg_desc) + i * dsc_size);
+
+               uint32_t blocks_in_group = info->blocks_per_group;
+               if (i == aux_info->groups - 1) {
+                       blocks_in_group = (uint32_t)
+                               (ext4_sb_get_blocks_cnt(aux_info->sb) - ext4_get32(aux_info->sb, first_data_block) - info->blocks_per_group * (ext4_block_group_cnt(aux_info->sb) - 1));
+               }
+
+               bg_free_blk = blocks_in_group - aux_info->inode_table_blocks;
 
                bg_free_blk -= 2;
                blk_off += aux_info->bg_desc_blocks;
 
-               if (i == (aux_info->groups - 1))
+               if (i == (aux_info->groups - 1)) {
                        bg_free_blk -= aux_info->first_data_block;
+               }
 
                if (has_superblock(info, i)) {
                        bg_start_block++;
@@ -328,83 +345,70 @@ static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
                        bg_free_blk -= aux_info->bg_desc_blocks;
                }
 
-               ext4_bg_set_block_bitmap(aux_info->bg_desc, aux_info->sb,
-                               bg_start_block + blk_off + 1);
+               ext4_bg_set_block_bitmap(bg_desc, aux_info->sb,
+                                        bg_start_block + blk_off + 1);
 
-               ext4_bg_set_inode_bitmap(aux_info->bg_desc, aux_info->sb,
-                               bg_start_block + blk_off + 2);
+               ext4_bg_set_inode_bitmap(bg_desc, aux_info->sb,
+                                        bg_start_block + blk_off + 2);
 
-               ext4_bg_set_inode_table_first_block(aux_info->bg_desc,
-                               aux_info->sb,
-                               bg_start_block + blk_off + 3);
+               ext4_bg_set_inode_table_first_block(bg_desc,
+                                               aux_info->sb,
+                                               bg_start_block + blk_off + 3);
 
-               ext4_bg_set_free_blocks_count(aux_info->bg_desc,
-                               aux_info->sb, bg_free_blk);
+               ext4_bg_set_free_blocks_count(bg_desc, aux_info->sb,
+                                             bg_free_blk);
 
-               ext4_bg_set_free_inodes_count(aux_info->bg_desc,
-                               aux_info->sb, aux_info->sb->inodes_per_group);
+               ext4_bg_set_free_inodes_count(bg_desc,
+                               aux_info->sb, to_le32(aux_info->sb->inodes_per_group));
 
-               ext4_bg_set_used_dirs_count(aux_info->bg_desc, aux_info->sb,
-                                           0);
+               ext4_bg_set_used_dirs_count(bg_desc, aux_info->sb, 0);
 
-               ext4_bg_set_flag(aux_info->bg_desc,
-                               EXT4_BLOCK_GROUP_BLOCK_UNINIT |
-                               EXT4_BLOCK_GROUP_INODE_UNINIT);
+               ext4_bg_set_flag(bg_desc,
+                                EXT4_BLOCK_GROUP_BLOCK_UNINIT |
+                                EXT4_BLOCK_GROUP_INODE_UNINIT);
 
                sb_free_blk += bg_free_blk;
+       }
 
+       /* Write the block group headers */
 
-               for (j = 0; j < aux_info->groups; j++) {
-                       uint64_t bg_start_block = aux_info->first_data_block +
-                                                 j * info->blocks_per_group;
-                       uint32_t blk_off = 0;
-
-                       blk_off += aux_info->bg_desc_blocks;
-                       if (has_superblock(info, j)) {
-                               bg_start_block++;
-                               blk_off += info->bg_desc_reserve_blocks;
-                       }
+       int r = EOK;
 
+       for (uint32_t i = 0; i < aux_info->groups; i++) {
+               if (progress) {
+                       progress(progress_context, (float) i / aux_info->groups);
+               }
 
-                       uint32_t dsc_pos = 0;
-                       uint32_t dsc_size = ext4_sb_get_desc_size(aux_info->sb);
-                       uint64_t dsc_blk = bg_start_block +
-                                          i * dsc_size / block_size;
+               uint64_t bg_start_block = aux_info->first_data_block +
+                       aux_info->first_data_block + i * info->blocks_per_group;
+               uint32_t blk_off = 0;
 
-                       r = ext4_block_get(bd, &b, dsc_blk);
-                       if (r != EOK)
-                               return r;
+               if (has_superblock(info, i)) {
+                       bg_start_block++;
+                       blk_off += info->bg_desc_reserve_blocks;
+               }
 
-                       dsc_pos = (i * dsc_size) % block_size;
-                       memcpy(b.data + dsc_pos,
-                                       aux_info->bg_desc,
-                                       dsc_size);
+               /* Group descriptors */
+               ext4_block_writebytes(bd, (bg_start_block + blk_off) * block_size, all_bg_desc, aux_info->groups * dsc_size);
 
+               blk_off += aux_info->bg_desc_blocks;
 
-                       ext4_bcache_set_dirty(b.buf);
-                       r = ext4_block_set(bd, &b);
-                       if (r != EOK)
-                               return r;
+               struct ext4_block_group_ref ref;
+               r = ext4_fs_get_block_group_ref(fs, i, &ref);
+               if (r != EOK) {
+                       free(all_bg_desc);
+                       break;
                }
 
-               r = ext4_block_get_noread(bd, &b, bg_start_block + blk_off + 1);
-               if (r != EOK)
-                       return r;
-               memset(b.data, 0, block_size);
-               ext4_bcache_set_dirty(b.buf);
-               r = ext4_block_set(bd, &b);
-               if (r != EOK)
-                       return r;
-               r = ext4_block_get_noread(bd, &b, bg_start_block + blk_off + 2);
-               if (r != EOK)
-                       return r;
-               memset(b.data, 0, block_size);
-               ext4_bcache_set_dirty(b.buf);
-               r = ext4_block_set(bd, &b);
-               if (r != EOK)
-                       return r;
+               r = ext4_fs_put_block_group_ref(&ref);
+               if (r != EOK) {
+                       free(all_bg_desc);
+                       break;
+               }
        }
 
+       free(all_bg_desc);
+
        ext4_sb_set_free_blocks_cnt(aux_info->sb, sb_free_blk);
        return r;
 }
@@ -445,7 +449,7 @@ int ext4_mkfs_read_info(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
        if (r != EOK)
                return r;
 
-       sb = malloc(EXT4_SUPERBLOCK_SIZE);
+       sb = ext4_malloc(EXT4_SUPERBLOCK_SIZE);
        if (!sb)
                goto Finish;
 
@@ -458,12 +462,12 @@ int ext4_mkfs_read_info(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
 
 Finish:
        if (sb)
-               free(sb);
+               ext4_free(sb);
        ext4_block_fini(bd);
        return r;
 }
 
-static int mkfs_initial(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
+static int mkfs_init(struct ext4_fs *fs, struct ext4_blockdev *bd, struct ext4_mkfs_info *info, ext4_progress progress, void* progress_context)
 {
        int r;
        struct fs_aux_info aux_info;
@@ -473,12 +477,15 @@ static int mkfs_initial(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
        if (r != EOK)
                goto Finish;
 
-       fill_in_sb(&aux_info, info);
+       fill_sb(&aux_info, info);
+       memcpy(&fs->sb, aux_info.sb, sizeof(struct ext4_sblock));
 
-       r = write_bgroups(bd, &aux_info, info);
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "mkfs_init: write_bgroups");
+       r = write_bgroups(fs, bd, &aux_info, info, progress, progress_context);
        if (r != EOK)
                goto Finish;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "mkfs_init: write_sblocks");
        r = write_sblocks(bd, &aux_info, info);
        if (r != EOK)
                goto Finish;
@@ -488,24 +495,6 @@ static int mkfs_initial(struct ext4_blockdev *bd, struct ext4_mkfs_info *info)
        return r;
 }
 
-static int init_bgs(struct ext4_fs *fs)
-{
-       int r = EOK;
-       struct ext4_block_group_ref ref;
-       uint32_t i;
-       uint32_t bg_count = ext4_block_group_cnt(&fs->sb);
-       for (i = 0; i < bg_count; ++i) {
-               r = ext4_fs_get_block_group_ref(fs, i, &ref);
-               if (r != EOK)
-                       break;
-
-               r = ext4_fs_put_block_group_ref(&ref);
-               if (r != EOK)
-                       break;
-       }
-       return r;
-}
-
 static int alloc_inodes(struct ext4_fs *fs)
 {
        int r = EOK;
@@ -519,6 +508,8 @@ static int alloc_inodes(struct ext4_fs *fs)
                case EXT4_GOOD_OLD_FIRST_INO:
                        filetype = EXT4_DE_DIR;
                        break;
+               default:
+                       break;
                }
 
                r = ext4_fs_alloc_inode(fs, &inode_ref, filetype);
@@ -526,6 +517,14 @@ static int alloc_inodes(struct ext4_fs *fs)
                        return r;
 
                ext4_inode_set_mode(&fs->sb, inode_ref.inode, 0);
+
+               switch (i) {
+               case EXT4_ROOT_INO:
+               case EXT4_JOURNAL_INO:
+                       ext4_fs_inode_blocks_init(fs, &inode_ref);
+                       break;
+               }
+
                ext4_fs_put_inode_ref(&inode_ref);
        }
 
@@ -599,11 +598,79 @@ static int create_dirs(struct ext4_fs *fs)
        return r;
 }
 
+static int create_journal_inode(struct ext4_fs *fs,
+                               struct ext4_mkfs_info *info)
+{
+       int ret;
+       struct ext4_inode_ref inode_ref;
+       uint64_t blocks_count;
+
+       if (!info->journal)
+               return EOK;
+
+       ret = ext4_fs_get_inode_ref(fs, EXT4_JOURNAL_INO, &inode_ref);
+       if (ret != EOK)
+               return ret;
+
+       struct ext4_inode *inode = inode_ref.inode;
+
+       ext4_inode_set_mode(&fs->sb, inode, EXT4_INODE_MODE_FILE | 0600);
+       ext4_inode_set_links_cnt(inode, 1);
+
+       blocks_count = ext4_inode_get_blocks_count(&fs->sb, inode);
+
+       while (blocks_count++ < info->journal_blocks)
+       {
+               ext4_fsblk_t fblock;
+               ext4_lblk_t iblock;
+               struct ext4_block blk;
+
+               ret = ext4_fs_append_inode_dblk(&inode_ref, &fblock, &iblock);
+               if (ret != EOK)
+                       goto Finish;
+
+               if (iblock != 0)
+                       continue;
+
+               ret = ext4_block_get(fs->bdev, &blk, fblock);
+               if (ret != EOK)
+                       goto Finish;
+
+
+               struct jbd_sb * jbd_sb = (struct jbd_sb * )blk.data;
+               memset(jbd_sb, 0, sizeof(struct jbd_sb));
+
+               jbd_sb->header.magic = to_be32(JBD_MAGIC_NUMBER);
+               jbd_sb->header.blocktype = to_be32(JBD_SUPERBLOCK_V2);
+               jbd_sb->blocksize = to_be32(info->block_size);
+               jbd_sb->maxlen = to_be32(info->journal_blocks);
+               jbd_sb->nr_users = to_be32(1);
+               jbd_sb->first = to_be32(1);
+               jbd_sb->sequence = to_be32(1);
+
+               ext4_bcache_set_dirty(blk.buf);
+               ret = ext4_block_set(fs->bdev, &blk);
+               if (ret != EOK)
+                       goto Finish;
+       }
+
+       memcpy(fs->sb.journal_blocks, inode->blocks, sizeof(inode->blocks));
+
+       Finish:
+       ext4_fs_put_inode_ref(&inode_ref);
+
+       return ret;
+}
+
 int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd,
-             struct ext4_mkfs_info *info, int fs_type)
+             struct ext4_mkfs_info *info, int fs_type, ext4_progress progress, void* progress_context)
 {
        int r;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_mkfs start");
+
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_block_init");
+
        r = ext4_block_init(bd);
        if (r != EOK)
                return r;
@@ -611,7 +678,7 @@ int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd,
        bd->fs = fs;
 
        if (info->len == 0)
-               info->len = bd->bdif->ph_bcnt * bd->bdif->ph_bsize;
+               info->len = bd->part_size;
 
        if (info->block_size == 0)
                info->block_size = 4096; /*Set block size to default value*/
@@ -654,14 +721,19 @@ int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd,
                break;
        }
 
-       /*TODO: handle this features*/
+       /*TODO: handle this features some day...*/
        info->feat_incompat &= ~EXT4_FINCOM_META_BG;
        info->feat_incompat &= ~EXT4_FINCOM_FLEX_BG;
+       info->feat_incompat &= ~EXT4_FINCOM_64BIT;
+
        info->feat_ro_compat &= ~EXT4_FRO_COM_METADATA_CSUM;
+       info->feat_ro_compat &= ~EXT4_FRO_COM_GDT_CSUM;
+       info->feat_ro_compat &= ~EXT4_FRO_COM_DIR_NLINK;
+       info->feat_ro_compat &= ~EXT4_FRO_COM_EXTRA_ISIZE;
+       info->feat_ro_compat &= ~EXT4_FRO_COM_HUGE_FILE;
 
-       /*TODO: handle journal feature & inode*/
-       if (info->journal == 0)
-               info->feat_compat |= 0;
+       if (info->journal)
+               info->feat_compat |= EXT4_FCOM_HAS_JOURNAL;
 
        if (info->dsc_size == 0) {
 
@@ -701,50 +773,76 @@ int ext4_mkfs(struct ext4_fs *fs, struct ext4_blockdev *bd,
        ext4_dbg(DEBUG_MKFS, DBG_NONE "Label: %s\n", info->label);
 
        struct ext4_bcache bc;
+
        memset(&bc, 0, sizeof(struct ext4_bcache));
        ext4_block_set_lb_size(bd, info->block_size);
+
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_bcache_init_dynamic");
+
        r = ext4_bcache_init_dynamic(&bc, CONFIG_BLOCK_DEV_CACHE_SIZE,
                                      info->block_size);
        if (r != EOK)
                goto block_fini;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_block_bind_bcache");
+
        /*Bind block cache to block device*/
        r = ext4_block_bind_bcache(bd, &bc);
        if (r != EOK)
                goto cache_fini;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_block_cache_write_back");
+
        r = ext4_block_cache_write_back(bd, 1);
        if (r != EOK)
                goto cache_fini;
 
-       r = mkfs_initial(bd, info);
+       fs->bdev = bd;
+       fs->read_only = false;
+
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "mkfs_init");
+
+       r = mkfs_init(fs, bd, info, progress, progress_context);
        if (r != EOK)
                goto cache_fini;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_fs_init");
+
        r = ext4_fs_init(fs, bd, false);
        if (r != EOK)
                goto cache_fini;
 
-       r = init_bgs(fs);
-       if (r != EOK)
-               goto fs_fini;
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "alloc_inodes");
 
        r = alloc_inodes(fs);
        if (r != EOK)
                goto fs_fini;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "create_dirs");
+
        r = create_dirs(fs);
        if (r != EOK)
                goto fs_fini;
 
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "create_journal_inode");
+
+       r = create_journal_inode(fs, info);
+       if (r != EOK)
+               goto fs_fini;
+
        fs_fini:
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_fs_fini");
        ext4_fs_fini(fs);
 
        cache_fini:
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_block_cache_write_back");
        ext4_block_cache_write_back(bd, 0);
+
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_bcache_fini_dynamic");
        ext4_bcache_fini_dynamic(&bc);
 
        block_fini:
+       ext4_dbg(DEBUG_MKFS, DBG_NONE "ext4_block_fini");
        ext4_block_fini(bd);
 
        return r;