Skip to content

Commit

Permalink
Kernel/Ext2FS: Refactor computing and flushing blocks
Browse files Browse the repository at this point in the history
This is a large commit, since this is essentially a complete rewrite of
the key low-level functions that handle reading/writing blocks. This is,
however, a necessary prerequisite of being able to write holes.

The previous version of `flush_block_list()` (along with its numerous
helper functions) was entirely reliant on all blocks being sequential.
In contrast to the previous implementation, the new version
of `flush_block_list()` simply writes out the difference between the old
block list and the new block list by calculating the correct indirect
block(s) to update based on the relevant block's logical index.

`compute_block_list()` has also been rewritten, since the estimated
amount of meta blocks was incorrectly calculated for files with holes as
a result of the estimated amount of blocks being a function of the file
size. Since it isn't possible to accurately compute the shape of the
block list without traversing it, we no longer try to perform such a
computation, and instead simply search through all of the allocated
indirect blocks.

`compute_block_list_with_meta_blocks()` has also been removed in favor
of the new `compute_meta_blocks()`, since meta blocks are fundamentally
distinct from data blocks due to there being no mapping between any
logical block index and the physical block index.
  • Loading branch information
implicitfield committed Apr 28, 2024
1 parent 8ef114f commit ab0aa9f
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 385 deletions.
41 changes: 7 additions & 34 deletions Kernel/FileSystem/Ext2FS/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,39 +159,6 @@ bool Ext2FS::find_block_containing_inode(InodeIndex inode, BlockIndex& block_ind
return true;
}

Ext2FS::BlockListShape Ext2FS::compute_block_list_shape(unsigned blocks) const
{
BlockListShape shape;
unsigned const entries_per_block = EXT2_ADDR_PER_BLOCK(&super_block());
unsigned blocks_remaining = blocks;

shape.direct_blocks = min((unsigned)EXT2_NDIR_BLOCKS, blocks_remaining);
blocks_remaining -= shape.direct_blocks;
if (!blocks_remaining)
return shape;

shape.indirect_blocks = min(blocks_remaining, entries_per_block);
shape.meta_blocks += 1;
blocks_remaining -= shape.indirect_blocks;
if (!blocks_remaining)
return shape;

shape.doubly_indirect_blocks = min(blocks_remaining, entries_per_block * entries_per_block);
shape.meta_blocks += 1;
shape.meta_blocks += ceil_div(shape.doubly_indirect_blocks, entries_per_block);
blocks_remaining -= shape.doubly_indirect_blocks;
if (!blocks_remaining)
return shape;

shape.triply_indirect_blocks = min(blocks_remaining, entries_per_block * entries_per_block * entries_per_block);
shape.meta_blocks += 1;
shape.meta_blocks += ceil_div(shape.triply_indirect_blocks, entries_per_block * entries_per_block);
shape.meta_blocks += ceil_div(shape.triply_indirect_blocks, entries_per_block);
blocks_remaining -= shape.triply_indirect_blocks;
VERIFY(blocks_remaining == 0);
return shape;
}

u8 Ext2FS::internal_file_type_to_directory_entry_type(DirectoryEntryView const& entry) const
{
switch (entry.file_type) {
Expand Down Expand Up @@ -618,11 +585,17 @@ ErrorOr<void> Ext2FS::free_inode(Ext2FSInode& inode)

// Mark all blocks used by this inode as free.
{
auto blocks = TRY(inode.compute_block_list_with_meta_blocks());
auto blocks = TRY(inode.compute_block_list());
for (auto const& [_, block_index] : blocks) {
VERIFY(block_index <= super_block().s_blocks_count && block_index != 0);
TRY(set_block_allocation_state(block_index, false));
}

auto meta_blocks = TRY(inode.compute_meta_blocks());
for (auto const& block : meta_blocks) {
VERIFY(block <= super_block().s_blocks_count && block != 0);
TRY(set_block_allocation_state(block, false));
}
}

// If the inode being freed is a directory, update block group directory counter.
Expand Down
10 changes: 0 additions & 10 deletions Kernel/FileSystem/Ext2FS/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,6 @@ class Ext2FS final : public BlockBasedFileSystem {

using BlockList = HashMap<BlockBasedFileSystem::BlockIndex, BlockBasedFileSystem::BlockIndex>;

struct BlockListShape {
unsigned direct_blocks { 0 };
unsigned indirect_blocks { 0 };
unsigned doubly_indirect_blocks { 0 };
unsigned triply_indirect_blocks { 0 };
unsigned meta_blocks { 0 };
};

BlockListShape compute_block_list_shape(unsigned blocks) const;

u64 m_block_group_count { 0 };

mutable ext2_super_block m_super_block {};
Expand Down
Loading

0 comments on commit ab0aa9f

Please sign in to comment.