diff options
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.cpp | 112 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.hpp | 23 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 27 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.cpp | 6 |
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) { |
