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 <fzdobylak@antmicro.com>
This commit is contained in:
Franciszek Zdobylak 2023-03-17 12:50:54 +01:00 committed by Anas Nashif
parent 2e2a3cbd44
commit b3eec79f5b
3 changed files with 63 additions and 20 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);