From b3eec79f5bb5ad13e51efaeafb5357cbe2cd88b7 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Fri, 17 Mar 2023 12:50:54 +0100 Subject: [PATCH] fs: ext2: Interpret s_errors field in superblocks Added funtion that takes specified action when file system corruption is detected. Possible actions are: do nothing, make mount point read-only, panic. Signed-off-by: Franciszek Zdobylak --- subsys/fs/ext2/ext2_diskops.c | 35 +++++++++++++++++--------- subsys/fs/ext2/ext2_impl.c | 46 +++++++++++++++++++++++++++++------ subsys/fs/ext2/ext2_impl.h | 2 ++ 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/subsys/fs/ext2/ext2_diskops.c b/subsys/fs/ext2/ext2_diskops.c index ba5cea56d42..b0b1dd98bc2 100644 --- a/subsys/fs/ext2/ext2_diskops.c +++ b/subsys/fs/ext2/ext2_diskops.c @@ -680,8 +680,10 @@ int64_t ext2_alloc_block(struct ext2_data *fs) struct ext2_disk_superblock *sb = EXT2_DATA_SBLOCK(fs); uint32_t set = ext2_bitmap_count_set(BGROUP_BLOCK_BITMAP(fs->bgroup), sb->s_blocks_count); - __ASSERT(set == sb->s_blocks_count - sb->s_free_blocks_count, - "Number of used inodes should be equal to bits set in bitmap"); + if (set != (sb->s_blocks_count - sb->s_free_blocks_count)) { + error_behavior(fs, "Wrong number of used blocks in superblock and bitmap"); + return -EINVAL; + } fs->sblock->flags |= EXT2_BLOCK_DIRTY; fs->bgroup->block->flags |= EXT2_BLOCK_DIRTY; @@ -726,12 +728,15 @@ int32_t ext2_alloc_inode(struct ext2_data *fs) } /* Add 1 because inodes are counted from 1 not 0. */ - int32_t total = group * EXT2_DATA_SBLOCK(fs)->s_inodes_per_group + r + 1; + int32_t global_idx = group * EXT2_DATA_SBLOCK(fs)->s_inodes_per_group + r + 1; /* Inode table entry for found inode must be cleared. */ - __ASSERT(check_zero_inode(fs, total) == 0, "Inode is not cleared in inode table!"); + if (check_zero_inode(fs, global_idx) != 0) { + error_behavior(fs, "Inode is not cleared in inode table!"); + return -EINVAL; + } - LOG_DBG("Found free inode %d in group %d (total: %d)", r, group, total); + LOG_DBG("Found free inode %d in group %d (global_idx: %d)", r, group, global_idx); rc = ext2_bitmap_set(BGROUP_INODE_BITMAP(fs->bgroup), r, fs->block_size); if (rc < 0) { @@ -744,8 +749,10 @@ int32_t ext2_alloc_inode(struct ext2_data *fs) struct ext2_disk_superblock *sb = EXT2_DATA_SBLOCK(fs); uint32_t set = ext2_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"); + if (set != sb->s_inodes_count - sb->s_free_inodes_count) { + error_behavior(fs, "Wrong number of used inodes in superblock and bitmap"); + return -EINVAL; + } fs->sblock->flags |= EXT2_BLOCK_DIRTY; fs->bgroup->block->flags |= EXT2_BLOCK_DIRTY; @@ -754,7 +761,7 @@ int32_t ext2_alloc_inode(struct ext2_data *fs) LOG_DBG("Free inodes (bg): %d", current_disk_bgroup(fs->bgroup)->bg_free_inodes_count); LOG_DBG("Free inodes (sb): %d", EXT2_DATA_SBLOCK(fs)->s_free_inodes_count); - return total; + return global_idx; } int ext2_free_block(struct ext2_data *fs, uint32_t block) @@ -789,8 +796,10 @@ int ext2_free_block(struct ext2_data *fs, uint32_t block) struct ext2_disk_superblock *sb = EXT2_DATA_SBLOCK(fs); uint32_t set = ext2_bitmap_count_set(BGROUP_BLOCK_BITMAP(fs->bgroup), sb->s_blocks_count); - __ASSERT(set == sb->s_blocks_count - sb->s_free_blocks_count, - "Number of used inodes should be equal to bits set in bitmap"); + if (set != sb->s_blocks_count - sb->s_free_blocks_count) { + error_behavior(fs, "Wrong number of used blocks in superblock and bitmap"); + return -EINVAL; + } fs->sblock->flags |= EXT2_BLOCK_DIRTY; fs->bgroup->block->flags |= EXT2_BLOCK_DIRTY; @@ -837,8 +846,10 @@ int ext2_free_inode(struct ext2_data *fs, uint32_t ino, bool directory) struct ext2_disk_superblock *sb = EXT2_DATA_SBLOCK(fs); uint32_t set = ext2_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"); + if (set != sb->s_inodes_count - sb->s_free_inodes_count) { + error_behavior(fs, "Wrong number of used inodes in superblock and bitmap"); + return -EINVAL; + } LOG_INF("Inode %d is free", ino); diff --git a/subsys/fs/ext2/ext2_impl.c b/subsys/fs/ext2/ext2_impl.c index b1af42637db..d676adc8930 100644 --- a/subsys/fs/ext2/ext2_impl.c +++ b/subsys/fs/ext2/ext2_impl.c @@ -34,6 +34,34 @@ K_HEAP_DEFINE(ext2_heap, CONFIG_EXT2_HEAP_SIZE); /* Helper functions --------------------------------------------------------- */ +void error_behavior(struct ext2_data *fs, const char *msg) +{ + LOG_ERR("File system corrupted: %s", msg); + + /* If file system is not initialized panic */ + if (!fs->sblock) { + LOG_ERR("File system data not found. Panic..."); + k_panic(); + } + + switch (EXT2_DATA_SBLOCK(fs)->s_errors) { + case EXT2_ERRORS_CONTINUE: + /* Do nothing */ + break; + case EXT2_ERRORS_RO: + LOG_WRN("Marking file system as read only"); + fs->flags |= EXT2_DATA_FLAGS_RO; + break; + case EXT2_ERRORS_PANIC: + LOG_ERR("Panic..."); + k_panic(); + break; + default: + LOG_ERR("Unrecognized errors behavior in superblock s_errors field. Panic..."); + k_panic(); + } +} + void *ext2_heap_alloc(size_t size) { return k_heap_alloc(&ext2_heap, size, K_NO_WAIT); @@ -252,10 +280,8 @@ int ext2_verify_superblock(struct ext2_disk_superblock *sb) return -EROFS; case EXT2_ERRORS_PANIC: - LOG_ERR("File system can't be mounted"); - /* panic or return that fs is invalid */ - __ASSERT(sb->s_state == EXT2_VALID_FS, "Error detected in superblock"); - return -EINVAL; + LOG_ERR("File system can't be mounted. Panic..."); + k_panic(); default: LOG_WRN("Unknown option for superblock s_errors field."); } @@ -326,13 +352,17 @@ int ext2_init_fs(struct ext2_data *fs) set = ext2_bitmap_count_set(BGROUP_BLOCK_BITMAP(fs->bgroup), fs_blocks); - __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"); + if (set != sb->s_blocks_count - sb->s_free_blocks_count - sb->s_first_data_block) { + error_behavior(fs, "Wrong number of used blocks in superblock and bitmap"); + return -EINVAL; + } set = ext2_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"); + if (set != sb->s_inodes_count - sb->s_free_inodes_count) { + error_behavior(fs, "Wrong number of used inodes in superblock and bitmap"); + return -EINVAL; + } return 0; out: ext2_drop_block(fs, fs->sblock); diff --git a/subsys/fs/ext2/ext2_impl.h b/subsys/fs/ext2/ext2_impl.h index 3a645c8aa46..6947fafb8ac 100644 --- a/subsys/fs/ext2/ext2_impl.h +++ b/subsys/fs/ext2/ext2_impl.h @@ -12,6 +12,8 @@ #include "ext2_struct.h" +void error_behavior(struct ext2_data *fs, const char *msg); + /* Memory allocation for ext2 implementation */ void *ext2_heap_alloc(size_t size); void ext2_heap_free(void *ptr);