aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-08-25 17:08:15 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-08-26 11:16:17 +0200
commitcd92184749880817b5f495b1006365c8c88ebab6 (patch)
treebbe1abc0eb17f1ce80f23cbed9af1dc6d05fa5fe /kernel
parent1a437c02fa9f488f2d2ada23b13fc9f5b16699bf (diff)
downloadkernel-cd92184749880817b5f495b1006365c8c88ebab6.tar.xz
kernel-cd92184749880817b5f495b1006365c8c88ebab6.zip
kernel/fs: ext2: extract stateless functions
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.cpp112
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.hpp23
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.tests.cpp27
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp6
4 files changed, 81 insertions, 87 deletions
diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp
index 5104e8cc..18af5a61 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.cpp
@@ -40,6 +40,12 @@ namespace kernel::filesystem::ext2
namespace
{
+ struct indirect_level
+ {
+ uint32_t slot_index;
+ size_t capacity;
+ };
+
//! Check if the given bit has the bit at the given index set.
//!
//! @warning This function will panic if the bit index is out-of-bounds for the given bitmap.
@@ -66,6 +72,36 @@ namespace kernel::filesystem::ext2
bitmap.at(byte_index) |= static_cast<std::byte>(1u << bit_index);
}
+ //! Get the number of block numbers storable on each level
+ //!
+ //! @param level The level to check.
+ //! @param block_size The size of a single block.
+ [[nodiscard]] constexpr auto block_numbers(std::size_t level, kstd::bytes block_size) noexcept -> std::size_t
+ {
+ if (level == 0)
+ {
+ return constants::direct_block_count;
+ }
+
+ auto const numbers_per_block = block_size / kstd::size_of<std::uint32_t>();
+ auto result = numbers_per_block;
+ for (auto current_level = level; current_level > 1; --current_level)
+ {
+ result *= numbers_per_block;
+ }
+
+ return result;
+ }
+
+ [[nodiscard]] constexpr auto indirect_levels(kstd::bytes block_size) -> std::array<indirect_level, 3>
+ {
+ return {
+ {{constants::singly_indirect_block_index, block_numbers(1, block_size)},
+ {constants::doubly_indirect_block_index, block_numbers(2, block_size)},
+ {constants::triply_indirect_block_index, block_numbers(3, block_size)}}
+ };
+ }
+
//! The set of "incompatible" Extended Filesystem features supported by this driver.
constexpr auto supported_incompatible_features = incompatible_features::file_types_in_directory_entries;
@@ -167,12 +203,11 @@ namespace kernel::filesystem::ext2
return kstd::failure(vfs_errc::not_mounted);
}
- auto const & inode_data = ext2_parent->data();
auto buffer = kstd::vector<std::byte>{block_size(*mount_state).value};
for (auto i = 0u; i < block_count(*ext2_parent, *mount_state); ++i)
{
- auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data, *mount_state);
+ auto const global_block_number = inode_block_number(i, *ext2_parent, *mount_state);
if (!global_block_number)
{
return kstd::failure(global_block_number.error());
@@ -328,20 +363,11 @@ namespace kernel::filesystem::ext2
return state.backing_inode->write(buffer, block_offset);
}
- auto filesystem::indirect_levels(mount_state const & state) const -> std::array<indirect_level, 3>
- {
- return {
- {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)},
- {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)},
- {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}}
- };
- }
-
auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode,
mount_state & state) -> kstd::result<void>
{
auto const last_block_index = block_count(directory, state) - 1;
- auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, directory.data(), state);
+ auto const global_block = inode_block_number(last_block_index, directory, state);
if (!global_block)
{
@@ -403,8 +429,7 @@ namespace kernel::filesystem::ext2
}
auto const new_block_index = block_count(directory, state) - 1;
- auto const new_global_block =
- map_inode_block_index_to_global_block_number(new_block_index, directory.data(), state);
+ auto const new_global_block = inode_block_number(new_block_index, directory, state);
if (!new_global_block)
{
return kstd::failure(new_global_block.error());
@@ -440,7 +465,7 @@ namespace kernel::filesystem::ext2
return kstd::failure(ext2_errc::not_enough_free_blocks);
}
- auto const global_block = map_inode_block_index_to_global_block_number(0, directory.data(), state);
+ auto const global_block = inode_block_number(0, directory, state);
if (!global_block)
{
return kstd::failure(global_block.error());
@@ -703,35 +728,38 @@ namespace kernel::filesystem::ext2
return kstd::failure(ext2_errc::not_enough_inodes);
}
- auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data,
- mount_state const & state) const
+ auto filesystem::inode_block_number(size_t index, inode const & inode, mount_state const & state) const
-> kstd::result<std::size_t>
{
- if (inode_block_index < constants::direct_block_count)
+ auto const & block_array = inode.data().block;
+
+ if (index < constants::direct_block_count)
{
- return data.block.at(inode_block_index);
+ return block_array.at(index);
}
- inode_block_index -= constants::direct_block_count;
-
- for (auto const & level : indirect_levels(state))
+ index -= constants::direct_block_count;
+ auto const block_size = this->block_size(state);
+ auto const numbers_per_block = block_numbers(1, block_size);
+ for (auto const & level : indirect_levels(block_size))
{
- if (inode_block_index >= level.capacity)
+ auto const capacity = level.capacity;
+ if (index >= capacity)
{
- inode_block_index -= level.capacity;
+ index -= capacity;
continue;
}
- auto block_number = data.block[level.slot_index];
+ auto block_number = block_array[level.slot_index];
if (block_number == 0)
{
return 0;
}
- for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state))
+ for (auto stride = capacity / numbers_per_block;; stride /= numbers_per_block)
{
- auto const idx = inode_block_index / stride;
- inode_block_index %= stride;
+ auto const idx = index / stride;
+ index %= stride;
if (auto read_result = read_block_number_at_index(block_number, idx, state); !read_result)
{
@@ -786,7 +814,9 @@ namespace kernel::filesystem::ext2
}
inode_block_index -= constants::direct_block_count;
- for (auto const & level : indirect_levels(state))
+ auto const block_size = this->block_size(state);
+ auto const numbers_per_block = block_numbers(1, block_size);
+ for (auto const & level : indirect_levels(block_size))
{
if (inode_block_index >= level.capacity)
{
@@ -799,7 +829,7 @@ namespace kernel::filesystem::ext2
auto parent_byte_offset = 0_B;
bool is_root = true;
- for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state))
+ for (auto stride = level.capacity / numbers_per_block;; stride /= numbers_per_block)
{
auto const idx = inode_block_index / stride;
inode_block_index %= stride;
@@ -828,7 +858,7 @@ namespace kernel::filesystem::ext2
}
}
- auto const byte_offset = block_number * block_size(state) + idx * kstd::size_of<uint32_t>();
+ auto const byte_offset = block_number * block_size + idx * kstd::size_of<uint32_t>();
if (stride == 1)
{
@@ -923,26 +953,6 @@ namespace kernel::filesystem::ext2
}();
}
- auto filesystem::block_numbers_per_block(mount_state const & state) const -> size_t
- {
- return block_size(state) / kstd::size_of<uint32_t>();
- }
-
- auto filesystem::block_numbers_per_singly_indirect_block(mount_state const & state) const -> size_t
- {
- return block_numbers_per_block(state);
- }
-
- auto filesystem::block_numbers_per_doubly_indirect_block(mount_state const & state) const -> size_t
- {
- return block_numbers_per_singly_indirect_block(state) * block_numbers_per_block(state);
- }
-
- auto filesystem::block_numbers_per_triply_indirect_block(mount_state const & state) const -> size_t
- {
- return block_numbers_per_doubly_indirect_block(state) * block_numbers_per_block(state);
- }
-
auto filesystem::update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void
{
data.blocks += delta * (2 << state.superblock.log_block_size);
diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp
index e98dabde..93836b91 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.hpp
@@ -18,7 +18,6 @@
#include <kstd/units.hpp>
#include <kstd/vector.hpp>
-#include <array>
#include <cstddef>
#include <cstdint>
#include <optional>
@@ -172,14 +171,13 @@ namespace kernel::filesystem::ext2
//! @param data The inode data to write.
auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result<void>;
- //! Map an inode block index to a global block number.
+ //! Get the block number associated with the nth block of an inode.
//!
- //! @param inode_block_index The index of the block within the inode.
+ //! @param index The index of the block within the inode.
+ //! @param inode The inode.
//! @param state The state to operate on.
- //! @param data The inode data.
//! @return The global block number on success, an error otherwise.
- [[nodiscard]] auto map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data,
- mount_state const & state) const
+ [[nodiscard]] auto inode_block_number(size_t index, inode const & inode, mount_state const & state) const
-> kstd::result<std::size_t>;
//! Write a global block number to an inode block index.
@@ -193,14 +191,6 @@ namespace kernel::filesystem::ext2
-> kstd::result<void>;
private:
- struct indirect_level
- {
- uint32_t slot_index;
- size_t capacity;
- };
-
- [[nodiscard]] auto indirect_levels(mount_state const & state) const -> std::array<indirect_level, 3>;
-
//! Allocate a single inode in the file system.
//!
//! @param state The driver state to operate on.
@@ -250,11 +240,6 @@ namespace kernel::filesystem::ext2
[[nodiscard]] auto block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes;
- [[nodiscard]] auto block_numbers_per_block(mount_state const & state) const -> size_t;
- [[nodiscard]] auto block_numbers_per_singly_indirect_block(mount_state const & state) const -> size_t;
- [[nodiscard]] auto block_numbers_per_doubly_indirect_block(mount_state const & state) const -> size_t;
- [[nodiscard]] auto block_numbers_per_triply_indirect_block(mount_state const & state) const -> size_t;
-
[[nodiscard]] auto write_block_group_descriptor(block_group_descriptor const & block_group_descriptor,
size_t block_group_descriptor_index,
mount_state const & state) const -> kstd::result<void>;
diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
index c0df4647..6303959d 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
@@ -8,6 +8,7 @@
#include <kernel/filesystem/ext2/mount_state.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
+#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/mount.hpp>
#include <kernel/test_support/cpu.hpp>
#include <kernel/test_support/devices/block_device.hpp>
@@ -227,18 +228,20 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
auto const doubly_start = singly_start + numbers_per_block;
auto const triply_start = doubly_start + numbers_per_block * numbers_per_block;
+ auto inode = kernel::filesystem::ext2::inode{42, inode_data};
+
THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
{
- REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data, *mount_state) == 7);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data, *mount_state) == 31);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data, *mount_state) == 42);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data, *mount_state) == 53);
+ REQUIRE(fs->inode_block_number(0, inode, *mount_state) == 7);
+ REQUIRE(fs->inode_block_number(singly_start, inode, *mount_state) == 31);
+ REQUIRE(fs->inode_block_number(doubly_start, inode, *mount_state) == 42);
+ REQUIRE(fs->inode_block_number(triply_start, inode, *mount_state) == 53);
}
THEN("mapping returns error for out-of-range indexes")
{
auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block;
- REQUIRE(!fs->map_inode_block_index_to_global_block_number(beyond_triply, inode_data, *mount_state));
+ REQUIRE(!fs->inode_block_number(beyond_triply, inode, *mount_state));
}
}
}
@@ -333,14 +336,12 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
REQUIRE(triply_leaf_table == 21);
REQUIRE(read_u32(static_cast<size_t>(triply_leaf_table) * block_size) == triply_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data, *mount_state) ==
- direct_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data, *mount_state) ==
- singly_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data, *mount_state) ==
- doubly_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data, *mount_state) ==
- triply_global_block_number);
+ auto inode = kernel::filesystem::ext2::inode{42, inode_data};
+
+ REQUIRE(fs->inode_block_number(0, inode, *mount_state) == direct_global_block_number);
+ REQUIRE(fs->inode_block_number(singly_start, inode, *mount_state) == singly_global_block_number);
+ REQUIRE(fs->inode_block_number(doubly_start, inode, *mount_state) == doubly_global_block_number);
+ REQUIRE(fs->inode_block_number(triply_start, inode, *mount_state) == triply_global_block_number);
}
}
}
diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp
index cfc22989..34452ac8 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -67,8 +67,7 @@ namespace kernel::filesystem::ext2
while (bytes_read < requested_size)
{
- auto const block_number =
- (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, **state);
+ auto const block_number = (*filesystem)->inode_block_number(block_index, *this, **state);
if (!block_number)
{
break;
@@ -156,8 +155,7 @@ namespace kernel::filesystem::ext2
while (bytes_written < kstd::bytes{buffer.size()})
{
- auto const block_number =
- (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, **state);
+ auto const block_number = (*filesystem)->inode_block_number(block_index, *this, **state);
// TODO BA-FS26 if blocknumber == 0 --> handle sparse file
if (!block_number)
{