aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-08-26 16:23:52 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-08-26 20:37:48 +0200
commit5e21c8f70a41d1ac31992d86730d987fdd952a51 (patch)
treedd0546b9a11640f1a018d25d1e81d5c2c351d358
parent35175463977f85d949b2168a4f062158d2a911d1 (diff)
downloadkernel-5e21c8f70a41d1ac31992d86730d987fdd952a51.tar.xz
kernel-5e21c8f70a41d1ac31992d86730d987fdd952a51.zip
kernel/fs: ext2: clean up stateless functions
-rw-r--r--kernel/kernel/filesystem/ext2/directory_iterator.cpp6
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.cpp971
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.hpp282
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.tests.cpp40
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp78
-rw-r--r--kernel/kernel/filesystem/ext2/inode.hpp10
-rw-r--r--kernel/kernel/filesystem/ext2/inode.tests.cpp10
-rw-r--r--kernel/kernel/filesystem/ext2/superblock.hpp14
-rw-r--r--kernel/kernel/filesystem/ext2/write_batch.cpp11
-rw-r--r--kernel/kernel/filesystem/ext2/write_batch.hpp4
10 files changed, 678 insertions, 748 deletions
diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.cpp
index 3e614f26..cfb520d6 100644
--- a/kernel/kernel/filesystem/ext2/directory_iterator.cpp
+++ b/kernel/kernel/filesystem/ext2/directory_iterator.cpp
@@ -37,7 +37,7 @@ namespace kernel::filesystem::ext2
auto directory_iterator::operator++() -> directory_iterator &
{
- if (!m_inode || m_file_offset >= m_filesystem->data_size(*m_inode, *m_state))
+ if (!m_inode || m_file_offset >= data_size(*m_inode, *m_state))
{
m_inode = nullptr;
return *this;
@@ -64,7 +64,7 @@ namespace kernel::filesystem::ext2
auto directory_iterator::read() -> void
{
- if (auto result = m_filesystem->do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result)
+ if (auto result = do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result)
{
kapi::system::panic("[FS:ext2] failed to read directory entry", result.error());
}
@@ -77,7 +77,7 @@ namespace kernel::filesystem::ext2
{
m_buffer.resize(m_buffer.size() + remainder);
- if (auto result = m_filesystem->do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result)
+ if (auto result = do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result)
{
kapi::system::panic("[FS:ext2] failed to read directory entry", result.error());
}
diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp
index 4f5ff686..10b5cd66 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.cpp
@@ -42,6 +42,7 @@ namespace kernel::filesystem::ext2
//! Check that this driver class is stateless.
static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem));
+ //! Hidden implementation details.
namespace
{
struct indirect_level
@@ -56,7 +57,7 @@ namespace kernel::filesystem::ext2
//!
//! @param bitmap The bitmap to check.
//! @param index The index of the bit to check.
- [[nodiscard]] auto bitmap_is_set(kstd::vector<std::byte> const & bitmap, size_t index) -> bool
+ [[nodiscard]] constexpr auto bitmap_is_set(kstd::vector<std::byte> const & bitmap, size_t index) -> bool
{
auto const byte_index = index / 8;
auto const bit_index = index % 8;
@@ -69,7 +70,7 @@ namespace kernel::filesystem::ext2
//!
//! @param bitmap The bitmap to manipulate.
//! @param index The index of the bit to set.
- auto bitmap_set(kstd::vector<std::byte> & bitmap, size_t index) -> void
+ constexpr auto bitmap_set(kstd::vector<std::byte> & bitmap, size_t index) -> void
{
auto const byte_index = index / 8;
auto const bit_index = index % 8;
@@ -97,6 +98,9 @@ namespace kernel::filesystem::ext2
return result;
}
+ //! Get mapping of block indirection levels to possible number of block on that level.
+ //!
+ //! @param block_size The size of a single block.
[[nodiscard]] constexpr auto indirect_levels(kstd::bytes block_size) -> std::array<indirect_level, 3>
{
return {
@@ -106,6 +110,466 @@ namespace kernel::filesystem::ext2
};
}
+ //! Extract the file type from the an ext2 file mode.
+ //!
+ //! @param mode The mode to extract the type from.
+ //! @return The file type encoded in the mode.
+ constexpr auto to_filetype(uint16_t mode) -> kapi::filesystem::file_type
+ {
+ switch (mode & constants::mode_mask)
+ {
+ case constants::mode_regular:
+ return kapi::filesystem::file_type::regular;
+ case constants::mode_directory:
+ return kapi::filesystem::file_type::directory;
+ case constants::mode_block_device:
+ return kapi::filesystem::file_type::block_device;
+ case constants::mode_character_device:
+ return kapi::filesystem::file_type::character_device;
+ case constants::mode_symbolic_link:
+ return kapi::filesystem::file_type::symbolic_link;
+ case constants::mode_fifo:
+ return kapi::filesystem::file_type::fifo;
+ case constants::mode_socket:
+ return kapi::filesystem::file_type::socket;
+ default:
+ return kapi::filesystem::file_type{0};
+ }
+ }
+
+ //! Combine a file type and an ext2 mode.
+ //!
+ //! @param type The type to encode.
+ //! @param mode The original ext2 file mode.
+ constexpr auto combine(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t
+ {
+ if (mode & constants::mode_mask)
+ {
+ return mode;
+ }
+
+ return mode | [=] {
+ switch (type)
+ {
+ case kapi::filesystem::file_type::directory:
+ return constants::mode_directory;
+ case kapi::filesystem::file_type::regular:
+ return constants::mode_regular;
+ case kapi::filesystem::file_type::block_device:
+ return constants::mode_block_device;
+ case kapi::filesystem::file_type::character_device:
+ return constants::mode_character_device;
+ case kapi::filesystem::file_type::symbolic_link:
+ return constants::mode_symbolic_link;
+ case kapi::filesystem::file_type::fifo:
+ return constants::mode_fifo;
+ case kapi::filesystem::file_type::socket:
+ return constants::mode_socket;
+ default:
+ kapi::system::panic("[EXT2] Not implemented.");
+ }
+ }();
+ }
+
+ //! Convert a file type to a directory entry file type.
+ //!
+ //! @param type The file type to convert.
+ //! @return The directory file type.
+ constexpr auto to_directory_file_type(kapi::filesystem::file_type type) -> std::uint8_t
+ {
+ switch (type)
+ {
+ case kapi::filesystem::file_type::regular:
+ return 1;
+ case kapi::filesystem::file_type::directory:
+ return 2;
+ case kapi::filesystem::file_type::character_device:
+ return 3;
+ case kapi::filesystem::file_type::block_device:
+ return 4;
+ case kapi::filesystem::file_type::fifo:
+ return 5;
+ case kapi::filesystem::file_type::socket:
+ return 6;
+ case kapi::filesystem::file_type::symbolic_link:
+ return 7;
+ default:
+ return 0;
+ }
+ }
+
+ //! Write a new directory entry into the given buffer.
+ //!
+ //! @param buffer The buffer to write to.
+ //! @param offset The offset inside to the buffer.
+ //! @param target The inode the entry targets.
+ //! @param name The name for the entry.
+ //! @param type The filet type of the entry.
+ //! @return A pointer to the written entry on success, an error otherwise.
+ auto write_directory_entry_to_buffer(std::span<std::byte> buffer, kstd::bytes offset, inode & target,
+ std::string_view name, kapi::filesystem::file_type type)
+ -> kstd::result<linked_directory_entry *>
+ {
+ auto const name_length = static_cast<uint8_t>(name.size());
+ auto const record_size = (sizeof(linked_directory_entry) - 1 + name_length + 3u) & ~3u;
+ if (buffer.size() - offset.value < record_size)
+ {
+ // TODO: improve error code.
+ return kstd::failure(vfs_errc::invalid_argument);
+ }
+
+ auto * entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
+ entry->inode = target.number();
+ entry->rec_len = record_size;
+ entry->name_len = name_length;
+ entry->file_type = to_directory_file_type(type);
+ kstd::libc::memcpy(&entry->name_start, name.data(), name_length);
+ return kstd::success(entry);
+ }
+
+ //! Get the revision level of the filesystem.
+ //!
+ //! @param state The driver state to operate on.
+ //! @return The revision level.
+ [[nodiscard]] constexpr auto revision_level(mount_state const & state) -> uint32_t
+ {
+ return state.superblock.rev_level;
+ }
+
+ //! Get the size of an inode in the filesystem.
+ //!
+ //! @param state The driver state to operate on.
+ //! @return The size of an inode in bytes.
+ [[nodiscard]] auto inode_size(mount_state const & state) -> kstd::bytes
+ {
+ return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size);
+ }
+
+ //! Read a block from the backing inode into the provided buffer.
+ //!
+ //! @param block_number The number of the block to read.
+ //! @param buffer The buffer to read the block data into.
+ //! @param state The state to operate on.
+ //! @return The number of bytes read.
+ [[nodiscard]] auto read_block(uint32_t block_number, std::span<std::byte> buffer, mount_state const & state)
+ -> kstd::result<kstd::bytes>
+ {
+ if (buffer.size() < block_size(state).value)
+ {
+ return kstd::failure(vfs_errc::invalid_argument);
+ }
+
+ auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
+ return state.backing_inode->read(buffer, block_offset);
+ }
+
+ //! Write a block of data from the provided buffer to the backing inode.
+ //!
+ //! @param block_number The number of the block to write.
+ //! @param buffer The buffer containing the data to write.
+ //! @param state The state to operate on.
+ //! @return The number of bytes written.
+ [[nodiscard]] auto write_block(uint32_t block_number, std::span<std::byte const> buffer, mount_state & state)
+ -> kstd::result<kstd::bytes>
+ {
+ if (buffer.size() < block_size(state).value)
+ {
+ return kstd::failure(vfs_errc::invalid_argument);
+ }
+
+ auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
+ return state.backing_inode->write(buffer, block_offset);
+ }
+
+ //! Allocate a single inode in the file system.
+ //!
+ //! @param state The driver state to operate on.
+ //! @param batch The active write batch.
+ //! @return An inode number on success, an error otherwise.
+ auto allocate_inode(mount_state & state, write_batch & batch) -> kstd::result<uint32_t>
+ {
+ auto & [superblock, block_group_descriptors, _, __] = state;
+
+ if (block_group_descriptors.empty() || superblock.free_inodes_count == 0)
+ {
+ return kstd::failure(ext2_errc::not_enough_inodes);
+ }
+
+ for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < block_group_descriptors.size();
+ ++block_group_descriptor_index)
+ {
+ auto & block_group_descriptor = block_group_descriptors.at(block_group_descriptor_index);
+ if (block_group_descriptor.free_inodes_count == 0)
+ {
+ continue;
+ }
+
+ auto inode_bitmap = kstd::vector<std::byte>{block_size(state).value};
+ if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap, state); !read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
+
+ for (auto i = 0uz; i < static_cast<size_t>(superblock.inodes_per_group); ++i)
+ {
+ if (!bitmap_is_set(inode_bitmap, i))
+ {
+ bitmap_set(inode_bitmap, i);
+ block_group_descriptor.free_inodes_count--;
+ superblock.free_inodes_count--;
+
+ if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap, state);
+ !write_result)
+ {
+ return kstd::failure(write_result.error());
+ }
+
+ batch.mark_group(block_group_descriptor_index);
+
+ return block_group_descriptor_index * superblock.inodes_per_group + i + 1;
+ }
+ }
+ }
+
+ return kstd::failure(ext2_errc::not_enough_inodes);
+ }
+
+ //! Add a new directory entry to a given directory.
+ //!
+ //! @param directory The directory to add the entry to.
+ //! @param name The name for the entry.
+ //! @param child The inode number of the child.
+ //! @param mode The file mode of the entry.
+ //! @param state The driver state to operate on.
+ //! @param batch The active write batch.
+ //! @return Nothing on success, an error code otherwise.
+ auto add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode,
+ mount_state & state, write_batch & batch) -> kstd::result<void>
+ {
+ auto const last_block_index = block_count(directory, state) - 1;
+ auto const global_block = inode_block_number(last_block_index, directory, state);
+
+ if (!global_block)
+ {
+ return kstd::failure(global_block.error());
+ }
+
+ auto buffer = kstd::vector<std::byte>{block_size(state).value};
+ if (auto result = read_block(*global_block, buffer, state); !result)
+ {
+ return kstd::failure(result.error());
+ }
+
+ // TODO handle "gaps" in directory entries (e.g., after deletions) in the current implementation, we only
+ // add new entries at the end of the last block, but we could also reuse space from deleted entries
+ auto offset = 0_B;
+ while (true)
+ {
+ auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + offset);
+ if (offset + kstd::bytes{entry->rec_len} >= block_size(state))
+ {
+ break;
+ }
+ offset += kstd::bytes{entry->rec_len};
+ }
+
+ auto const file_type = to_filetype(mode);
+ auto const name_len = static_cast<uint8_t>(name.size());
+ auto const needed_rec_len = static_cast<kstd::bytes>((8u + name_len + 3u) & ~3u);
+
+ auto * last_entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
+ auto const last_entry_actual_len = static_cast<kstd::bytes>((8u + last_entry->name_len + 3u) & ~3u);
+
+ if (kstd::bytes{last_entry->rec_len} - last_entry_actual_len >= needed_rec_len)
+ {
+ last_entry->rec_len = last_entry_actual_len.value;
+ auto entry_offset = offset + last_entry_actual_len;
+ auto entry = write_directory_entry_to_buffer(buffer, entry_offset, child, name, file_type);
+ if (!entry)
+ {
+ return kstd::failure(entry.error());
+ }
+
+ auto remainder = block_size(state) - entry_offset;
+ (*entry)->rec_len = remainder.value;
+
+ return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); })
+ .transform([](auto) {});
+ }
+ else
+ {
+ if (!directory.append_blocks(1, batch))
+ {
+ return kstd::failure(ext2_errc::not_enough_free_blocks);
+ }
+
+ auto const new_block_index = block_count(directory, state) - 1;
+ auto const new_global_block = inode_block_number(new_block_index, directory, state);
+ if (!new_global_block)
+ {
+ return kstd::failure(new_global_block.error());
+ }
+
+ kstd::libc::memset(buffer.data(), 0, block_size(state).value);
+ auto entry = write_directory_entry_to_buffer(buffer, 0_B, child, name, file_type);
+ if (!entry)
+ {
+ return kstd::failure(entry.error());
+ }
+
+ auto remainder = block_size(state);
+ (*entry)->rec_len = remainder.value;
+
+ if (auto result =
+ new_global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); });
+ !result)
+ {
+ return kstd::failure(result.error());
+ }
+ }
+
+ auto size = block_count(directory, state) * block_size(state);
+ directory.data().size = size.value;
+ batch.mark_inode(directory);
+ return kstd::success();
+ }
+
+ //! Initialize a new directory inode.
+ //!
+ //! This function initializes an inode to be an empty directory. On success, the inode will be a directory with only
+ //! two children, "." and "..".
+ //!
+ //! @param directory The inode to initialize.
+ //! @param parent The parent of this newly initialized directory.
+ //! @param state The driver state to operate on.
+ //! @param batch The active write batch.
+ //! @return Nothing on success, an error otherwise.
+ auto init_directory(inode & directory, inode & parent, mount_state & state, write_batch & batch)
+ -> kstd::result<void>
+ {
+ if (!directory.append_blocks(1, batch))
+ {
+ return kstd::failure(ext2_errc::not_enough_free_blocks);
+ }
+
+ auto const global_block = inode_block_number(0, directory, state);
+ if (!global_block)
+ {
+ return kstd::failure(global_block.error());
+ }
+
+ auto buffer = kstd::vector<std::byte>{block_size(state).value};
+ auto dot = write_directory_entry_to_buffer(buffer, 0_B, directory, ".", kapi::filesystem::file_type::directory);
+
+ if (!dot)
+ {
+ return kstd::failure(dot.error());
+ }
+
+ auto dot_dot_offset = kstd::bytes{(*dot)->rec_len};
+ auto dot_dot =
+ write_directory_entry_to_buffer(buffer, dot_dot_offset, parent, "..", kapi::filesystem::file_type::directory);
+ if (!dot_dot)
+ {
+ return kstd::failure(dot_dot.error());
+ }
+ auto remainder = block_size(state) - dot_dot_offset;
+ (*dot_dot)->rec_len = remainder.value;
+
+ // '..' inside the new dir counts as an extra hard link to the parent
+ auto & parent_inode_data = parent.data();
+ parent_inode_data.links_count++;
+
+ batch.mark_inode(parent);
+
+ return global_block.and_then([&](auto number) { return write_block(number, buffer, state); }).transform([](auto) {
+ });
+ }
+
+ //! Calculate the offset of the inode with a given number in the filesystem.
+ //!
+ //! @param number The number of the inode.
+ //! @param state The driver state to operate on.
+ //! @return The offset to the filesystem start of the inode.
+ [[nodiscard]] auto calculate_inode_offset(std::uint32_t number, mount_state const & state)
+ -> kstd::result<kstd::bytes>
+ {
+ auto const inodes_per_group = state.superblock.inodes_per_group;
+ auto const block_group_index = (number - 1) / inodes_per_group;
+ auto const inode_index_within_group = (number - 1) % inodes_per_group;
+
+ if (block_group_index >= state.block_group_descriptors.size())
+ {
+ return kstd::failure(ext2_errc::invalid_block_group_index);
+ }
+
+ auto const & block_group_descriptor = state.block_group_descriptors.at(block_group_index);
+ auto const inode_table_start_block = block_group_descriptor.inode_table;
+ auto const inode_table_offset = inode_table_start_block * block_size(state);
+ auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size(state);
+
+ return inode_offset;
+ }
+
+ //! Read the inode with the given number from the filesystem.
+ //!
+ //! @param number The number of the inode to read.
+ //! @param state The driver state to operate on.
+ //! @return The read inode on success, an error otherwise.
+ [[nodiscard]] auto read_inode(std::uint32_t number, mount_state const & state)
+ -> kstd::result<kstd::shared_ptr<inode>>
+ {
+ if (auto inode_offset = calculate_inode_offset(number, state))
+ {
+ auto new_inode_data = inode_data{};
+
+ if (auto read_result = state.backing_inode->read(kstd::raw_bytes(new_inode_data), *inode_offset); !read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
+ else
+ {
+ return kstd::make_shared<struct inode>(number, new_inode_data);
+ }
+ }
+ else
+ {
+ return kstd::failure(inode_offset.error());
+ }
+ }
+
+ //! Read the indirect block number from the specified block at the specified index.
+ //!
+ //! @param block The number of the indirect block to read from.
+ //! @param index The index into the indirect block to read from.
+ //! @param state The driver state to operate on.
+ //! @return The block number at the given index in the given indirect block on success, an error otherwise.
+ [[nodiscard]] auto read_block_number_at_index(std::uint32_t block, std::size_t index, mount_state const & state)
+ -> kstd::result<uint32_t>
+ {
+ uint32_t block_number_buffer = 0;
+
+ auto const block_offset = block * block_size(state);
+ auto const number_offset = block_offset + index * kstd::size_of<uint32_t>();
+
+ if (auto read_result = state.backing_inode->read(kstd::raw_bytes(block_number_buffer), number_offset);
+ !read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
+
+ return block_number_buffer;
+ }
+
+ //! Get the offset of the Block Group Descriptor table.
+ //!
+ //! @param state The driver state to operate on.
+ //! @return The filesystem offset of the block group descriptor table.
+ [[nodiscard]] auto block_group_descriptor_table_offset(mount_state const & state) -> kstd::bytes
+ {
+ return block_size(state) == 1024_B ? 2 * block_size(state) : block_size(state);
+ }
+
//! The set of "incompatible" Extended Filesystem features supported by this driver.
constexpr auto supported_incompatible_features = incompatible_features::file_types_in_directory_entries;
@@ -229,12 +693,13 @@ namespace kernel::filesystem::ext2
driver_data_ptr driver_data, std::optional<kapi::filesystem::device_number> raw_device)
-> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>>
{
- if (!parent)
+ auto const ext2_parent = static_pointer_cast<inode>(parent);
+ if (!ext2_parent)
{
- return kstd::failure(vfs_errc::invalid_inode);
+ return kstd::failure(vfs_errc::invalid_argument);
}
- if (!parent->is_directory())
+ if (!ext2_parent->is_directory())
{
return kstd::failure(vfs_errc::not_a_directory);
}
@@ -245,12 +710,6 @@ namespace kernel::filesystem::ext2
return kstd::failure(vfs_errc::invalid_argument);
}
- auto const ext2_parent = static_pointer_cast<inode>(parent);
- if (!ext2_parent)
- {
- return kstd::failure(vfs_errc::invalid_argument);
- }
-
auto const mount_state = static_pointer_cast<struct mount_state>(driver_data);
if (!mount_state)
{
@@ -258,7 +717,7 @@ namespace kernel::filesystem::ext2
}
auto guard = kstd::lock_guard{mount_state->lock};
- auto batch = write_batch{*this, *mount_state};
+ auto batch = write_batch{*mount_state};
auto maybe_inode_number = allocate_inode(*mount_state, batch);
if (!maybe_inode_number)
@@ -271,7 +730,7 @@ namespace kernel::filesystem::ext2
auto data = inode_data{};
// TODO: use correct access rights
- data.mode = map_vfs_inode_type_into_inode_mode(type, no_access_restrictions);
+ data.mode = combine(type, no_access_restrictions);
data.size = 0;
data.dir_acl = 0;
data.links_count = 1;
@@ -308,281 +767,89 @@ namespace kernel::filesystem::ext2
return created;
}
- auto filesystem::block_size(mount_state const & state) const -> kstd::bytes
- {
- return kstd::bytes{constants::base_block_size.value << state.superblock.log_block_size};
- }
-
- auto filesystem::revision_level(mount_state const & state) const -> uint32_t
- {
- return state.superblock.rev_level;
- }
+ //! @name Free Functions
+ //! @{
- auto filesystem::inode_size(mount_state const & state) const -> kstd::bytes
+ auto block_size(mount_state const & state) -> kstd::bytes
{
- return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size);
+ return kstd::bytes{constants::base_block_size.value << state.superblock.log_block_size};
}
- auto filesystem::block_count(inode const & inode, mount_state const & state) const -> uint32_t
+ auto block_count(inode const & inode, mount_state const & state) -> uint32_t
{
return inode.data().blocks / (2 << state.superblock.log_block_size);
}
- auto filesystem::read_block(uint32_t block_number, std::span<std::byte> buffer, mount_state const & state) const
- -> kstd::result<kstd::bytes>
+ auto data_size(inode const & inode, mount_state const & state) -> kstd::bytes
{
- if (buffer.size() < block_size(state).value)
- {
- return kstd::failure(vfs_errc::invalid_argument);
- }
-
- auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
- return state.backing_inode->read(buffer, block_offset);
- }
+ uint64_t size = inode.data().size;
- auto filesystem::write_block(uint32_t block_number, std::span<std::byte const> buffer, mount_state & state)
- -> kstd::result<kstd::bytes>
- {
- if (buffer.size() < block_size(state).value)
+ if (revision_level(state) > constants::good_old_revision && inode.is_regular())
{
- return kstd::failure(vfs_errc::invalid_argument);
+ size |= static_cast<uint64_t>(inode.data().dir_acl) << 32;
}
- auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
- return state.backing_inode->write(buffer, block_offset);
+ return kstd::bytes{size};
}
- auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode,
- mount_state & state, write_batch & batch) -> kstd::result<void>
+ auto set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) -> void
{
- auto const last_block_index = block_count(directory, state) - 1;
- auto const global_block = inode_block_number(last_block_index, directory, state);
-
- if (!global_block)
- {
- return kstd::failure(global_block.error());
- }
-
- auto buffer = kstd::vector<std::byte>{block_size(state).value};
- if (auto result = read_block(*global_block, buffer, state); !result)
- {
- return kstd::failure(result.error());
- }
-
- // TODO handle "gaps" in directory entries (e.g., after deletions) in the current implementation, we only
- // add new entries at the end of the last block, but we could also reuse space from deleted entries
- auto offset = 0_B;
- while (true)
- {
- auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + offset);
- if (offset + kstd::bytes{entry->rec_len} >= block_size(state))
- {
- break;
- }
- offset += kstd::bytes{entry->rec_len};
- }
-
- auto const file_type = map_inode_mode_to_file_type(mode);
- auto const name_len = static_cast<uint8_t>(name.size());
- auto const needed_rec_len = static_cast<kstd::bytes>((8u + name_len + 3u) & ~3u);
-
- auto * last_entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
- auto const last_entry_actual_len = static_cast<kstd::bytes>((8u + last_entry->name_len + 3u) & ~3u);
-
- if (kstd::bytes{last_entry->rec_len} - last_entry_actual_len >= needed_rec_len)
- {
- last_entry->rec_len = last_entry_actual_len.value;
- auto entry_offset = offset + last_entry_actual_len;
- auto entry = write_directory_entry_to_buffer(buffer, entry_offset, child, name, file_type);
- if (!entry)
- {
- return kstd::failure(entry.error());
- }
-
- auto remainder = block_size(state) - entry_offset;
- (*entry)->rec_len = remainder.value;
-
- return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); })
- .transform([](auto) {});
- }
- else
+ if (revision_level(state) > constants::good_old_revision && inode.is_regular())
{
- if (!directory.append_blocks(1, batch))
- {
- return kstd::failure(ext2_errc::not_enough_free_blocks);
- }
-
- auto const new_block_index = block_count(directory, state) - 1;
- auto const new_global_block = inode_block_number(new_block_index, directory, state);
- if (!new_global_block)
- {
- return kstd::failure(new_global_block.error());
- }
-
- kstd::libc::memset(buffer.data(), 0, block_size(state).value);
- auto entry = write_directory_entry_to_buffer(buffer, 0_B, child, name, file_type);
- if (!entry)
- {
- return kstd::failure(entry.error());
- }
-
- auto remainder = block_size(state);
- (*entry)->rec_len = remainder.value;
-
- if (auto result =
- new_global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); });
- !result)
- {
- return kstd::failure(result.error());
- }
+ inode.data().dir_acl = static_cast<uint32_t>(new_size.value >> 32);
}
-
- auto size = block_count(directory, state) * block_size(state);
- directory.data().size = size.value;
- batch.mark_inode(directory);
- return kstd::success();
+ inode.data().size = static_cast<uint32_t>(new_size.value);
}
- auto filesystem::init_directory(inode & directory, inode & parent, mount_state & state, write_batch & batch)
- -> kstd::result<void>
+ auto do_read(inode const & inode, std::span<std::byte> buffer, kstd::bytes offset, mount_state const & state)
+ -> kstd::result<kstd::bytes>
{
- if (!directory.append_blocks(1, batch))
- {
- return kstd::failure(ext2_errc::not_enough_free_blocks);
- }
-
- auto const global_block = inode_block_number(0, directory, state);
- if (!global_block)
- {
- return kstd::failure(global_block.error());
- }
-
- auto buffer = kstd::vector<std::byte>{block_size(state).value};
- auto dot = write_directory_entry_to_buffer(buffer, 0_B, directory, ".", kapi::filesystem::file_type::directory);
-
- if (!dot)
- {
- return kstd::failure(dot.error());
- }
-
- auto dot_dot_offset = kstd::bytes{(*dot)->rec_len};
- auto dot_dot =
- write_directory_entry_to_buffer(buffer, dot_dot_offset, parent, "..", kapi::filesystem::file_type::directory);
- if (!dot_dot)
- {
- return kstd::failure(dot_dot.error());
- }
- auto remainder = block_size(state) - dot_dot_offset;
- (*dot_dot)->rec_len = remainder.value;
-
- // '..' inside the new dir counts as an extra hard link to the parent
- auto & parent_inode_data = parent.data();
- parent_inode_data.links_count++;
+ auto const max_readable = data_size(inode, state) - offset;
+ auto const requested_size = std::min(kstd::bytes{buffer.size()}, max_readable);
- batch.mark_inode(parent);
+ auto const block_size = ext2::block_size(state);
+ auto block_index = offset / block_size;
+ auto in_block_offset = offset % block_size;
- return global_block.and_then([&](auto number) { return write_block(number, buffer, state); }).transform([](auto) {
- });
- }
+ auto bytes_read = 0_B;
- auto filesystem::write_directory_entry_to_buffer(std::span<std::byte> buffer, kstd::bytes offset, inode & target,
- std::string_view name, kapi::filesystem::file_type type)
- -> kstd::result<linked_directory_entry *>
- {
- auto const name_length = static_cast<uint8_t>(name.size());
- auto const record_size = (sizeof(linked_directory_entry) - 1 + name_length + 3u) & ~3u;
- if (buffer.size() - offset.value < record_size)
+ while (bytes_read < requested_size)
{
- // TODO: improve error code.
- return kstd::failure(vfs_errc::invalid_argument);
- }
-
- auto * entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
- entry->inode = target.number();
- entry->rec_len = record_size;
- entry->name_len = name_length;
- entry->file_type = [=] {
- switch (type)
+ auto const block_number = inode_block_number(block_index, inode, state);
+ if (!block_number)
{
- case kapi::filesystem::file_type::regular:
- return 1;
- case kapi::filesystem::file_type::directory:
- return 2;
- case kapi::filesystem::file_type::character_device:
- return 3;
- case kapi::filesystem::file_type::block_device:
- return 4;
- case kapi::filesystem::file_type::fifo:
- return 5;
- case kapi::filesystem::file_type::socket:
- return 6;
- case kapi::filesystem::file_type::symbolic_link:
- return 7;
- default:
- return 0;
+ break;
}
- }();
- kstd::libc::memcpy(&entry->name_start, name.data(), name_length);
- return kstd::success(entry);
- }
-
- auto filesystem::read_inode(uint32_t inode_number, mount_state const & state) const
- -> kstd::result<kstd::shared_ptr<inode>>
- {
- if (auto inode_offset = calculate_inode_offset(inode_number, state))
- {
- auto new_inode_data = inode_data{};
- if (auto read_result = state.backing_inode->read(kstd::raw_bytes(new_inode_data), *inode_offset); !read_result)
+ auto const bytes_to_read = std::min(requested_size - bytes_read, block_size - in_block_offset);
+ if (block_number == 0)
{
- return kstd::failure(read_result.error());
+ kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value);
+ bytes_read += bytes_to_read;
}
else
{
- return kstd::make_shared<struct inode>(inode_number, new_inode_data);
- }
- }
- else
- {
- return kstd::failure(inode_offset.error());
- }
- }
+ auto const block_start_offset = block_number.value() * block_size;
+ auto const read_offset = block_start_offset + in_block_offset;
- auto filesystem::write_inode(uint32_t inode_number, inode_data const & data, mount_state & state)
- -> kstd::result<void>
- {
- if (auto inode_offset = calculate_inode_offset(inode_number, state))
- {
- return state.backing_inode->write(kstd::raw_bytes(data), *inode_offset).transform([](auto) {});
- }
- else
- {
- return kstd::failure(inode_offset.error());
- }
- }
+ auto const read_result =
+ state.backing_inode->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset);
+ if (!read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
- auto filesystem::calculate_inode_offset(uint32_t inode_number, mount_state const & state) const
- -> kstd::result<kstd::bytes>
- {
- auto const inodes_per_group = state.superblock.inodes_per_group;
- auto const block_group_index = (inode_number - 1) / inodes_per_group;
- auto const inode_index_within_group = (inode_number - 1) % inodes_per_group;
+ bytes_read += read_result.value();
+ }
- if (block_group_index >= state.block_group_descriptors.size())
- {
- return kstd::failure(ext2_errc::invalid_block_group_index);
+ block_index++;
+ in_block_offset = 0_B;
}
- auto const & block_group_descriptor = state.block_group_descriptors.at(block_group_index);
- auto const inode_table_start_block = block_group_descriptor.inode_table;
- auto const inode_table_offset = inode_table_start_block * block_size(state);
- auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size(state);
-
- return inode_offset;
+ return bytes_read;
}
- auto filesystem::allocate_blocks(size_t count, mount_state & state, write_batch & batch)
- -> kstd::result<kstd::vector<uint32_t>>
+ auto allocate_blocks(size_t count, mount_state & state, write_batch & batch) -> kstd::result<kstd::vector<uint32_t>>
{
auto & [superblock, block_group_descriptors, backing_inode, _] = state;
@@ -654,124 +921,24 @@ namespace kernel::filesystem::ext2
return allocated_blocks;
}
- auto filesystem::data_size(inode const & inode, mount_state const & state) const -> kstd::bytes
- {
- uint64_t size = inode.data().size;
-
- if (revision_level(state) > constants::good_old_revision && inode.is_regular())
- {
- size |= static_cast<uint64_t>(inode.data().dir_acl) << 32;
- }
-
- return kstd::bytes{size};
- }
-
- auto filesystem::set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) const -> void
+ auto update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void
{
- if (revision_level(state) > constants::good_old_revision && inode.is_regular())
- {
- inode.data().dir_acl = static_cast<uint32_t>(new_size.value >> 32);
- }
- inode.data().size = static_cast<uint32_t>(new_size.value);
- }
-
- auto filesystem::do_read(inode const & inode, std::span<std::byte> buffer, kstd::bytes offset,
- mount_state const & state) const -> kstd::result<kstd::bytes>
- {
- auto const max_readable = data_size(inode, state) - offset;
- auto const requested_size = std::min(kstd::bytes{buffer.size()}, max_readable);
-
- auto const block_size = this->block_size(state);
- auto block_index = offset / block_size;
- auto in_block_offset = offset % block_size;
-
- auto bytes_read = 0_B;
-
- while (bytes_read < requested_size)
- {
- auto const block_number = inode_block_number(block_index, inode, state);
- if (!block_number)
- {
- break;
- }
-
- auto const bytes_to_read = std::min(requested_size - bytes_read, block_size - in_block_offset);
- if (block_number == 0)
- {
- kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value);
- bytes_read += bytes_to_read;
- }
- else
- {
- auto const block_start_offset = block_number.value() * block_size;
- auto const read_offset = block_start_offset + in_block_offset;
-
- auto const read_result =
- state.backing_inode->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset);
- if (!read_result)
- {
- return kstd::failure(read_result.error());
- }
-
- bytes_read += read_result.value();
- }
-
- block_index++;
- in_block_offset = 0_B;
- }
-
- return bytes_read;
+ data.blocks += delta * (2 << state.superblock.log_block_size);
}
- auto filesystem::allocate_inode(mount_state & state, write_batch & batch) -> kstd::result<uint32_t>
+ auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result<void>
{
- auto & [superblock, block_group_descriptors, _, __] = state;
-
- if (block_group_descriptors.empty() || superblock.free_inodes_count == 0)
+ if (auto inode_offset = calculate_inode_offset(inode_number, state))
{
- return kstd::failure(ext2_errc::not_enough_inodes);
+ return state.backing_inode->write(kstd::raw_bytes(data), *inode_offset).transform([](auto) {});
}
-
- for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < block_group_descriptors.size();
- ++block_group_descriptor_index)
+ else
{
- auto & block_group_descriptor = block_group_descriptors.at(block_group_descriptor_index);
- if (block_group_descriptor.free_inodes_count == 0)
- {
- continue;
- }
-
- auto inode_bitmap = kstd::vector<std::byte>{block_size(state).value};
- if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap, state); !read_result)
- {
- return kstd::failure(read_result.error());
- }
-
- for (auto i = 0uz; i < static_cast<size_t>(superblock.inodes_per_group); ++i)
- {
- if (!bitmap_is_set(inode_bitmap, i))
- {
- bitmap_set(inode_bitmap, i);
- block_group_descriptor.free_inodes_count--;
- superblock.free_inodes_count--;
-
- if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap, state); !write_result)
- {
- return kstd::failure(write_result.error());
- }
-
- batch.mark_group(block_group_descriptor_index);
-
- return block_group_descriptor_index * superblock.inodes_per_group + i + 1;
- }
- }
+ return kstd::failure(inode_offset.error());
}
-
- return kstd::failure(ext2_errc::not_enough_inodes);
}
- auto filesystem::inode_block_number(size_t index, inode const & inode, mount_state const & state) const
- -> kstd::result<std::size_t>
+ auto inode_block_number(size_t index, inode const & inode, mount_state const & state) -> kstd::result<std::size_t>
{
auto const & block_array = inode.data().block;
@@ -781,7 +948,7 @@ namespace kernel::filesystem::ext2
}
index -= constants::direct_block_count;
- auto const block_size = this->block_size(state);
+ auto const block_size = ext2::block_size(state);
auto const numbers_per_block = block_numbers(1, block_size);
for (auto const & level : indirect_levels(block_size))
{
@@ -829,25 +996,9 @@ namespace kernel::filesystem::ext2
return kstd::failure(ext2_errc::invalid_block_index);
}
- auto filesystem::read_block_number_at_index(uint32_t block_number, size_t index, mount_state const & state) const
- -> kstd::result<uint32_t>
- {
- uint32_t block_number_buffer = 0;
-
- auto const block_start_offset = block_number * block_size(state);
- auto const number_start_address = block_start_offset + index * kstd::size_of<uint32_t>();
- if (auto read_result = state.backing_inode->read(kstd::raw_bytes(block_number_buffer), number_start_address);
- !read_result)
- {
- return kstd::failure(read_result.error());
- }
-
- return block_number_buffer;
- }
-
- auto filesystem::write_global_block_number_to_inode_block_index(size_t inode_block_index, inode_data & data,
- uint32_t global_block_number, mount_state & state,
- write_batch & batch) -> kstd::result<void>
+ auto write_global_block_number_to_inode_block_index(size_t inode_block_index, inode_data & data,
+ uint32_t global_block_number, mount_state & state,
+ write_batch & batch) -> kstd::result<void>
{
if (inode_block_index < constants::direct_block_count)
{
@@ -856,7 +1007,7 @@ namespace kernel::filesystem::ext2
}
inode_block_index -= constants::direct_block_count;
- auto const block_size = this->block_size(state);
+ auto const block_size = ext2::block_size(state);
auto const numbers_per_block = block_numbers(1, block_size);
for (auto const & level : indirect_levels(block_size))
{
@@ -928,8 +1079,8 @@ namespace kernel::filesystem::ext2
return kstd::success();
}
- auto filesystem::write_block_group_descriptor(block_group_descriptor const & block_group_descriptor,
- size_t block_group_descriptor_index, mount_state const & state) const
+ auto write_block_group_descriptor(block_group_descriptor const & block_group_descriptor,
+ size_t block_group_descriptor_index, mount_state const & state)
-> kstd::result<void>
{
// TODO update all block group descriptors
@@ -940,69 +1091,13 @@ namespace kernel::filesystem::ext2
.transform([](auto) {});
}
- auto filesystem::write_superblock(mount_state & state) const -> kstd::result<void>
+ auto write_superblock(mount_state & state) -> kstd::result<void>
{
// TODO update all superblock copies
return state.backing_inode->write(kstd::raw_bytes(state.superblock), constants::superblock_offset)
.transform([](auto) {});
}
- auto filesystem::map_inode_mode_to_file_type(uint16_t mode) -> kapi::filesystem::file_type
- {
- switch (mode & constants::mode_mask)
- {
- case constants::mode_regular:
- return kapi::filesystem::file_type::regular;
- case constants::mode_directory:
- return kapi::filesystem::file_type::directory;
- case constants::mode_block_device:
- return kapi::filesystem::file_type::block_device;
- case constants::mode_character_device:
- return kapi::filesystem::file_type::character_device;
- case constants::mode_symbolic_link:
- return kapi::filesystem::file_type::symbolic_link;
- case constants::mode_fifo:
- return kapi::filesystem::file_type::fifo;
- case constants::mode_socket:
- return kapi::filesystem::file_type::socket;
- default:
- return kapi::filesystem::file_type{0};
- }
- }
-
- auto filesystem::map_vfs_inode_type_into_inode_mode(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t
- {
- return mode | [=] {
- switch (type)
- {
- case kapi::filesystem::file_type::directory:
- return constants::mode_directory;
- case kapi::filesystem::file_type::regular:
- return constants::mode_regular;
- case kapi::filesystem::file_type::block_device:
- return constants::mode_block_device;
- case kapi::filesystem::file_type::character_device:
- return constants::mode_character_device;
- case kapi::filesystem::file_type::symbolic_link:
- return constants::mode_symbolic_link; // TODO implement
- case kapi::filesystem::file_type::fifo:
- return constants::mode_fifo;
- case kapi::filesystem::file_type::socket:
- return constants::mode_socket;
- default:
- kapi::system::panic("[EXT2] Not implemented.");
- }
- }();
- }
-
- 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);
- }
-
- auto filesystem::block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes
- {
- return block_size(state) == 1024_B ? 2 * block_size(state) : block_size(state);
- }
+ //! @}
} // namespace kernel::filesystem::ext2
diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp
index 66db7589..85ce4624 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.hpp
@@ -13,7 +13,6 @@
#include <kapi/filesystem.hpp>
-#include <kstd/bitfield_enum.hpp>
#include <kstd/memory.hpp>
#include <kstd/result.hpp>
#include <kstd/system_error.hpp>
@@ -25,7 +24,6 @@
#include <optional>
#include <span>
#include <string_view>
-#include <type_traits>
namespace kernel::filesystem::ext2
{
@@ -76,203 +74,91 @@ namespace kernel::filesystem::ext2
-> kstd::result<inode_ptr> override;
//! @}
-
- //! @name Filesystem Information Queries
- //! @{
-
- //! Get the size of a block in the filesystem.
- //!
- //! @param state The driver state to operate on.
- //! @return The size of a block in bytes.
- [[nodiscard]] auto block_size(mount_state const & state) const -> kstd::bytes;
-
- //! Get the revision level of the filesystem.
- //!
- //! @param state The driver state to operate on.
- //! @return The revision level.
- [[nodiscard]] auto revision_level(mount_state const & state) const -> uint32_t;
-
- //! Get the size of an inode in the filesystem.
- //!
- //! @param state The driver state to operate on.
- //! @return The size of an inode in bytes.
- [[nodiscard]] auto inode_size(mount_state const & state) const -> kstd::bytes;
-
- //! Get the number of blocks allocated to an inode.
- //!
- //! @param inode The inode whose block count to query.
- //! @param state The driver state to operate on.
- //! @return The number of blocks allocated to the inode.
- [[nodiscard]] auto block_count(inode const & inode, mount_state const & state) const -> uint32_t;
-
- //! @}
-
- //! @name Block I/O
- //! @{
-
- //! Read a block from the backing inode into the provided buffer.
- //!
- //! @param block_number The number of the block to read.
- //! @param buffer The buffer to read the block data into.
- //! @param state The state to operate on.
- //! @return The number of bytes read.
- [[nodiscard]] auto read_block(uint32_t block_number, std::span<std::byte> buffer, mount_state const & state) const
- -> kstd::result<kstd::bytes>;
-
- //! Write a block of data from the provided buffer to the backing inode.
- //!
- //! @param block_number The number of the block to write.
- //! @param buffer The buffer containing the data to write.
- //! @param state The state to operate on.
- //! @return The number of bytes written.
- [[nodiscard]] auto write_block(uint32_t block_number, std::span<std::byte const> buffer, mount_state & state)
- -> kstd::result<kstd::bytes>;
-
- //! @}
-
- //! Allocate a specified number of blocks.
- //!
- //! @param count The number of blocks to allocate.
- //! @param state The state to operate on.
- //! @param batch The active write batch.
- //! @return A vector of the allocated block numbers.
- auto allocate_blocks(size_t count, mount_state & state, write_batch & batch)
- -> kstd::result<kstd::vector<uint32_t>>;
-
- //! Update the number of blocks allocated to an inode.
- //!
- //! @param data The inode data.
- //! @param state The state to operate on.
- //! @param delta The change in the number of blocks.
- auto update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void;
-
- //! Write an inode to the backing inode.
- //!
- //! @param inode_number The number of the inode to write.
- //! @param state The state to operate on.
- //! @param data The inode data to write.
- auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result<void>;
-
- //! Get the block number associated with the nth block of an inode.
- //!
- //! @param index The index of the block within the inode.
- //! @param inode The inode.
- //! @param state The state to operate on.
- //! @return The global block number on success, an error otherwise.
- [[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.
- //!
- //! @param block_index The index of the block within the inode.
- //! @param data The inode data.
- //! @param global_block_number The global block number to write.
- //! @param state The state to operate on.
- //! @param batch The active write batch.
- auto write_global_block_number_to_inode_block_index(size_t block_index, inode_data & data,
- uint32_t global_block_number, mount_state & state,
- write_batch & batch) -> kstd::result<void>;
-
- private:
- friend write_batch;
- friend inode;
- friend directory_iterator;
-
- //! Perform the actual read of the requested data.
- //!
- //! @param inode The inode whose data to read.
- //! @param buffer The buffer to read into.
- //! @param offset The offset inside the inode's data to start at.
- //! @param state The driver state to operate on.
- //! @return The number of bytes read on success, an error otherwise.
- [[nodiscard]] auto do_read(inode const & inode, std::span<std::byte> buffer, kstd::bytes offset,
- mount_state const & state) const -> kstd::result<kstd::bytes>;
-
- //! Determine the size of an inode's data on disk.
- //!
- //! @param inode The inode whose data size to determine.
- //! @param state The driver state to operate on.
- //! @return The size of the data referenced by the inode.
- [[nodiscard]] auto data_size(inode const & inode, mount_state const & state) const -> kstd::bytes;
-
- //! Set the size of an inode's data on disk.
- //!
- //! @param inode The inode whose data size to set.
- //! @param new_size The size to set.
- //! @param state The driver state to operate on.
- auto set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) const -> void;
-
- //! Allocate a single inode in the file system.
- //!
- //! @param state The driver state to operate on.
- //! @param batch The active write batch.
- //! @return An inode number on success, an error otherwise.
- auto allocate_inode(mount_state & state, write_batch & batch) -> kstd::result<uint32_t>;
-
- //! Add a new directory entry to a given directory.
- //!
- //! @param directory The directory to add the entry to.
- //! @param name The name for the entry.
- //! @param child The inode number of the child.
- //! @param mode The file mode of the entry.
- //! @param state The driver state to operate on.
- //! @param batch The active write batch.
- //! @return Nothing on success, an error code otherwise.
- auto add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode,
- mount_state & state, write_batch & batch) -> kstd::result<void>;
-
- //! Initialize a new directory inode.
- //!
- //! This function initializes an inode to be an empty directory. On success, the inode will be a directory with only
- //! two children, "." and "..".
- //!
- //! @param directory The inode to initialize.
- //! @param parent The parent of this newly initialized directory.
- //! @param state The driver state to operate on.
- //! @param batch The active write batch.
- //! @return Nothing on success, an error otherwise.
- auto init_directory(inode & directory, inode & parent, mount_state & state, write_batch & batch)
- -> kstd::result<void>;
-
- //! Write a new directory entry into the given buffer.
- //!
- //! @param buffer The buffer to write to.
- //! @param offset The offset inside to the buffer.
- //! @param target The inode the entry targets.
- //! @param name The name for the entry.
- //! @param type The filet type of the entry.
- //! @return A pointer to the written entry on success, an error otherwise.
- auto write_directory_entry_to_buffer(std::span<std::byte> buffer, kstd::bytes offset, inode & target,
- std::string_view name, kapi::filesystem::file_type type)
- -> kstd::result<linked_directory_entry *>;
-
- [[nodiscard]] auto calculate_inode_offset(uint32_t inode_number, mount_state const & state) const
- -> kstd::result<kstd::bytes>;
- [[nodiscard]] auto read_inode(uint32_t inode_number, mount_state const & state) const
- -> kstd::result<kstd::shared_ptr<inode>>;
- [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index, mount_state const & state) const
- -> kstd::result<uint32_t>;
-
- [[nodiscard]] auto block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes;
-
- [[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>;
- [[nodiscard]] auto write_superblock(mount_state & state) const -> kstd::result<void>;
-
- auto map_inode_mode_to_file_type(uint16_t mode) -> kapi::filesystem::file_type;
- auto map_vfs_inode_type_into_inode_mode(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t;
};
-} // namespace kernel::filesystem::ext2
-template<>
-struct kstd::is_bitfield_enum<kernel::filesystem::ext2::incompatible_features> : std::true_type
-{
-};
-
-template<>
-struct kstd::is_bitfield_enum<kernel::filesystem::ext2::read_only_compatible_features> : std::true_type
-{
-};
+ //! Get the size of a block in the filesystem.
+ //!
+ //! @param state The driver state to operate on.
+ //! @return The size of a block in bytes.
+ [[nodiscard]] auto block_size(mount_state const & state) -> kstd::bytes;
+
+ //! Get the number of blocks allocated to an inode.
+ //!
+ //! @param inode The inode whose block count to query.
+ //! @param state The driver state to operate on.
+ //! @return The number of blocks allocated to the inode.
+ [[nodiscard]] auto block_count(inode const & inode, mount_state const & state) -> uint32_t;
+
+ //! Determine the size of an inode's data on disk.
+ //!
+ //! @param inode The inode whose data size to determine.
+ //! @param state The driver state to operate on.
+ //! @return The size of the data referenced by the inode.
+ [[nodiscard]] auto data_size(inode const & inode, mount_state const & state) -> kstd::bytes;
+
+ //! Set the size of an inode's data on disk.
+ //!
+ //! @param inode The inode whose data size to set.
+ //! @param new_size The size to set.
+ //! @param state The driver state to operate on.
+ auto set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) -> void;
+
+ //! Perform the actual read of the requested data.
+ //!
+ //! @param inode The inode whose data to read.
+ //! @param buffer The buffer to read into.
+ //! @param offset The offset inside the inode's data to start at.
+ //! @param state The driver state to operate on.
+ //! @return The number of bytes read on success, an error otherwise.
+ [[nodiscard]] auto do_read(inode const & inode, std::span<std::byte> buffer, kstd::bytes offset,
+ mount_state const & state) -> kstd::result<kstd::bytes>;
+
+ //! Allocate a specified number of blocks.
+ //!
+ //! @param count The number of blocks to allocate.
+ //! @param state The state to operate on.
+ //! @param batch The active write batch.
+ //! @return A vector of the allocated block numbers.
+ auto allocate_blocks(size_t count, mount_state & state, write_batch & batch) -> kstd::result<kstd::vector<uint32_t>>;
+
+ //! Update the number of blocks allocated to an inode.
+ //!
+ //! @param data The inode data.
+ //! @param state The state to operate on.
+ //! @param delta The change in the number of blocks.
+ auto update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void;
+
+ //! Write an inode to the backing inode.
+ //!
+ //! @param inode_number The number of the inode to write.
+ //! @param state The state to operate on.
+ //! @param data The inode data to write.
+ auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result<void>;
+
+ //! Get the block number associated with the nth block of an inode.
+ //!
+ //! @param index The index of the block within the inode.
+ //! @param inode The inode.
+ //! @param state The state to operate on.
+ //! @return The global block number on success, an error otherwise.
+ [[nodiscard]] auto inode_block_number(size_t index, inode const & inode, mount_state const & state)
+ -> kstd::result<std::size_t>;
+
+ //! Write a global block number to an inode block index.
+ //!
+ //! @param block_index The index of the block within the inode.
+ //! @param data The inode data.
+ //! @param global_block_number The global block number to write.
+ //! @param state The state to operate on.
+ //! @param batch The active write batch.
+ auto write_global_block_number_to_inode_block_index(size_t block_index, inode_data & data,
+ uint32_t global_block_number, mount_state & state,
+ write_batch & batch) -> kstd::result<void>;
+
+ [[nodiscard]] auto write_block_group_descriptor(block_group_descriptor const & block_group_descriptor,
+ size_t block_group_descriptor_index, mount_state const & state)
+ -> kstd::result<void>;
+ [[nodiscard]] auto write_superblock(mount_state & state) -> kstd::result<void>;
+} // namespace kernel::filesystem::ext2
#endif
diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
index 28aabed7..8565db4d 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
@@ -241,16 +241,16 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
{
- 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);
+ REQUIRE(inode_block_number(0, inode, *mount_state) == 7);
+ REQUIRE(inode_block_number(singly_start, inode, *mount_state) == 31);
+ REQUIRE(inode_block_number(doubly_start, inode, *mount_state) == 42);
+ REQUIRE(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->inode_block_number(beyond_triply, inode, *mount_state));
+ REQUIRE(!inode_block_number(beyond_triply, inode, *mount_state));
}
}
}
@@ -314,32 +314,32 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
constexpr auto doubly_global_block_number = 303;
constexpr auto triply_global_block_number = 404;
- auto batch = kernel::filesystem::ext2::write_batch{*fs, *mount_state};
+ auto batch = kernel::filesystem::ext2::write_batch{*mount_state};
- REQUIRE(fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number,
- *mount_state, batch));
+ REQUIRE(write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number, *mount_state,
+ batch));
REQUIRE(inode_data.block[0] == direct_global_block_number);
- REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number,
- *mount_state, batch));
+ REQUIRE(write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number,
+ *mount_state, batch));
REQUIRE(inode_data.block[12] == 16);
REQUIRE(read_u32(static_cast<kstd::bytes>(inode_data.block[12]) * block_size.value) ==
singly_global_block_number);
- REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start + 1, inode_data,
- singly_global_block_number + 1, *mount_state, batch));
+ REQUIRE(write_global_block_number_to_inode_block_index(singly_start + 1, inode_data,
+ singly_global_block_number + 1, *mount_state, batch));
REQUIRE(read_u32(static_cast<kstd::bytes>(inode_data.block[12]) * block_size.value +
1 * kstd::size_of<uint32_t>()) == singly_global_block_number + 1);
- REQUIRE(fs->write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number,
- *mount_state, batch));
+ REQUIRE(write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number,
+ *mount_state, batch));
REQUIRE(inode_data.block[13] == 17);
auto const doubly_leaf_table = read_u32(static_cast<size_t>(inode_data.block[13]) * block_size);
REQUIRE(doubly_leaf_table == 18);
REQUIRE(read_u32(static_cast<size_t>(doubly_leaf_table) * block_size) == doubly_global_block_number);
- REQUIRE(fs->write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number,
- *mount_state, batch));
+ REQUIRE(write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number,
+ *mount_state, batch));
REQUIRE(inode_data.block[14] == 19);
auto const triply_middle_table = read_u32(static_cast<size_t>(inode_data.block[14]) * block_size);
REQUIRE(triply_middle_table == 20);
@@ -349,10 +349,10 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
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);
+ REQUIRE(inode_block_number(0, inode, *mount_state) == direct_global_block_number);
+ REQUIRE(inode_block_number(singly_start, inode, *mount_state) == singly_global_block_number);
+ REQUIRE(inode_block_number(doubly_start, inode, *mount_state) == doubly_global_block_number);
+ REQUIRE(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 075d6c5f..aa0c6368 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -43,12 +43,6 @@ namespace kernel::filesystem::ext2
return requested_size;
}
- auto filesystem = get_filesystem();
- if (!filesystem)
- {
- return kstd::failure(filesystem.error());
- }
-
auto state = get_driver_data();
if (!state)
{
@@ -62,7 +56,7 @@ namespace kernel::filesystem::ext2
}
auto guard = kstd::lock_guard{(*state)->lock};
- return (*filesystem)->do_read(*this, buffer, offset, **state);
+ return ext2::do_read(*this, buffer, offset, **state);
}
auto inode::write(std::span<std::byte const> buffer, kstd::bytes offset) -> kstd::result<kstd::bytes>
@@ -75,12 +69,6 @@ namespace kernel::filesystem::ext2
// TODO check maximum file size of filesystem
// TODO handle sparse files
- auto filesystem = get_filesystem();
- if (!filesystem)
- {
- return kstd::failure(filesystem.error());
- }
-
auto state = get_driver_data();
if (!state)
{
@@ -94,12 +82,12 @@ namespace kernel::filesystem::ext2
}
auto guard = kstd::lock_guard{(*state)->lock};
- auto batch = write_batch{**filesystem, **state};
+ auto batch = write_batch{**state};
- auto const new_inode_size = std::max((*filesystem)->data_size(*this, **state), offset + kstd::bytes{buffer.size()});
+ auto const new_inode_size = std::max(ext2::data_size(*this, **state), offset + kstd::bytes{buffer.size()});
- auto block_size = (*filesystem)->block_size(**state);
- auto const current_block_count = (*filesystem)->block_count(*this, **state);
+ auto block_size = ext2::block_size(**state);
+ auto const current_block_count = ext2::block_count(*this, **state);
auto const max_new_inode_size_without_new_blocks = current_block_count * block_size;
if (new_inode_size > max_new_inode_size_without_new_blocks)
@@ -120,7 +108,7 @@ namespace kernel::filesystem::ext2
while (bytes_written < kstd::bytes{buffer.size()})
{
- auto const block_number = (*filesystem)->inode_block_number(block_index, *this, **state);
+ auto const block_number = ext2::inode_block_number(block_index, *this, **state);
// TODO BA-FS26 if blocknumber == 0 --> handle sparse file
if (!block_number)
{
@@ -145,8 +133,7 @@ namespace kernel::filesystem::ext2
in_block_offset = 0_B;
}
- (*filesystem)
- ->set_data_size(*this, std::max((*filesystem)->data_size(*this, **state), offset + bytes_written), **state);
+ ext2::set_data_size(*this, std::max(ext2::data_size(*this, **state), offset + bytes_written), **state);
batch.mark_inode(*this);
return bytes_written;
}
@@ -209,19 +196,13 @@ namespace kernel::filesystem::ext2
auto inode::append_blocks(size_t count, write_batch & batch) -> bool
{
- auto filesystem = get_filesystem();
- if (!filesystem)
- {
- return false;
- }
-
auto state = get_driver_data();
if (!state)
{
return false;
}
- auto new_blocks = (*filesystem)->allocate_blocks(count, **state, batch);
+ auto new_blocks = ext2::allocate_blocks(count, **state, batch);
if (!new_blocks)
{
return false;
@@ -229,11 +210,10 @@ namespace kernel::filesystem::ext2
for (auto i = 0uz; i < new_blocks->size(); ++i)
{
- auto const block_index = (*filesystem)->block_count(*this, **state) + i;
+ auto const block_index = ext2::block_count(*this, **state) + i;
auto const global_block_number = new_blocks->at(i);
- if (auto write_result = (*filesystem)
- ->write_global_block_number_to_inode_block_index(block_index, m_data,
+ if (auto write_result = ext2::write_global_block_number_to_inode_block_index(block_index, m_data,
global_block_number, **state, batch);
!write_result)
{
@@ -241,18 +221,12 @@ namespace kernel::filesystem::ext2
}
}
- (*filesystem)->update_inode_block_count(m_data, count, **state);
+ ext2::update_inode_block_count(m_data, count, **state);
return true;
}
auto inode::set_size(kstd::bytes new_size) -> void
{
- auto filesystem = get_filesystem();
- if (!filesystem)
- {
- return;
- }
-
auto driver_data = get_driver_data();
if (!driver_data)
{
@@ -261,7 +235,7 @@ namespace kernel::filesystem::ext2
auto state = static_pointer_cast<mount_state>(*driver_data);
auto guard = kstd::lock_guard{state->lock};
- return (*filesystem)->set_data_size(*this, new_size, *state);
+ return ext2::set_data_size(*this, new_size, *state);
}
[[nodiscard]] auto inode::data() -> inode_data &
@@ -276,12 +250,6 @@ namespace kernel::filesystem::ext2
auto inode::size() const -> kstd::bytes
{
- auto filesystem = get_filesystem();
- if (!filesystem)
- {
- return 0_B;
- }
-
auto state = get_driver_data();
if (!state)
{
@@ -289,7 +257,7 @@ namespace kernel::filesystem::ext2
}
auto guard = kstd::lock_guard{(*state)->lock};
- return (*filesystem)->data_size(*this, **state);
+ return ext2::data_size(*this, **state);
}
[[nodiscard]] auto inode::number() const -> uint32_t
@@ -297,26 +265,6 @@ namespace kernel::filesystem::ext2
return m_inode_number;
}
- auto inode::get_filesystem() -> kstd::result<kstd::shared_ptr<filesystem>>
- {
- if (auto mount = owning_mount().lock())
- {
- return static_pointer_cast<filesystem>(mount->filesystem());
- }
-
- return kstd::failure(vfs_errc::not_mounted);
- }
-
- auto inode::get_filesystem() const -> kstd::result<kstd::shared_ptr<filesystem const>>
- {
- if (auto mount = owning_mount().lock())
- {
- return static_pointer_cast<filesystem>(mount->filesystem());
- }
-
- return kstd::failure(vfs_errc::not_mounted);
- }
-
auto inode::get_driver_data() -> kstd::result<kstd::shared_ptr<mount_state>>
{
if (auto mount = owning_mount().lock())
diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp
index 5393a853..b506be55 100644
--- a/kernel/kernel/filesystem/ext2/inode.hpp
+++ b/kernel/kernel/filesystem/ext2/inode.hpp
@@ -134,16 +134,6 @@ namespace kernel::filesystem::ext2
//! @}
private:
- //! Get the filesystem driver associated with this inode.
- //!
- //! @return The filesystem driver on success, and error otherwise.
- [[nodiscard]] auto get_filesystem() -> kstd::result<kstd::shared_ptr<filesystem>>;
-
- //! Get the filesystem driver associated with this inode.
- //!
- //! @return The filesystem driver on success, and error otherwise.
- [[nodiscard]] auto get_filesystem() const -> kstd::result<kstd::shared_ptr<filesystem const>>;
-
//! Get the filesystem driver data associated with this inode.
//!
//! @return The filesystem driver data on success, and error otherwise.
diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp
index eab0aabd..bf5d9ab7 100644
--- a/kernel/kernel/filesystem/ext2/inode.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp
@@ -358,8 +358,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
{
auto inode = static_pointer_cast<kernel::filesystem::ext2::inode>(file.value());
- auto const block_size = fs->block_size(*mount_state);
- auto const expected_allocated_blocks = 32 * fs->block_count(*inode, *mount_state);
+ auto const block_size = kernel::filesystem::ext2::block_size(*mount_state);
+ auto const expected_allocated_blocks = 32 * block_count(*inode, *mount_state);
auto write_buffer = kstd::vector<std::byte>(block_size.value * expected_allocated_blocks, std::byte{'A'});
@@ -372,7 +372,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
REQUIRE(std::ranges::all_of(read_buffer, [](std::byte c) { return c == std::byte{'A'}; }));
REQUIRE(inode->size().value == write_buffer.size());
- REQUIRE(fs->block_count(*inode, *mount_state) == expected_allocated_blocks);
+ REQUIRE(block_count(*inode, *mount_state) == expected_allocated_blocks);
}
THEN("writing to a an inode of type directory panics")
@@ -431,8 +431,8 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
inode_data.mode = kernel::filesystem::ext2::constants::mode_regular;
uint32_t inode_number = 3;
- auto const inode_data_offset =
- block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs->inode_size(*mount_state);
+ auto const inode_data_offset = block_group_descriptor.inode_table * block_size +
+ kstd::bytes{(inode_number - 1) * mount_state->superblock.inode_size};
auto inode = kernel::filesystem::ext2::inode{inode_number, inode_data};
inode.set_owning_mount(*mount);
diff --git a/kernel/kernel/filesystem/ext2/superblock.hpp b/kernel/kernel/filesystem/ext2/superblock.hpp
index e5cd845b..dce3cb29 100644
--- a/kernel/kernel/filesystem/ext2/superblock.hpp
+++ b/kernel/kernel/filesystem/ext2/superblock.hpp
@@ -1,8 +1,11 @@
#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_SUPERBLOCK_HPP
#define TEACHOS_KERNEL_FILESYSTEM_EXT2_SUPERBLOCK_HPP
+#include <kstd/bitfield_enum.hpp>
+
#include <array>
#include <cstdint>
+#include <type_traits>
namespace kernel::filesystem::ext2
{
@@ -105,4 +108,15 @@ namespace kernel::filesystem::ext2
std::array<uint8_t, 760> unused; // NOLINT(readability-magic-numbers)
};
} // namespace kernel::filesystem::ext2
+
+template<>
+struct kstd::is_bitfield_enum<kernel::filesystem::ext2::incompatible_features> : std::true_type
+{
+};
+
+template<>
+struct kstd::is_bitfield_enum<kernel::filesystem::ext2::read_only_compatible_features> : std::true_type
+{
+};
+
#endif \ No newline at end of file
diff --git a/kernel/kernel/filesystem/ext2/write_batch.cpp b/kernel/kernel/filesystem/ext2/write_batch.cpp
index e8663d21..3ea6ef19 100644
--- a/kernel/kernel/filesystem/ext2/write_batch.cpp
+++ b/kernel/kernel/filesystem/ext2/write_batch.cpp
@@ -13,16 +13,15 @@
namespace kernel::filesystem::ext2
{
- write_batch::write_batch(filesystem & filesystem, mount_state & state)
- : m_filesystem{filesystem}
- , m_state{state}
+ write_batch::write_batch(mount_state & state)
+ : m_state{state}
{}
write_batch::~write_batch()
{
std::ranges::for_each(m_dirty_groups, [this](auto index) {
auto & descriptor = m_state.block_group_descriptors.at(index);
- auto result = m_filesystem.write_block_group_descriptor(descriptor, index, m_state);
+ auto result = ext2::write_block_group_descriptor(descriptor, index, m_state);
if (!result)
{
@@ -32,7 +31,7 @@ namespace kernel::filesystem::ext2
if (!m_dirty_groups.empty())
{
- auto result = m_filesystem.write_superblock(m_state);
+ auto result = ext2::write_superblock(m_state);
if (!result)
{
kapi::system::panic("[FS:ext2] failed to write superblock", result.error());
@@ -40,7 +39,7 @@ namespace kernel::filesystem::ext2
}
std::ranges::for_each(m_dirty_inodes, [this](auto inode) {
- auto result = m_filesystem.write_inode(inode->number(), inode->data(), m_state);
+ auto result = ext2::write_inode(inode->number(), inode->data(), m_state);
if (!result)
{
kapi::system::panic("[FS:ext2] failed to write inode", result.error());
diff --git a/kernel/kernel/filesystem/ext2/write_batch.hpp b/kernel/kernel/filesystem/ext2/write_batch.hpp
index f4000391..110d089c 100644
--- a/kernel/kernel/filesystem/ext2/write_batch.hpp
+++ b/kernel/kernel/filesystem/ext2/write_batch.hpp
@@ -19,9 +19,8 @@ namespace kernel::filesystem::ext2
{
//! Construct a new write batch for the given filesystem and mount state.
//!
- //! @param filesystem The filesystem driver to use for writes.
//! @param state The driver state to operate on.
- write_batch(filesystem & filesystem, mount_state & state);
+ explicit write_batch(mount_state & state);
write_batch(write_batch const &) = delete;
write_batch(write_batch &&) = delete;
@@ -42,7 +41,6 @@ namespace kernel::filesystem::ext2
auto mark_inode(inode & inode) -> void;
private:
- filesystem & m_filesystem;
mount_state & m_state;
kstd::vector<std::size_t> m_dirty_groups{};
kstd::vector<inode *> m_dirty_inodes{};