Skip to content

Commit

Permalink
ext4: Re-organize files
Browse files Browse the repository at this point in the history
Moves everything into its own file, and gets rid of the horrible
ext4_ll. ext4.cpp now takes care of basic implementations of the VFS
ops.

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
  • Loading branch information
heatd committed Dec 28, 2022
1 parent 4717857 commit a6fa615
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 321 deletions.
12 changes: 6 additions & 6 deletions kernel/kernel/fs/ext4/block_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ unsigned int ext4_bmap_get_block_path(ext4_superblock *sb, ext4_block_no offsets
{
unsigned int type = ext4_detect_block_type(block_nr, sb);
const unsigned int entries = (sb->block_size / sizeof(uint32_t));
unsigned int min_singly_block = direct_block_count;
unsigned int min_doubly_block = entries + direct_block_count;
unsigned int min_trebly_block = entries * entries + entries + direct_block_count;
unsigned int min_singly_block = EXT4_DIRECT_BLOCK_COUNT;
unsigned int min_doubly_block = entries + EXT4_DIRECT_BLOCK_COUNT;
unsigned int min_trebly_block = entries * entries + entries + EXT4_DIRECT_BLOCK_COUNT;
unsigned int idx = 0;

if (type == EXT4_TYPE_DIRECT_BLOCK)
Expand Down Expand Up @@ -225,9 +225,9 @@ struct ext4_block_coords
return coords[0] << sb->block_size_shift;

const unsigned int entries = (sb->block_size / sizeof(uint32_t));
unsigned int min_singly_block = direct_block_count;
unsigned int min_doubly_block = entries + direct_block_count;
unsigned int min_trebly_block = entries * entries + entries + direct_block_count;
unsigned int min_singly_block = EXT4_DIRECT_BLOCK_COUNT;
unsigned int min_doubly_block = entries + EXT4_DIRECT_BLOCK_COUNT;
unsigned int min_trebly_block = entries * entries + entries + EXT4_DIRECT_BLOCK_COUNT;

if (size == 2)
{
Expand Down
133 changes: 0 additions & 133 deletions kernel/kernel/fs/ext4/ext4_ll.cpp → kernel/kernel/fs/ext4/dir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,118 +23,6 @@

#include "ext4.h"

const unsigned int direct_block_count = 12;

/**
* @brief Reads metadata blocks from the filesystem using sb_read_block
*
* @param block Starting block
* @param number_of_blocks Number of blocks
* @param bufs Pointer to an array of N auto_block_buf's
* @return 0 on success, negative error codes
*/
int ext4_superblock::read_blocks(ext4_block_no block, ext4_block_no number_of_blocks,
auto_block_buf *bufs)
{
for (ext4_block_no i = 0; i < number_of_blocks; i++)
{
bufs[i] = sb_read_block(this, block + i);
if (!bufs[i])
{
for (ext4_block_no j = 0; j < i; j++)
{
bufs[j].reset(nullptr);
return -errno;
}
}
}

return 0;
}

/**
* @brief Read an ext4_inode from disk
*
* @param nr The inode number
* @param check_csum If the function should check the checksum
* @return A pointer to the inode number
*/
ext4_inode *ext4_superblock::get_inode(ext4_inode_no inode, bool check_csum) const
{
uint32_t bg_no = ext4_inode_number_to_bg(inode, this);
uint32_t index = (inode - 1) % inodes_per_block_group;
uint32_t inodes_per_block = block_size / inode_size;
uint32_t block = index / inodes_per_block;
uint32_t off = (index % inodes_per_block) * inode_size;

assert(bg_no < number_of_block_groups);

const auto &bg = block_groups[bg_no];

auto buf = bg.get_inode_table(this, block);
if (!buf)
{
error("Error reading inode table.");
printk("Tried to read block %u\n", bg.get_bgd()->bg_inode_table_lo);
return nullptr;
}

ext4_inode *ino = (ext4_inode *) malloc(inode_size);

if (!ino)
return nullptr;

ext4_inode *on_disk = (ext4_inode *) ((char *) block_buf_data(buf) + off);

if (check_csum && !ext4_check_inode_csum(this, on_disk, inode))
{
free(ino);
error("Inode %u has a bad checksum", inode);
errno = EIO;
return nullptr;
}

memcpy(ino, on_disk, inode_size);

return ino;
}

/**
* @brief Updates an inode on disk
*
* @param ino Pointer to ext4_inode
* @param inode_no Inode number
*/
void ext4_superblock::update_inode(const ext4_inode *ino, ext4_inode_no inode_no)
{
assert(inode_no != 0);
uint32_t bg_no = ext4_inode_number_to_bg(inode_no, this);
uint32_t index = (inode_no - 1) % inodes_per_block_group;
uint32_t inodes_per_block = block_size / inode_size;
uint32_t block = index / inodes_per_block;
uint32_t off = (index % inodes_per_block) * inode_size;

assert(bg_no < number_of_block_groups);

const auto &bg = block_groups[bg_no];

auto buf = bg.get_inode_table(this, block);
if (!buf)
{
error("Error reading inode table.");
printk("Tried to read block %u\n", bg.get_bgd()->bg_inode_table_lo);
return;
}

ext4_inode *on_disk = (ext4_inode *) ((char *) block_buf_data(buf) + off);

memcpy(on_disk, ino, inode_size);

ext4_update_inode_csum(this, on_disk, inode_no);

block_buf_dirty(buf);
}

size_t ext4_calculate_dirent_size(size_t len_name)
{
size_t dirent_size = sizeof(ext4_dir_entry_t) - (255 - len_name);
Expand Down Expand Up @@ -536,22 +424,6 @@ int ext4_link_fops(struct file *_target, const char *name, struct dentry *_dir)
return ext4_link(_target->f_ino, name, _dir->d_inode);
}

struct inode *ext4_load_inode_from_disk(uint32_t inum, struct ext4_superblock *fs)
{
struct ext4_inode *inode = fs->get_inode(inum);
if (!inode)
return nullptr;

struct inode *node = ext4_fs_ino_to_vfs_ino(inode, inum, fs);
if (!node)
{
free(inode);
return errno = ENOMEM, nullptr;
}

return node;
}

bool ext4_is_standard_dir_link(ext4_dir_entry_t *entry)
{
if (!memcmp(entry->name, ".", entry->name_len))
Expand Down Expand Up @@ -684,8 +556,3 @@ int ext4_unlink(const char *name, int flags, struct dentry *dir)

return 0;
}

int ext4_fallocate(int mode, off_t off, off_t len, struct file *ino)
{
return -ENOSYS;
}
177 changes: 4 additions & 173 deletions kernel/kernel/fs/ext4/ext4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,66 +62,17 @@ struct file_ops ext4_ops = {.open = ext4_open,
.writepage = ext4_writepage,
.prepare_write = ext4_prepare_write};

/**
Calculates the superblock's checksum.
@param[in] Partition Pointer to the opened partition.
@param[in] Sb Pointer to the superblock.
@return The superblock's checksum.
**/
static uint32_t ext4_calculate_sb_csum(const ext4_superblock *sb)
int ext4_fallocate(int mode, off_t off, off_t len, struct file *ino)
{
return ext4_calculate_csum(sb, sb->sb, offsetof(superblock_t, s_checksum), ~0U);
}

void ext4_dirty_sb(ext4_superblock *fs)
{
if (EXT4_HAS_METADATA_CSUM(fs))
fs->sb->s_checksum = ext4_calculate_sb_csum(fs);
block_buf_dirty(fs->sb_bb);
}

/**
Verifies that the superblock's checksum is valid.
@param[in] Partition Pointer to the opened partition.
@param[in] Sb Pointer to the superblock.
@return The superblock's checksum.
**/
static bool ext4_verify_sb_csum(const ext4_superblock *sb)
{
if (!EXT4_HAS_METADATA_CSUM(sb))
{
return true;
}

return sb->sb->s_checksum == ext4_calculate_sb_csum(sb);
}

void ext4_delete_inode(struct inode *inode_, uint32_t inum, struct ext4_superblock *fs)
{
struct ext4_inode *inode = ext4_get_inode_from_node(inode_);

inode->i_dtime = clock_get_posix_time();
ext4_free_inode_space(inode_, fs);

inode->i_links = 0;
fs->update_inode(inode, inum);

uint32_t block_group = (inum - 1) / fs->inodes_per_block_group;

if (S_ISDIR(inode->i_mode))
fs->block_groups[block_group].dec_used_dirs();

fs->free_inode(inum);
return -ENOSYS;
}

void ext4_close(struct inode *vfs_ino)
{
struct ext4_inode *inode = ext4_get_inode_from_node(vfs_ino);

/* TODO: It would be better, cache-wise and memory allocator-wise if we
* had ext4_inode incorporate a struct inode inside it, and have everything in the same
* location.
* TODO: We're also storing a lot of redudant info in ext4_inode(we already have most stuff in
/*
* TODO: We're storing a lot of redudant info in ext4_inode(we already have most stuff in
* the regular struct inode).
*/
free(inode);
Expand Down Expand Up @@ -468,37 +419,6 @@ struct inode *ext4_creat(const char *name, int mode, struct dentry *dir)
return i;
}

int ext4_flush_inode(struct inode *inode)
{
struct ext4_inode *ino = ext4_get_inode_from_node(inode);
struct ext4_superblock *fs = ext4_superblock_from_inode(inode);

/* Refresh the on-disk struct with the vfs inode data */
ino->i_atime = inode->i_atime;
ino->i_ctime = inode->i_ctime;
ino->i_mtime = inode->i_mtime;
ino->i_size_lo = (uint32_t) inode->i_size;
ino->i_size_hi = (uint32_t) (inode->i_size >> 32);
ino->i_gid = inode->i_gid;
ino->i_uid = inode->i_uid;
ino->i_links = (uint16_t) inode->i_nlink;
ino->i_blocks = (uint32_t) inode->i_blocks;
ino->i_mode = inode->i_mode;
ino->i_uid = inode->i_uid;

fs->update_inode(ino, (ext4_inode_no) inode->i_inode);

return 0;
}

int ext4_kill_inode(struct inode *inode)
{
struct ext4_superblock *fs = ext4_superblock_from_inode(inode);

ext4_delete_inode(inode, (uint32_t) inode->i_inode, fs);
return 0;
}

int ext4_statfs(struct statfs *buf, superblock *sb)
{
return ((ext4_superblock *) sb)->stat_fs(buf);
Expand Down Expand Up @@ -778,92 +698,3 @@ struct inode *ext4_mkdir(const char *name, mode_t mode, struct dentry *dir)

return new_dir;
}

/**
* @brief Reports a filesystem error
*
* @param str Error Message
*/
void ext4_superblock::error(const char *str, ...) const
{
char *buf = (char *) malloc(512);
bool stack = false;
if (!buf)
{
// Cheers, I hate this. But lets prioritize error reporting
stack = true;
buf = (char *) alloca(200);
}

va_list va;
va_start(va, str);
int st = vsnprintf(buf, stack ? 200 : 512, str, va);

if (st < 0)
strcpy(buf, "<bad error format string>");

va_end(va);
printk("ext4 error: %s\n", buf);

if (!stack)
free(buf);

sb->s_state = EXT4_ERROR_FS;
block_buf_dirty(sb_bb);
block_buf_writeback(sb_bb);

if (sb->s_errors == EXT4_ERRORS_CONTINUE)
return;
else if (sb->s_errors == EXT4_ERRORS_PANIC)
panic("ext4: Panic from previous filesystem error");

/* TODO: Add (re)mouting read-only */
}

/**
* @brief Does statfs
*
* @param buf statfs struct to fill
* @return 0 on success, negative error codes (in our case, always succesful)
*/
int ext4_superblock::stat_fs(struct statfs *buf)
{
buf->f_type = EXT4_SIGNATURE;
buf->f_bsize = block_size;
buf->f_blocks = sb->s_blocks_count;
buf->f_bfree = sb->s_free_blocks_count;
buf->f_bavail = sb->s_free_blocks_count - sb->s_r_blocks_count;
buf->f_files = sb->s_inodes_count;
buf->f_ffree = sb->s_free_inodes_count;

return 0;
}

/**
Calculates the checksum of the given buffer.
@param[in] Partition Pointer to the opened EXT4 partition.
@param[in] Buffer Pointer to the buffer.
@param[in] Length Length of the buffer, in bytes.
@param[in] InitialValue Initial value of the CRC.
@return The checksum.
**/
uint32_t ext4_calculate_csum(const ext4_superblock *sb, const void *buffer, size_t length,
uint32_t initial_value)
{
if (!EXT4_HAS_METADATA_CSUM(sb))
{
return 0;
}

switch (sb->sb->s_checksum_type)
{
case EXT4_CHECKSUM_CRC32C:
// For some reason, EXT4 really likes non-inverted CRC32C checksums, so we stick to that
// here.
return ~crc32c_calculate(buffer, length, ~initial_value);
default:
panic("ext4: Bad checksum type %u - this should be unreachable\n",
sb->sb->s_checksum_type);
return 0;
}
}
Loading

0 comments on commit a6fa615

Please sign in to comment.