* @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>
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;
}
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_blk = calloc(1, info->block_size);
+ aux_info->bg_desc_blk = ext4_calloc(1, info->block_size);
if (!aux_info->bg_desc_blk)
return ENOMEM;
static void release_fs_aux_info(struct fs_aux_info *aux_info)
{
if (aux_info->sb)
- free(aux_info->sb);
+ ext4_free(aux_info->sb);
if (aux_info->bg_desc_blk)
- free(aux_info->bg_desc_blk);
+ ext4_free(aux_info->bg_desc_blk);
}
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);
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);
}
-static int write_bgroup_block(struct ext4_blockdev *bd,
- struct fs_aux_info *aux_info,
- struct ext4_mkfs_info *info,
- uint32_t blk)
+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 j;
- struct ext4_block b;
-
+ /* 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);
- 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;
+ /* Calculate the group descriptors chunk that will be written to each block group */
- blk_off += aux_info->bg_desc_blocks;
- if (has_superblock(info, j)) {
- bg_start_block++;
- blk_off += info->bg_desc_reserve_blocks;
- }
-
- uint64_t dsc_blk = bg_start_block + blk;
-
- r = ext4_block_get_noread(bd, &b, dsc_blk);
- if (r != EOK)
- return r;
-
- memcpy(b.data, aux_info->bg_desc_blk, block_size);
-
- ext4_bcache_set_dirty(b.buf);
- r = ext4_block_set(bd, &b);
- if (r != EOK)
- return r;
+ /* The whole set of group descriptors */
+ void* all_bg_desc = ext4_calloc(1, aux_info->groups * dsc_size);
+ if (!all_bg_desc) {
+ return ENOMEM;
}
- return r;
-}
-
-static int write_bgroups(struct ext4_blockdev *bd, struct fs_aux_info *aux_info,
- struct ext4_mkfs_info *info)
-{
- 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++) {
+ 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_desc = (void *)(aux_info->bg_desc_blk + k * dsc_size);
- 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++;
bg_free_blk);
ext4_bg_set_free_inodes_count(bg_desc,
- aux_info->sb, aux_info->sb->inodes_per_group);
+ aux_info->sb, to_le32(aux_info->sb->inodes_per_group));
ext4_bg_set_used_dirs_count(bg_desc, aux_info->sb, 0);
EXT4_BLOCK_GROUP_INODE_UNINIT);
sb_free_blk += bg_free_blk;
+ }
- 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;
+ /* Write the block group headers */
- if (++k != dsc_per_block)
- continue;
+ int r = EOK;
- k = 0;
- r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block);
- if (r != EOK)
- return r;
+ for (uint32_t i = 0; i < aux_info->groups; i++) {
+ if (progress) {
+ progress(progress_context, (float) i / aux_info->groups);
+ }
+ 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;
+
+ if (has_superblock(info, i)) {
+ bg_start_block++;
+ blk_off += info->bg_desc_reserve_blocks;
+ }
+
+ /* 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;
+
+ 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_fs_put_block_group_ref(&ref);
+ if (r != EOK) {
+ free(all_bg_desc);
+ break;
+ }
}
- r = write_bgroup_block(bd, aux_info, info, i / dsc_per_block);
- if (r != EOK)
- return r;
+ free(all_bg_desc);
ext4_sb_set_free_blocks_cnt(aux_info->sb, sb_free_blk);
return r;
if (r != EOK)
return r;
- sb = malloc(EXT4_SUPERBLOCK_SIZE);
+ sb = ext4_malloc(EXT4_SUPERBLOCK_SIZE);
if (!sb)
goto Finish;
Finish:
if (sb)
- free(sb);
+ ext4_free(sb);
ext4_block_fini(bd);
return r;
}
-static int mkfs_init(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;
goto Finish;
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;
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;
case EXT4_GOOD_OLD_FIRST_INO:
filetype = EXT4_DE_DIR;
break;
+ default:
+ break;
}
r = ext4_fs_alloc_inode(fs, &inode_ref, filetype);
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);
}
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;
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*/
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) {
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_init(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;