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:
parent
10364b756f
commit
b814246764
@ -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)
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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__ */
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user