fs: ext2: create correct file system in mkfs

Changes:
  - Add fs::sync function
  - Make correct file system in mkfs
  - Add few assertions to ensure that all assumptions are correct

Signed-off-by: Franciszek Zdobylak <fzdobylak@antmicro.com>
This commit is contained in:
Franciszek Zdobylak 2023-03-13 08:44:50 +01:00 committed by Anas Nashif
parent 10364b756f
commit b814246764
8 changed files with 367 additions and 149 deletions

View File

@ -44,6 +44,30 @@
#define EXT2_S_IFCHR 0x2000 /* character device */
#define EXT2_S_IFIFO 0x1000 /* fifo */
#define EXT2_S_IRUSR 0x100 /* owner may read */
#define EXT2_S_IWUSR 0x080 /* owner may write */
#define EXT2_S_IXUSR 0x040 /* owner may execute */
#define EXT2_S_IRGRP 0x020 /* group members may read */
#define EXT2_S_IWGRP 0x010 /* group members may write */
#define EXT2_S_IXGRP 0x008 /* group members may execute */
#define EXT2_S_IROTH 0x004 /* others may read */
#define EXT2_S_IWOTH 0x002 /* others may write */
#define EXT2_S_IXOTH 0x001 /* others may execute */
/* Default file mode: rw-r--r-- */
#define EXT2_DEF_FILE_MODE \
(EXT2_S_IFREG | \
EXT2_S_IRUSR | EXT2_S_IWUSR | \
EXT2_S_IRGRP | \
EXT2_S_IROTH)
/* Default dir mode: rwxr-xr-x */
#define EXT2_DEF_DIR_MODE \
(EXT2_S_IFDIR | \
EXT2_S_IRUSR | EXT2_S_IWUSR | EXT2_S_IXUSR | \
EXT2_S_IRGRP | EXT2_S_IXGRP | \
EXT2_S_IROTH | EXT2_S_IXOTH)
#define IS_REG_FILE(mode) (((mode) & EXT2_S_IFMT) == EXT2_S_IFREG)
#define IS_DIR(mode) (((mode) & EXT2_S_IFMT) == EXT2_S_IFDIR)

View File

@ -27,6 +27,8 @@ int ext2_bitmap_set(uint8_t *bm, uint32_t index, uint32_t size)
return -EINVAL;
}
__ASSERT((bm[idx] & BIT(off)) == 0, "Bit %d set in bitmap", index);
LOG_DBG("Bitmap %d: %x", idx, bm[idx]);
bm[idx] |= BIT(off);
LOG_DBG("Bitmap %d: %x", idx, bm[idx]);
@ -46,6 +48,8 @@ int ext2_bitmap_unset(uint8_t *bm, uint32_t index, uint32_t size)
return -EINVAL;
}
__ASSERT(bm[idx] & BIT(off), "Bit %d not set in bitmap", index);
LOG_DBG("Bitmap %d: %x", idx, bm[idx]);
bm[idx] &= ~BIT(off);
LOG_DBG("Bitmap %d: %x", idx, bm[idx]);
@ -67,3 +71,18 @@ int32_t ext2_bitmap_find_free(uint8_t *bm, uint32_t size)
}
return -ENOSPC;
}
uint32_t bitmap_count_set(uint8_t *bm, uint32_t size)
{
int32_t count = 0;
for (uint32_t i = 0; i < size; i += 8) {
uint8_t val = bm[i / 8];
for (int b = 0; b < 8 && i + b < size; ++b) {
count += (val >> b) & BIT(0);
}
}
return count;
}

View File

@ -51,4 +51,14 @@ int ext2_bitmap_unset(uint8_t *bm, uint32_t index, uint32_t size);
*/
int32_t ext2_bitmap_find_free(uint8_t *bm, uint32_t size);
/**
* @brief Helper function to count bits set in bitmap
*
* @param bm Pointer to bitmap
* @param size Size of bitmap in bits
*
* @retval Number of set bits in bitmap;
*/
uint32_t bitmap_count_set(uint8_t *bm, uint32_t size);
#endif /* __EXT2_BITMAP_H__ */

View File

@ -605,19 +605,20 @@ int64_t ext2_alloc_block(struct ext2_data *fs)
return rc;
}
int r = ext2_bitmap_find_free(BGROUP_BLOCK_BITMAP(fs->bgroup), fs->block_size);
int bitmap_slot = ext2_bitmap_find_free(BGROUP_BLOCK_BITMAP(fs->bgroup), fs->block_size);
if (r < 0) {
LOG_WRN("Cannot find free block in group %d (rc: %d)", group, r);
return r;
if (bitmap_slot < 0) {
LOG_WRN("Cannot find free block in group %d (rc: %d)", group, bitmap_slot);
return bitmap_slot;
}
/* Add 1 because bitmaps describe blocks except the first one */
int32_t total = group * EXT2_DATA_SBLOCK(fs)->s_blocks_per_group + r + 1;
/* In bitmap blocks are counted from s_first_data_block hence we have to add this offset. */
int32_t total = group * EXT2_DATA_SBLOCK(fs)->s_blocks_per_group
+ bitmap_slot + EXT2_DATA_SBLOCK(fs)->s_first_data_block;
LOG_DBG("Found free block %d in group %d (total: %d)", r, group, total);
LOG_DBG("Found free block %d in group %d (total: %d)", bitmap_slot, group, total);
rc = ext2_bitmap_set(BGROUP_BLOCK_BITMAP(fs->bgroup), r, fs->block_size);
rc = ext2_bitmap_set(BGROUP_BLOCK_BITMAP(fs->bgroup), bitmap_slot, fs->block_size);
if (rc < 0) {
return rc;
}
@ -667,7 +668,7 @@ int32_t ext2_alloc_inode(struct ext2_data *fs)
return r;
}
/* Add 1 because bitmaps describe blocks except the first one */
/* Add 1 because inodes are counted from 1 not 0. */
int32_t total = group * EXT2_DATA_SBLOCK(fs)->s_inodes_per_group + r + 1;
LOG_DBG("Found free inode %d in group %d (total: %d)", r, group, total);

View File

@ -12,7 +12,7 @@
#include "ext2_impl.h"
#include "ext2_struct.h"
LOG_MODULE_DECLARE(ext2);
LOG_MODULE_DECLARE(ext2, LOG_LEVEL_DBG);
FS_EXT2_DECLARE_DEFAULT_CONFIG(ext2_default);
@ -40,6 +40,57 @@ static void validate_config(struct ext2_cfg *cfg)
}
}
static void set_bitmap_padding(uint8_t *bitmap, uint32_t nelems, struct ext2_cfg *cfg)
{
uint32_t used_bytes = nelems / 8 + (nelems % 8 != 0);
LOG_DBG("Set bitmap padding: %d bytes", nelems);
memset(bitmap, 0x00, used_bytes);
/* Set padding in block-bitmap block */
if (nelems % 8) {
bitmap[used_bytes - 1] = (0xff << (nelems % 8)) & 0xff;
LOG_DBG("last byte: %02x", (0xff << (nelems % 8)) & 0xff);
}
memset(bitmap + used_bytes, 0xff, cfg->block_size - used_bytes);
}
static void set_bitmap_bits(uint8_t *bitmap, uint32_t to_set)
{
int i = 0, bits;
uint16_t set_value;
while (to_set > 0) {
bits = MIN(8, to_set);
set_value = (1 << bits) - 1;
bitmap[i] = (uint8_t)set_value;
to_set -= bits;
i++;
}
}
static void default_directory_inode(struct ext2_disk_inode *in, uint32_t nblocks,
struct ext2_cfg *cfg)
{
LOG_DBG("Set directory inode: %p", in);
in->i_mode = EXT2_S_IFDIR;
in->i_uid = 0;
in->i_size = nblocks * cfg->block_size;
in->i_atime = 0;
in->i_ctime = 0;
in->i_mtime = 0;
in->i_dtime = 0;
in->i_gid = 0;
in->i_blocks = nblocks * cfg->block_size / 512;
in->i_flags = 0;
in->i_osd1 = 0;
in->i_generation = 0;
in->i_file_acl = 0;
in->i_dir_acl = 0;
in->i_faddr = 0;
memset(in->i_block, 0, EXT2_INODE_BLOCKS * sizeof(uint32_t));
}
int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
{
int ret = 0;
@ -64,92 +115,89 @@ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
return -ENOSPC;
}
uint32_t blocks_count = fs_memory / cfg->block_size;
uint32_t blocks_per_group = cfg->block_size * 8;
uint32_t inodes_per_block = cfg->block_size / sizeof(struct ext2_disk_inode);
uint32_t mem_per_inode = cfg->bytes_per_inode + sizeof(struct ext2_disk_inode);
/* Require at least 24 blocks to have at least 1 block per inode */
/* 24 block should be enough to fit minimal file system. */
if (blocks_count < 24) {
LOG_ERR("Storage device too small to fit ext2 file system");
return -ENOSPC;
}
/* We want to have only 1 block group (and one extra block) */
if (blocks_count > blocks_per_group + 1) {
uint32_t sb_offset;
uint32_t first_data_block;
uint32_t occupied_blocks;
if (cfg->block_size == 1024) {
/* Superblock is stored in 1st block */
sb_offset = 0;
first_data_block = 1;
occupied_blocks = 2;
} else {
/* Superblock is stored in 0th block */
sb_offset = 1024;
first_data_block = 0;
occupied_blocks = 1;
}
/* Reserve blocks for block group and bitmaps. */
uint32_t bg_block_num = occupied_blocks++;
uint32_t bbitmap_block_num = occupied_blocks++;
uint32_t ibitmap_block_num = occupied_blocks++;
/* We want to have only 1 block group (that starts with first data block) */
if (blocks_count > blocks_per_group + first_data_block) {
LOG_ERR("File systems with more than 1 block group are not supported.");
return -ENOTSUP;
}
/* Superblock, group descriptor table, 2 x bitmap. */
uint32_t reserved_blocks = 4;
uint32_t mem_for_inodes = fs_memory - reserved_blocks * cfg->block_size;
uint32_t mem_per_inode = cfg->bytes_per_inode + sizeof(struct ext2_disk_inode);
uint32_t inodes_per_block = cfg->block_size / sizeof(struct ext2_disk_inode);
uint32_t mem_for_inodes = fs_memory - occupied_blocks * cfg->block_size;
uint32_t inodes_count = mem_for_inodes / mem_per_inode;
/* Align indes_count to use last block of inode table entirely. */
if (inodes_count % inodes_per_block) {
/* Increase inodes_count to use entire blocks that are reserved for inode table. */
inodes_count += inodes_per_block - (inodes_count % inodes_per_block);
}
uint32_t itable_blocks = inodes_count / inodes_per_block;
uint32_t reserved_inodes = 10;
uint32_t used_inodes = EXT2_RESERVED_INODES;
uint32_t lost_found_inode = 1 + used_inodes++; /* We count inodes from 1. */
/* Used blocks:
* Reserved blocks:
* 0 - boot sector
* 1 - superblock
* 2 - block group descriptor table
* 3 - block bitmap
* 4 - inode bitmap
*
* Inode table blocks:
* 5-x - inode table (x = 5 + inode_count / inodes per block )
*
* Other used blocks:
* x+1 - root dir
*/
uint32_t used_blocks = reserved_blocks + itable_blocks + 1;
uint32_t free_blocks = blocks_count - used_blocks - 1; /* boot sector block also counts */
/* First unoccupied block will be the start of inode table. */
uint32_t itable_block_num = occupied_blocks;
LOG_INF("[Blocks] total:%d per_grp:%d reserved:%d",
blocks_count, blocks_per_group, used_blocks);
LOG_INF("[Inodes] total:%d reserved:%d itable_blocks:%d",
inodes_count, reserved_inodes, itable_blocks);
occupied_blocks += itable_blocks;
uint32_t sb_offset;
uint32_t sb_block_num, bg_block_num, bbitmap_block_num, ibitmap_block_num, in1_block_num,
root_dir_blk_num;
/* Two next block after inode table will be the blocks for '/' and 'lost+found' dirs */
uint32_t root_dir_blk_num = occupied_blocks++;
uint32_t lost_found_dir_blk_num = occupied_blocks++;
if (cfg->block_size == 1024) {
sb_offset = 0;
sb_block_num = 1;
bg_block_num = 2;
bbitmap_block_num = 3;
ibitmap_block_num = 4;
in1_block_num = 5;
root_dir_blk_num = used_blocks; /* last used block */
} else {
sb_offset = 1024;
sb_block_num = 0;
bg_block_num = 1;
bbitmap_block_num = 2;
ibitmap_block_num = 3;
in1_block_num = 4;
root_dir_blk_num = used_blocks; /* last used block */
}
LOG_INF("root: %d l+f: %d", root_dir_blk_num, lost_found_dir_blk_num);
struct ext2_block *sb_block = ext2_get_block(fs, sb_block_num);
/* All blocks available for writes after creating file system. */
uint32_t free_blocks = blocks_count - occupied_blocks;
/* Blocks that will be described in bitmaps. */
uint32_t used_blocks = occupied_blocks - first_data_block;
LOG_INF("[Blocks] total:%d per_grp:%d occupied:%d used:%d",
blocks_count, blocks_per_group, occupied_blocks, used_blocks);
LOG_INF("[Inodes] total:%d used:%d itable_blocks:%d",
inodes_count, used_inodes, itable_blocks);
struct ext2_block *sb_block = ext2_get_block(fs, first_data_block);
struct ext2_block *bg_block = ext2_get_block(fs, bg_block_num);
struct ext2_block *bbitmap_block = ext2_get_block(fs, bbitmap_block_num);
struct ext2_block *ibitmap_block = ext2_get_block(fs, ibitmap_block_num);
struct ext2_block *in1_block = ext2_get_block(fs, in1_block_num);
struct ext2_block *root_dir_blk_block = ext2_get_block(fs, root_dir_blk_num);
struct ext2_block *itable_block1, *itable_block2, *root_dir_blk, *lost_found_dir_blk;
if (root_dir_blk_block == NULL || in1_block == NULL || ibitmap_block == NULL ||
bbitmap_block == NULL || bg_block == NULL || sb_block == NULL) {
itable_block1 = itable_block2 = root_dir_blk = lost_found_dir_blk = NULL;
if (ibitmap_block == NULL || bbitmap_block == NULL ||
bg_block == NULL || sb_block == NULL) {
ret = -ENOMEM;
goto out;
}
@ -162,8 +210,8 @@ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
sb->s_blocks_count = blocks_count;
sb->s_r_blocks_count = 0;
sb->s_free_blocks_count = free_blocks;
sb->s_free_inodes_count = inodes_count - reserved_inodes;
sb->s_first_data_block = sb_block_num;
sb->s_free_inodes_count = inodes_count - used_inodes;
sb->s_first_data_block = first_data_block;
sb->s_log_block_size = block_log_size;
sb->s_log_frag_size = block_log_size;
sb->s_blocks_per_group = cfg->block_size * 8;
@ -189,10 +237,6 @@ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
sb->s_feature_compat = 0;
sb->s_feature_incompat = EXT2_FEATURE_INCOMPAT_FILETYPE;
sb->s_feature_ro_compat = 0;
memcpy(sb->s_uuid, cfg->uuid, 16);
memcpy(sb->s_volume_name, cfg->uuid, 16);
sb->s_algo_bitmap = 0;
sb->s_prealloc_blocks = 0;
sb->s_prealloc_dir_blocks = 0;
@ -200,6 +244,11 @@ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
sb->s_journal_dev = 0;
sb->s_last_orphan = 0;
memcpy(sb->s_uuid, cfg->uuid, 16);
strcpy(sb->s_volume_name, cfg->volume_name);
sb_block->flags |= EXT2_BLOCK_DIRTY;
/* Block descriptor table */
struct ext2_disk_bgroup *bg = (struct ext2_disk_bgroup *)bg_block->data;
@ -207,88 +256,141 @@ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg)
memset(bg, 0, cfg->block_size);
bg->bg_block_bitmap = bbitmap_block_num;
bg->bg_inode_bitmap = ibitmap_block_num;
bg->bg_inode_table = in1_block_num;
bg->bg_inode_table = itable_block_num;
bg->bg_free_blocks_count = free_blocks;
bg->bg_free_inodes_count = inodes_count - reserved_inodes;
bg->bg_used_dirs_count = 1;
bg->bg_free_inodes_count = inodes_count - used_inodes;
bg->bg_used_dirs_count = 2; /* '/' and 'lost+found' */
/* Inode table */
struct ext2_disk_inode *in1 = (struct ext2_disk_inode *)in1_block->data;
memset(in1, 0, cfg->block_size);
in1[1].i_mode = 0x4000 | 0755;
in1[1].i_uid = 0;
in1[1].i_size = cfg->block_size;
in1[1].i_atime = 0;
in1[1].i_ctime = 0;
in1[1].i_mtime = 0;
in1[1].i_dtime = 0;
in1[1].i_gid = 0;
in1[1].i_links_count = 2;
in1[1].i_blocks = cfg->block_size / 512;
in1[1].i_flags = 0;
in1[1].i_osd1 = 0;
in1[1].i_generation = 0;
in1[1].i_file_acl = 0;
in1[1].i_dir_acl = 0;
in1[1].i_faddr = 0;
in1[1].i_block[0] = root_dir_blk_num;
bg_block->flags |= EXT2_BLOCK_DIRTY;
/* Block bitmap */
uint8_t *bbitmap = bbitmap_block->data;
memset(bbitmap, 0, cfg->block_size);
int i = 0, blocks = used_blocks;
int bits;
uint16_t to_set;
while (blocks > 0) {
bits = MIN(8, blocks);
to_set = (1 << bits) - 1;
bbitmap[i] = (uint8_t)to_set;
blocks -= 8;
i++;
}
/* In bitmap we describe blocks starting from s_first_data_block. */
set_bitmap_padding(bbitmap, blocks_count - sb->s_first_data_block, cfg);
set_bitmap_bits(bbitmap, used_blocks);
bbitmap_block->flags |= EXT2_BLOCK_DIRTY;
/* Inode bitmap */
uint8_t *ibitmap = ibitmap_block->data;
memset(ibitmap, 0, cfg->block_size);
ibitmap[0] = 0xff;
ibitmap[1] = 0x03;
memset(root_dir_blk_block->data, 0, cfg->block_size);
struct ext2_disk_dentry *de = (struct ext2_disk_dentry *)root_dir_blk_block->data;
de->de_inode = 2;
de->de_rec_len = sizeof(struct ext2_disk_dentry) + 4;
de->de_name_len = 1;
de->de_file_type = EXT2_FT_DIR;
memset(de->de_name, '.', 1);
de = (struct ext2_disk_dentry *)(((uint8_t *)de) + de->de_rec_len);
de->de_inode = 2;
de->de_rec_len = cfg->block_size - 12;
de->de_name_len = 2;
de->de_file_type = EXT2_FT_DIR;
memset(de->de_name, '.', 2);
sb_block->flags |= EXT2_BLOCK_DIRTY;
bg_block->flags |= EXT2_BLOCK_DIRTY;
in1_block->flags |= EXT2_BLOCK_DIRTY;
bbitmap_block->flags |= EXT2_BLOCK_DIRTY;
set_bitmap_padding(ibitmap, inodes_count, cfg);
set_bitmap_bits(ibitmap, used_inodes);
ibitmap_block->flags |= EXT2_BLOCK_DIRTY;
root_dir_blk_block->flags |= EXT2_BLOCK_DIRTY;
/* Inode table */
/* Zero inode table */
for (int i = 0; i < itable_blocks; i++) {
struct ext2_block *blk = ext2_get_block(fs, itable_block_num + i);
memset(blk->data, 0, cfg->block_size);
blk->flags |= EXT2_BLOCK_DIRTY;
ext2_drop_block(fs, blk);
}
struct ext2_disk_inode *in;
int inode_offset;
/* Set inode 2 ('/' directory) */
itable_block1 = ext2_get_block(fs, itable_block_num);
in = (struct ext2_disk_inode *)itable_block1->data;
inode_offset = EXT2_ROOT_INODE - 1;
default_directory_inode(&in[inode_offset], 1, cfg);
in[inode_offset].i_mode = EXT2_DEF_DIR_MODE;
in[inode_offset].i_links_count = 3; /* 2 from itself and 1 from child directory */
in[inode_offset].i_block[0] = root_dir_blk_num;
itable_block1->flags |= EXT2_BLOCK_DIRTY;
/* Set inode for 'lost+found' directory */
inode_offset = (lost_found_inode - 1) % inodes_per_block; /* We count inodes from 1 */
LOG_DBG("Inode offset: %d", inode_offset);
if (inodes_per_block < lost_found_inode) {
/* We need to fetch new inode table block */
uint32_t block_num = itable_block_num + lost_found_inode / inodes_per_block;
itable_block2 = ext2_get_block(fs, block_num);
in = (struct ext2_disk_inode *)itable_block2->data;
}
default_directory_inode(&in[inode_offset], 1, cfg);
in[inode_offset].i_mode = EXT2_DEF_DIR_MODE;
in[inode_offset].i_links_count = 2; /* 1 from itself and 1 from parent directory */
in[inode_offset].i_block[0] = lost_found_dir_blk_num;
if (itable_block2) {
itable_block2->flags |= EXT2_BLOCK_DIRTY;
}
struct ext2_disk_dentry *de;
uint32_t current_size;
/* Contents of '/' directory */
LOG_DBG("Root dir blk: %d", root_dir_blk_num);
root_dir_blk = ext2_get_block(fs, root_dir_blk_num);
if (root_dir_blk == NULL) {
ret = ENOMEM;
goto out;
}
memset(root_dir_blk->data, 0, cfg->block_size);
current_size = 0;
de = (struct ext2_disk_dentry *)root_dir_blk->data;
ext2_fill_direntry(de, ".", 1, EXT2_ROOT_INODE, EXT2_FT_DIR);
current_size += de->de_rec_len;
de = EXT2_NEXT_DISK_DIRENTRY(de);
ext2_fill_direntry(de, "..", 2, EXT2_ROOT_INODE, EXT2_FT_DIR);
current_size += de->de_rec_len;
de = EXT2_NEXT_DISK_DIRENTRY(de);
ext2_fill_direntry(de, "lost+found", strlen("lost+found"), lost_found_inode, EXT2_FT_DIR);
current_size += de->de_rec_len;
/* This was the last entry so add padding until end of block */
de->de_rec_len += cfg->block_size - current_size;
root_dir_blk->flags |= EXT2_BLOCK_DIRTY;
/* Contents of 'lost+found' directory */
LOG_DBG("Lost found dir blk: %d", lost_found_dir_blk_num);
lost_found_dir_blk = ext2_get_block(fs, lost_found_dir_blk_num);
if (lost_found_dir_blk == NULL) {
ret = ENOMEM;
goto out;
}
memset(lost_found_dir_blk->data, 0, cfg->block_size);
current_size = 0;
de = (struct ext2_disk_dentry *)lost_found_dir_blk->data;
ext2_fill_direntry(de, ".", 1, lost_found_inode, EXT2_FT_DIR);
current_size += de->de_rec_len;
de = EXT2_NEXT_DISK_DIRENTRY(de);
ext2_fill_direntry(de, "..", 2, EXT2_ROOT_INODE, EXT2_FT_DIR);
current_size += de->de_rec_len;
/* This was the last entry so add padding until end of block */
de->de_rec_len += cfg->block_size - current_size;
LOG_DBG("Initialized directory entry %p{%s(%d) %d %d %c}",
de, de->de_name, de->de_name_len, de->de_inode, de->de_rec_len,
de->de_file_type == EXT2_FT_DIR ? 'd' : 'f');
lost_found_dir_blk->flags |= EXT2_BLOCK_DIRTY;
out:
ext2_drop_block(fs, sb_block);
ext2_drop_block(fs, bg_block);
ext2_drop_block(fs, in1_block);
ext2_drop_block(fs, bbitmap_block);
ext2_drop_block(fs, ibitmap_block);
ext2_drop_block(fs, root_dir_blk_block);
ext2_drop_block(fs, itable_block1);
ext2_drop_block(fs, itable_block2);
ext2_drop_block(fs, root_dir_blk);
ext2_drop_block(fs, lost_found_dir_blk);
fs->backend_ops->sync(fs);
return ret;
}

View File

@ -14,6 +14,7 @@
#include "ext2_impl.h"
#include "ext2_struct.h"
#include "ext2_diskops.h"
#include "ext2_bitmap.h"
LOG_MODULE_REGISTER(ext2, CONFIG_EXT2_LOG_LEVEL);
@ -309,6 +310,30 @@ int ext2_init_fs(struct ext2_data *fs)
EXT2_DATA_SBLOCK(fs)->s_mnt_count += 1;
fs->sblock->flags |= EXT2_BLOCK_DIRTY;
}
ret = ext2_fetch_block_group(fs, 0);
if (ret < 0) {
goto out;
}
ret = ext2_fetch_bg_ibitmap(fs->bgroup);
ret = ext2_fetch_bg_bbitmap(fs->bgroup);
/* Validate superblock */
uint32_t set;
struct ext2_disk_superblock *sb = EXT2_DATA_SBLOCK(fs);
uint32_t fs_blocks = sb->s_blocks_count - sb->s_first_data_block;
set = bitmap_count_set(BGROUP_BLOCK_BITMAP(fs->bgroup), fs_blocks);
LOG_INF("Set: %ld Should: %ld", set, fs_blocks - sb->s_free_blocks_count);
__ASSERT(set == sb->s_blocks_count - sb->s_free_blocks_count - sb->s_first_data_block,
"Number of used blocks should be equal to bits set in bitmap");
set = bitmap_count_set(BGROUP_INODE_BITMAP(fs->bgroup), sb->s_inodes_count);
__ASSERT(set == sb->s_inodes_count - sb->s_free_inodes_count,
"Number of used inodes should be equal to bits set in bitmap");
return 0;
out:
ext2_drop_block(fs, fs->sblock);
@ -340,6 +365,7 @@ int ext2_close_fs(struct ext2_data *fs)
ext2_drop_block(fs, fs->bgroup->block);
}
ext2_drop_block(fs, fs->sblock);
ret = fs->backend_ops->sync(fs);
fs->sblock = NULL;
return ret;
}
@ -856,6 +882,27 @@ static int ext2_create_inode(struct ext2_data *fs, struct ext2_inode *parent,
return rc;
}
void ext2_fill_direntry(struct ext2_disk_dentry *de, const char *name, uint8_t namelen,
uint32_t ino, uint8_t filetype)
{
uint32_t reclen = sizeof(struct ext2_disk_dentry) + namelen;
/* Align reclen to 4 bytes. */
reclen = ROUND_UP(reclen, 4);
__ASSERT(namelen <= EXT2_MAX_FILE_NAME, "Name length to long");
de->de_inode = ino;
de->de_rec_len = reclen;
de->de_name_len = (uint8_t)namelen;
de->de_file_type = filetype;
memcpy(de->de_name, name, namelen);
LOG_DBG("Initialized directory entry %p{%s(%d) %d %d %c}",
de, de->de_name, de->de_name_len, de->de_inode, de->de_rec_len,
de->de_file_type == EXT2_FT_DIR ? 'd' : 'f');
}
static int ext2_add_direntry(struct ext2_inode *dir, struct ext2_disk_dentry *entry)
{
LOG_DBG("Adding entry: {in=%d type=%d name_len=%d} to directory (in=%d)",
@ -958,10 +1005,8 @@ int ext2_create_file(struct ext2_inode *parent, struct ext2_inode *new_inode,
goto out;
}
entry->de_inode = new_inode->i_id;
entry->de_name_len = args->name_len;
entry->de_file_type = EXT2_FT_REG_FILE;
memcpy(entry->de_name, args->path + args->name_pos, entry->de_name_len);
ext2_fill_direntry(entry, args->path + args->name_pos, args->name_len, new_inode->i_id,
EXT2_FT_REG_FILE);
rc = ext2_add_direntry(parent, entry);
if (rc < 0) {
@ -1004,10 +1049,8 @@ int ext2_create_dir(struct ext2_inode *parent, struct ext2_inode *new_inode,
goto out;
}
entry->de_inode = new_inode->i_id;
entry->de_name_len = args->name_len;
entry->de_file_type = EXT2_FT_DIR;
memcpy(entry->de_name, args->path + args->name_pos, entry->de_name_len);
ext2_fill_direntry(entry, args->path + args->name_pos, args->name_len, new_inode->i_id,
EXT2_FT_DIR);
rc = ext2_add_direntry(parent, entry);
if (rc < 0) {

View File

@ -229,6 +229,23 @@ int ext2_inode_sync(struct ext2_inode *inode);
*/
int ext2_get_direntry(struct ext2_dir *dir, struct fs_dirent *ent);
/**
* @brief Fill in the directory structure with given attributes
*
* Fills in all the fields of directory entry. Automatically calculates de_rec_len field.
*
* NOTE: if you need to adjust the size (e.g. when this entry is last in the block)
* then just update the size after this function returns.
*
* @param de Structure to fill in
* @param name Name of direntry
* @param namelen Length of name
* @param ino Inode associated with that entry
* @param filetype File type of that entry
*/
void ext2_fill_direntry(struct ext2_disk_dentry *de, const char *name, uint8_t len, uint32_t ino,
uint8_t filetype);
/**
* @brief Create a file
*

View File

@ -101,6 +101,8 @@ struct ext2_disk_dentry {
/* Program structures ------------------------------------------------------- */
#define EXT2_BLOCK_NUM_SIZE (sizeof(uint32_t))
#define EXT2_NEXT_DISK_DIRENTRY(de) \
((struct ext2_disk_dentry *)(((uint8_t *)(de)) + (de)->de_rec_len))
#define EXT2_BLOCK_ASSIGNED BIT(0)
#define EXT2_BLOCK_DIRTY BIT(1)