Skip to content

Commit

Permalink
fs: ext2: Interpret s_errors field in superblocks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
fzdobylak committed Mar 20, 2023
1 parent 0e425e4 commit 6344aee
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 20 deletions.
35 changes: 23 additions & 12 deletions subsys/fs/ext2/ext2_diskops.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,10 @@ int64_t alloc_block(struct ext2_data *fs)
struct disk_superblock *sb = EXT2_DATA_SBLOCK(fs);
uint32_t set = 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_beharior(fs, "Wrong number of used blocks in superblock and bitmap");
return -EINVAL;
}

fs->sblock->flags |= BLOCK_DIRTY;
fs->bgroup->block->flags |= BLOCK_DIRTY;
Expand Down Expand Up @@ -719,12 +721,15 @@ int32_t 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_beharior(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 = bitmap_set(BGROUP_INODE_BITMAP(fs->bgroup), r, fs->block_size);
if (rc < 0) {
Expand All @@ -737,8 +742,10 @@ int32_t alloc_inode(struct ext2_data *fs)
struct disk_superblock *sb = EXT2_DATA_SBLOCK(fs);
uint32_t 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");
if (set != sb->s_inodes_count - sb->s_free_inodes_count) {
error_beharior(fs, "Wrong number of used inodes in superblock and bitmap");
return -EINVAL;
}

fs->sblock->flags |= BLOCK_DIRTY;
fs->bgroup->block->flags |= BLOCK_DIRTY;
Expand All @@ -747,7 +754,7 @@ int32_t 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 free_block(struct ext2_data *fs, uint32_t block)
Expand Down Expand Up @@ -782,8 +789,10 @@ int free_block(struct ext2_data *fs, uint32_t block)
struct disk_superblock *sb = EXT2_DATA_SBLOCK(fs);
uint32_t set = 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_beharior(fs, "Wrong number of used blocks in superblock and bitmap");
return -EINVAL;
}

fs->sblock->flags |= BLOCK_DIRTY;
fs->bgroup->block->flags |= BLOCK_DIRTY;
Expand Down Expand Up @@ -830,8 +839,10 @@ int free_inode(struct ext2_data *fs, uint32_t ino, bool directory)
struct disk_superblock *sb = EXT2_DATA_SBLOCK(fs);
uint32_t 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");
if (set != sb->s_inodes_count - sb->s_free_inodes_count) {
error_beharior(fs, "Wrong number of used inodes in superblock and bitmap");
return -EINVAL;
}

LOG_INF("Inode %d is free", ino);

Expand Down
46 changes: 38 additions & 8 deletions subsys/fs/ext2/ext2_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ K_HEAP_DEFINE(ext2_heap, CONFIG_EXT2_HEAP_SIZE);

/* Helper functions --------------------------------------------------------- */

void error_beharior(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)
{
void *ptr = k_heap_alloc(&ext2_heap, size, K_NO_WAIT);
Expand Down Expand Up @@ -265,10 +293,8 @@ int ext2_verify_superblock(struct 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.");
}
Expand Down Expand Up @@ -340,13 +366,17 @@ int ext2_init_fs(struct ext2_data *fs)

set = 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_beharior(fs, "Wrong number of used blocks in superblock and bitmap");
return -EINVAL;
}

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");
if (set != sb->s_inodes_count - sb->s_free_inodes_count) {
error_beharior(fs, "Wrong number of used inodes in superblock and bitmap");
return -EINVAL;
}
return 0;
out:
drop_block(fs, fs->sblock);
Expand Down
2 changes: 2 additions & 0 deletions subsys/fs/ext2/ext2_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "ext2_struct.h"

void error_beharior(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);
Expand Down

0 comments on commit 6344aee

Please sign in to comment.