aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.cpp308
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.hpp72
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.tests.cpp47
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp108
-rw-r--r--kernel/kernel/filesystem/ext2/inode.hpp4
-rw-r--r--kernel/kernel/filesystem/ext2/inode.tests.cpp14
-rw-r--r--kernel/kernel/filesystem/ext2/mount_state.hpp6
7 files changed, 340 insertions, 219 deletions
diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp
index 9275f5a9..ef81f6ac 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.cpp
@@ -97,44 +97,48 @@ namespace kernel::filesystem::ext2
[[gnu::used]]
constexpr auto registration = type_registration<type>{};
- auto filesystem::indirect_levels() const -> std::array<indirect_level, 3>
+ static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem));
+
+ 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()},
- {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block()},
- {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block()}}
+ {{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::mount(inode_ptr const & backing_inode) -> kstd::result<mount_result>
{
- m_backing_inode = backing_inode;
+ auto mount_state = kstd::make_shared<struct mount_state>();
+ auto & [superblock, block_group_descriptors, backing] = *mount_state;
- if (auto read_result =
- m_backing_inode->read(std::as_writable_bytes(std::span{&m_superblock, 1}), constants::superblock_offset);
- !read_result)
+ backing = backing_inode;
+
+ auto superblock_bytes = std::as_writable_bytes(std::span{&superblock, 1});
+ if (auto read_result = backing->read(superblock_bytes, constants::superblock_offset); !read_result)
{
return kstd::failure(read_result.error());
}
- if (m_superblock.magic != constants::magic_number)
+ if (superblock.magic != constants::magic_number)
{
return kstd::failure(ext2_errc::invalid_magic_number);
}
- auto const blocks_per_group = m_superblock.blocks_per_group;
- auto const num_block_groups = (m_superblock.blocks_count + blocks_per_group - 1) / blocks_per_group;
+ auto const blocks_per_group = superblock.blocks_per_group;
+ auto const num_block_groups = (superblock.blocks_count + blocks_per_group - 1) / blocks_per_group;
- m_block_group_descriptors = kstd::vector<block_group_descriptor>(num_block_groups);
-
- if (auto read_result = m_backing_inode->read(std::as_writable_bytes(std::span{m_block_group_descriptors}),
- block_group_descriptor_table_offset());
+ block_group_descriptors = kstd::vector<block_group_descriptor>(num_block_groups);
+ auto block_group_descriptors_bytes = std::as_writable_bytes(std::span{block_group_descriptors});
+ if (auto read_result =
+ backing->read(block_group_descriptors_bytes, block_group_descriptor_table_offset(*mount_state));
!read_result)
{
return kstd::failure(read_result.error());
}
- auto root = read_inode(constants::root_inode_number);
+ auto root = read_inode(constants::root_inode_number, *mount_state);
if (!root)
{
@@ -146,8 +150,7 @@ namespace kernel::filesystem::ext2
return kstd::failure(ext2_errc::invalid_root_inode);
}
- return mount_result{*root,
- kstd::make_shared<mount_state>(m_superblock, m_block_group_descriptors, m_backing_inode)};
+ return mount_result{*root, mount_state};
}
auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const
@@ -171,17 +174,17 @@ namespace kernel::filesystem::ext2
auto * ext2_parent = static_cast<inode *>(parent.get());
auto const & inode_data = ext2_parent->data();
- kstd::vector<uint8_t> buffer(block_size().value);
+ kstd::vector<uint8_t> buffer(block_size(*mount_state).value);
- for (uint32_t i = 0; i < inode_block_count(inode_data); ++i)
+ for (uint32_t i = 0; i < inode_block_count(inode_data, *mount_state); ++i)
{
- auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data);
+ auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data, *mount_state);
if (!global_block_number)
{
return kstd::failure(global_block_number.error());
}
- if (auto read_result = read_block(*global_block_number, buffer.data()); !read_result)
+ if (auto read_result = read_block(*global_block_number, buffer.data(), *mount_state); !read_result)
{
return kstd::failure(read_result.error());
}
@@ -189,12 +192,12 @@ namespace kernel::filesystem::ext2
auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data());
auto bytes_read = 0_B;
- while (bytes_read < block_size() && entry->inode != 0)
+ while (bytes_read < block_size(*mount_state) && entry->inode != 0)
{
auto const entry_name = std::string_view{entry->name.data(), entry->name_len};
if (entry_name == name)
{
- return read_inode(entry->inode);
+ return read_inode(entry->inode, *mount_state);
}
bytes_read += kstd::bytes{entry->rec_len};
@@ -237,7 +240,7 @@ namespace kernel::filesystem::ext2
return kstd::failure(vfs_errc::invalid_driver_data);
}
- auto maybe_inode_number = allocate_inode();
+ auto maybe_inode_number = allocate_inode(*mount_state);
if (!maybe_inode_number)
{
return kstd::failure(maybe_inode_number.error());
@@ -263,7 +266,7 @@ namespace kernel::filesystem::ext2
// TODO preallocate blocks depending on type and m_superblock.prealloc_dir_blocks or m_superblock.prealloc_blocks;
- if (auto result = add_directory_entry(ext2_parent, name, inode_number, new_inode_data.mode); !result)
+ if (auto result = add_directory_entry(ext2_parent, name, inode_number, new_inode_data.mode, *mount_state); !result)
{
return kstd::failure(result.error());
}
@@ -274,13 +277,13 @@ namespace kernel::filesystem::ext2
if (new_inode->is_directory())
{
// TODO increment used_dirs_count in block group descriptor
- if (auto result = init_directory(new_inode, ext2_parent); !result)
+ if (auto result = init_directory(new_inode, ext2_parent, *mount_state); !result)
{
return kstd::failure(result.error());
}
}
- if (auto write_result = write_inode(inode_number, new_inode->data()); !write_result)
+ if (auto write_result = write_inode(inode_number, new_inode->data(), *mount_state); !write_result)
{
return kstd::failure(write_result.error());
}
@@ -289,18 +292,19 @@ namespace kernel::filesystem::ext2
}
auto filesystem::add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number,
- [[maybe_unused]] uint16_t mode) -> kstd::result<void>
+ [[maybe_unused]] uint16_t mode, mount_state & state) -> kstd::result<void>
{
- auto const last_block_index = inode_block_count(ext2_parent->data()) - 1;
- auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, ext2_parent->data());
+ auto const last_block_index = inode_block_count(ext2_parent->data(), state) - 1;
+ auto const global_block =
+ map_inode_block_index_to_global_block_number(last_block_index, ext2_parent->data(), state);
if (!global_block)
{
return kstd::failure(global_block.error());
}
- kstd::vector<uint8_t> buffer(block_size().value);
- if (auto read_result = read_block(*global_block, buffer.data()); !read_result)
+ kstd::vector<uint8_t> buffer(block_size(state).value);
+ if (auto read_result = read_block(*global_block, buffer.data(), state); !read_result)
{
return kstd::failure(read_result.error());
}
@@ -311,7 +315,7 @@ namespace kernel::filesystem::ext2
while (true)
{
auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + offset);
- if (offset + kstd::bytes{entry->rec_len} >= block_size())
+ if (offset + kstd::bytes{entry->rec_len} >= block_size(state))
{
break;
}
@@ -329,8 +333,8 @@ namespace kernel::filesystem::ext2
{
last_entry->rec_len = last_entry_actual_len.value;
write_directory_entry_to_buffer(buffer.data(), offset + last_entry_actual_len, child_inode_number, name,
- file_type);
- return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data()); })
+ file_type, state);
+ return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data(), state); })
.transform([](auto) {});
}
else
@@ -340,79 +344,82 @@ namespace kernel::filesystem::ext2
return kstd::failure(ext2_errc::not_enough_free_blocks);
}
- auto const new_block_index = inode_block_count(ext2_parent->data()) - 1;
- auto const new_global_block = map_inode_block_index_to_global_block_number(new_block_index, ext2_parent->data());
+ auto const new_block_index = inode_block_count(ext2_parent->data(), state) - 1;
+ auto const new_global_block =
+ map_inode_block_index_to_global_block_number(new_block_index, ext2_parent->data(), state);
if (!new_global_block)
{
return kstd::failure(new_global_block.error());
}
- kstd::libc::memset(buffer.data(), 0, block_size().value);
- write_directory_entry_to_buffer(buffer.data(), 0_B, child_inode_number, name, file_type);
- if (auto update_result =
- new_global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data()); });
+ kstd::libc::memset(buffer.data(), 0, block_size(state).value);
+ write_directory_entry_to_buffer(buffer.data(), 0_B, child_inode_number, name, file_type, state);
+ if (auto update_result = new_global_block.and_then(
+ [&](auto block_number) { return write_block(block_number, buffer.data(), state); });
!update_result)
{
return kstd::failure(update_result.error());
}
}
- ext2_parent->data_mutable().size = (inode_block_count(ext2_parent->data()) * block_size()).value;
- return write_inode(ext2_parent->number(), ext2_parent->data());
+ ext2_parent->data_mutable().size = (inode_block_count(ext2_parent->data(), state) * block_size(state)).value;
+ return write_inode(ext2_parent->number(), ext2_parent->data(), state);
}
auto filesystem::init_directory(kstd::shared_ptr<kernel::filesystem::ext2::inode> const & new_inode,
- kernel::filesystem::ext2::inode * parent_inode) -> kstd::result<void>
+ kernel::filesystem::ext2::inode * parent_inode, mount_state & state)
+ -> kstd::result<void>
{
if (!new_inode->append_blocks(1))
{
return kstd::failure(ext2_errc::not_enough_free_blocks);
}
- auto const global_block = map_inode_block_index_to_global_block_number(0, new_inode->data());
+ auto const global_block = map_inode_block_index_to_global_block_number(0, new_inode->data(), state);
if (!global_block)
{
return kstd::failure(global_block.error());
}
- kstd::vector<uint8_t> buffer(block_size().value, 0);
- write_directory_entry_to_buffer(buffer.data(), 0_B, new_inode->number(), ".", 2);
+ kstd::vector<uint8_t> buffer(block_size(state).value, 0);
+ write_directory_entry_to_buffer(buffer.data(), 0_B, new_inode->number(), ".", 2, state);
auto const dot_actual_len = static_cast<kstd::bytes>((8u + 1 + 3u) & ~3u);
auto * entry = reinterpret_cast<linked_directory_entry *>(buffer.data());
entry->rec_len = dot_actual_len.value;
- write_directory_entry_to_buffer(buffer.data(), dot_actual_len, parent_inode->number(), "..", 2);
+ write_directory_entry_to_buffer(buffer.data(), dot_actual_len, parent_inode->number(), "..", 2, state);
// '..' inside the new dir counts as an extra hard link to the parent
auto & parent_inode_data = parent_inode->data_mutable();
parent_inode_data.links_count++;
- return write_inode(parent_inode->number(), parent_inode_data)
+ return write_inode(parent_inode->number(), parent_inode_data, state)
.and_then([&]() { return global_block; })
- .and_then([&](auto block_number) { return write_block(block_number, buffer.data()); })
+ .and_then([&](auto block_number) { return write_block(block_number, buffer.data(), state); })
.transform([](auto) {});
}
auto filesystem::write_directory_entry_to_buffer(uint8_t * block_buffer, kstd::bytes offset,
uint32_t child_inode_number, std::string_view name,
- uint8_t file_type) -> void
+ uint8_t file_type, mount_state & state) -> void
{
auto const name_len = static_cast<uint8_t>(name.size());
auto * entry = reinterpret_cast<linked_directory_entry *>(block_buffer + offset);
entry->inode = child_inode_number;
- entry->rec_len = static_cast<uint16_t>(block_size() - offset);
+ entry->rec_len = static_cast<uint16_t>(block_size(state) - offset);
entry->name_len = name_len;
entry->file_type = file_type;
kstd::libc::memcpy(entry->name.data(), name.data(), name_len);
}
- auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>
+ 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))
+ if (auto inode_offset = calculate_inode_offset(inode_number, state))
{
auto new_inode_data = inode_data{};
- if (auto read_result = m_backing_inode->read(as_writable_bytes(std::span{&new_inode_data, 1}), *inode_offset);
+ if (auto read_result = state.backing_inode->read(as_writable_bytes(std::span{&new_inode_data, 1}), *inode_offset);
!read_result)
{
return kstd::failure(read_result.error());
@@ -428,11 +435,12 @@ namespace kernel::filesystem::ext2
}
}
- auto filesystem::write_inode(uint32_t inode_number, inode_data const & data) -> kstd::result<void>
+ 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))
+ if (auto inode_offset = calculate_inode_offset(inode_number, state))
{
- return m_backing_inode->write(as_bytes(std::span{&data, 1}), *inode_offset).transform([](auto) {});
+ return state.backing_inode->write(as_bytes(std::span{&data, 1}), *inode_offset).transform([](auto) {});
}
else
{
@@ -440,51 +448,54 @@ namespace kernel::filesystem::ext2
}
}
- auto filesystem::calculate_inode_offset(uint32_t inode_number) const -> kstd::result<kstd::bytes>
+ auto filesystem::calculate_inode_offset(uint32_t inode_number, mount_state const & state) const
+ -> kstd::result<kstd::bytes>
{
- auto const inodes_per_group = m_superblock.inodes_per_group;
+ 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;
- if (block_group_index >= m_block_group_descriptors.size())
+ if (block_group_index >= state.block_group_descriptors.size())
{
return kstd::failure(ext2_errc::invalid_block_group_index);
}
- auto const & block_group_descriptor = m_block_group_descriptors.at(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();
- auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size();
+ 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;
}
- auto filesystem::allocate_blocks(size_t count) -> kstd::result<kstd::vector<uint32_t>>
+ auto filesystem::allocate_blocks(size_t count, mount_state & state) -> kstd::result<kstd::vector<uint32_t>>
{
- if (m_block_group_descriptors.empty() || count > m_superblock.free_blocks_count)
+ auto & [superblock, block_group_descriptors, backing_inode] = state;
+
+ if (block_group_descriptors.empty() || count > superblock.free_blocks_count)
{
return kstd::failure(ext2_errc::not_enough_free_blocks);
}
kstd::vector<uint32_t> allocated_blocks{};
- for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < m_block_group_descriptors.size();
+ for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < block_group_descriptors.size();
++block_group_descriptor_index)
{
- auto & block_group_descriptor = m_block_group_descriptors.at(block_group_descriptor_index);
+ auto & block_group_descriptor = block_group_descriptors.at(block_group_descriptor_index);
if (block_group_descriptor.free_blocks_count == 0)
{
continue;
}
- kstd::vector<uint8_t> block_bitmap(block_size().value, 0);
- if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap.data()); !read_result)
+ kstd::vector<uint8_t> block_bitmap(block_size(state).value, 0);
+ if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap.data(), state); !read_result)
{
return kstd::failure(read_result.error());
}
bool is_bitmap_dirty = false;
- for (auto i = 0uz; i < static_cast<size_t>(m_superblock.blocks_per_group) && allocated_blocks.size() < count; ++i)
+ for (auto i = 0uz; i < static_cast<size_t>(superblock.blocks_per_group) && allocated_blocks.size() < count; ++i)
{
if (!bitmap_is_set(block_bitmap, i))
{
@@ -492,24 +503,25 @@ namespace kernel::filesystem::ext2
bitmap_set(block_bitmap, i);
block_group_descriptor.free_blocks_count--;
- m_superblock.free_blocks_count--;
+ superblock.free_blocks_count--;
- allocated_blocks.push_back(i + block_group_descriptor_index * m_superblock.blocks_per_group);
+ allocated_blocks.push_back(i + block_group_descriptor_index * superblock.blocks_per_group);
}
}
if (is_bitmap_dirty)
{
- if (auto write_result = write_block(block_group_descriptor.block_bitmap, block_bitmap.data()); !write_result)
+ if (auto write_result = write_block(block_group_descriptor.block_bitmap, block_bitmap.data(), state);
+ !write_result)
{
return kstd::failure(write_result.error());
}
// TODO update all block group descriptors
if (auto write_result =
- m_backing_inode->write(as_bytes(std::span{&block_group_descriptor, 1}),
- block_group_descriptor_table_offset() +
- block_group_descriptor_index * kstd::size_of(block_group_descriptor));
+ backing_inode->write(as_bytes(std::span{&block_group_descriptor, 1}),
+ block_group_descriptor_table_offset(state) +
+ block_group_descriptor_index * kstd::size_of(block_group_descriptor));
!write_result)
{
return kstd::failure(write_result.error());
@@ -517,8 +529,8 @@ namespace kernel::filesystem::ext2
}
}
- // TODO update all superblocks
- if (auto write_result = m_backing_inode->write(as_bytes(std::span{&m_superblock, 1}), constants::superblock_offset);
+ // TODO update all superblock copies
+ if (auto write_result = backing_inode->write(as_bytes(std::span{&superblock, 1}), constants::superblock_offset);
!write_result)
{
return kstd::failure(write_result.error());
@@ -532,54 +544,58 @@ namespace kernel::filesystem::ext2
return allocated_blocks;
}
- auto filesystem::allocate_inode() -> kstd::result<uint32_t>
+ auto filesystem::allocate_inode(mount_state & state) -> kstd::result<uint32_t>
{
- if (m_block_group_descriptors.empty() || m_superblock.free_inodes_count == 0)
+ 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 < m_block_group_descriptors.size();
+ for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < block_group_descriptors.size();
++block_group_descriptor_index)
{
- auto & block_group_descriptor = m_block_group_descriptors.at(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;
}
- kstd::vector<uint8_t> inode_bitmap(block_size().value, 0);
- if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap.data()); !read_result)
+ kstd::vector<uint8_t> inode_bitmap(block_size(state).value, 0);
+ if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap.data(), state); !read_result)
{
return kstd::failure(read_result.error());
}
- for (auto i = 0uz; i < static_cast<size_t>(m_superblock.inodes_per_group); ++i)
+ 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--;
- m_superblock.free_inodes_count--;
+ superblock.free_inodes_count--;
- if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap.data()); !write_result)
+ if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap.data(), state);
+ !write_result)
{
return kstd::failure(write_result.error());
}
- if (auto write_result = write_block_group_descriptor(block_group_descriptor, block_group_descriptor_index);
+ if (auto write_result =
+ write_block_group_descriptor(block_group_descriptor, block_group_descriptor_index, state);
!write_result)
{
return kstd::failure(write_result.error());
}
// TODO update all superblocks
- if (auto write_result = write_superblock(); !write_result)
+ if (auto write_result = write_superblock(state); !write_result)
{
return kstd::failure(write_result.error());
}
- return block_group_descriptor_index * m_superblock.inodes_per_group + i + 1;
+ return block_group_descriptor_index * superblock.inodes_per_group + i + 1;
}
}
}
@@ -587,7 +603,8 @@ 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) const
+ auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data,
+ mount_state const & state) const
-> kstd::result<std::size_t>
{
if (inode_block_index < constants::direct_block_count)
@@ -597,7 +614,7 @@ namespace kernel::filesystem::ext2
inode_block_index -= constants::direct_block_count;
- for (auto const & level : indirect_levels())
+ for (auto const & level : indirect_levels(state))
{
if (inode_block_index >= level.capacity)
{
@@ -611,12 +628,12 @@ namespace kernel::filesystem::ext2
return 0;
}
- for (auto stride = level.capacity / block_numbers_per_block();; stride /= block_numbers_per_block())
+ for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state))
{
auto const idx = inode_block_index / stride;
inode_block_index %= stride;
- if (auto read_result = read_block_number_at_index(block_number, idx); !read_result)
+ if (auto read_result = read_block_number_at_index(block_number, idx, state); !read_result)
{
return kstd::failure(read_result.error());
}
@@ -642,14 +659,15 @@ 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) const -> kstd::result<uint32_t>
+ 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();
+ 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 =
- m_backing_inode->read(as_writable_bytes(std::span{&block_number_buffer, 1}), number_start_address);
+ state.backing_inode->read(as_writable_bytes(std::span{&block_number_buffer, 1}), number_start_address);
!read_result)
{
return kstd::failure(read_result.error());
@@ -659,7 +677,8 @@ namespace kernel::filesystem::ext2
}
auto filesystem::write_global_block_number_to_inode_block_index(size_t inode_block_index, inode_data & data,
- uint32_t global_block_number) -> kstd::result<void>
+ uint32_t global_block_number, mount_state & state)
+ -> kstd::result<void>
{
if (inode_block_index < constants::direct_block_count)
{
@@ -668,7 +687,7 @@ namespace kernel::filesystem::ext2
}
inode_block_index -= constants::direct_block_count;
- for (auto const & level : indirect_levels())
+ for (auto const & level : indirect_levels(state))
{
if (inode_block_index >= level.capacity)
{
@@ -676,18 +695,19 @@ namespace kernel::filesystem::ext2
continue;
}
+ auto & backing_inode = state.backing_inode;
auto block_number = data.block[level.slot_index];
auto parent_byte_offset = 0_B;
bool is_root = true;
- for (auto stride = level.capacity / block_numbers_per_block();; stride /= block_numbers_per_block())
+ for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state))
{
auto const idx = inode_block_index / stride;
inode_block_index %= stride;
if (idx == 0 && inode_block_index == 0)
{
- auto allocated = allocate_blocks(1);
+ auto allocated = allocate_blocks(1, state);
if (!allocated)
{
return kstd::failure(allocated.error());
@@ -701,7 +721,7 @@ namespace kernel::filesystem::ext2
}
else
{
- if (auto write_result = m_backing_inode->write(as_bytes(std::span{&block_number, 1}), parent_byte_offset);
+ if (auto write_result = backing_inode->write(as_bytes(std::span{&block_number, 1}), parent_byte_offset);
!write_result)
{
return kstd::failure(write_result.error());
@@ -709,11 +729,11 @@ namespace kernel::filesystem::ext2
}
}
- auto const byte_offset = block_number * block_size() + idx * kstd::size_of<uint32_t>();
+ auto const byte_offset = block_number * block_size(state) + idx * kstd::size_of<uint32_t>();
if (stride == 1)
{
- if (auto write_result = m_backing_inode->write(as_bytes(std::span{&global_block_number, 1}), byte_offset);
+ if (auto write_result = backing_inode->write(as_bytes(std::span{&global_block_number, 1}), byte_offset);
!write_result)
{
return kstd::failure(write_result.error());
@@ -723,7 +743,7 @@ namespace kernel::filesystem::ext2
parent_byte_offset = byte_offset;
is_root = false;
- if (auto read_result = read_block_number_at_index(block_number, idx); !read_result)
+ if (auto read_result = read_block_number_at_index(block_number, idx, state); !read_result)
{
return kstd::failure(read_result.error());
}
@@ -737,38 +757,38 @@ namespace kernel::filesystem::ext2
return kstd::success();
}
- auto filesystem::backing_inode() const -> kstd::shared_ptr<kernel::filesystem::inode> const &
- {
- return m_backing_inode;
- }
-
- auto filesystem::read_block(uint32_t block_number, void * buffer) const -> kstd::result<kstd::bytes>
+ auto filesystem::read_block(uint32_t block_number, void * buffer, mount_state & state) const
+ -> kstd::result<kstd::bytes>
{
- auto const block_offset = static_cast<size_t>(block_number) * block_size();
- return m_backing_inode->read(std::span{static_cast<std::byte *>(buffer), block_size().value}, block_offset);
+ auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
+ return state.backing_inode->read(std::span{static_cast<std::byte *>(buffer), block_size(state).value},
+ block_offset);
}
- auto filesystem::write_block(uint32_t block_number, void const * buffer) -> kstd::result<kstd::bytes>
+ auto filesystem::write_block(uint32_t block_number, void const * buffer, mount_state & state)
+ -> kstd::result<kstd::bytes>
{
- auto const block_offset = static_cast<size_t>(block_number) * block_size();
- return m_backing_inode->write(std::span{static_cast<std::byte const *>(buffer), block_size().value}, block_offset);
+ auto const block_offset = static_cast<size_t>(block_number) * block_size(state);
+ return state.backing_inode->write(std::span{static_cast<std::byte const *>(buffer), block_size(state).value},
+ block_offset);
}
auto filesystem::write_block_group_descriptor(block_group_descriptor const & block_group_descriptor,
- size_t block_group_descriptor_index) const -> kstd::result<void>
+ size_t block_group_descriptor_index, mount_state const & state) const
+ -> kstd::result<void>
{
// TODO update all block group descriptors
- return m_backing_inode
+ return state.backing_inode
->write(as_bytes(std::span{&block_group_descriptor, 1}),
- block_group_descriptor_table_offset() +
+ block_group_descriptor_table_offset(state) +
block_group_descriptor_index * kstd::size_of(block_group_descriptor))
.transform([](auto) {});
}
- auto filesystem::write_superblock() const -> kstd::result<void>
+ auto filesystem::write_superblock(mount_state & state) const -> kstd::result<void>
{
- // TODO update all superblocks
- return m_backing_inode->write(as_bytes(std::span{&m_superblock, 1}), constants::superblock_offset)
+ // TODO update all superblock copies
+ return state.backing_inode->write(as_bytes(std::span{&state.superblock, 1}), constants::superblock_offset)
.transform([](auto) {});
}
@@ -806,54 +826,54 @@ namespace kernel::filesystem::ext2
}
}
- auto filesystem::block_numbers_per_block() const -> size_t
+ auto filesystem::block_numbers_per_block(mount_state const & state) const -> size_t
{
- return block_size() / kstd::size_of<uint32_t>();
+ return block_size(state) / kstd::size_of<uint32_t>();
}
- auto filesystem::block_numbers_per_singly_indirect_block() const -> size_t
+ auto filesystem::block_numbers_per_singly_indirect_block(mount_state const & state) const -> size_t
{
- return block_numbers_per_block();
+ return block_numbers_per_block(state);
}
- auto filesystem::block_numbers_per_doubly_indirect_block() const -> size_t
+ auto filesystem::block_numbers_per_doubly_indirect_block(mount_state const & state) const -> size_t
{
- return block_numbers_per_singly_indirect_block() * block_numbers_per_block();
+ return block_numbers_per_singly_indirect_block(state) * block_numbers_per_block(state);
}
- auto filesystem::block_numbers_per_triply_indirect_block() const -> size_t
+ auto filesystem::block_numbers_per_triply_indirect_block(mount_state const & state) const -> size_t
{
- return block_numbers_per_doubly_indirect_block() * block_numbers_per_block();
+ return block_numbers_per_doubly_indirect_block(state) * block_numbers_per_block(state);
}
- auto filesystem::block_size() const -> kstd::bytes
+ auto filesystem::block_size(mount_state const & state) const -> kstd::bytes
{
- return kstd::bytes{constants::base_block_size.value << m_superblock.log_block_size};
+ return kstd::bytes{constants::base_block_size.value << state.superblock.log_block_size};
}
- auto filesystem::revision_level() const -> uint32_t
+ auto filesystem::revision_level(mount_state const & state) const -> uint32_t
{
- return m_superblock.rev_level;
+ return state.superblock.rev_level;
}
- auto filesystem::inode_size() const -> kstd::bytes
+ auto filesystem::inode_size(mount_state const & state) const -> kstd::bytes
{
- return kstd::bytes(revision_level() == constants::good_old_revision ? 128 : m_superblock.inode_size);
+ return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size);
}
- auto filesystem::inode_block_count(inode_data const & data) const -> uint32_t
+ auto filesystem::inode_block_count(inode_data const & data, mount_state const & state) const -> uint32_t
{
- return data.blocks / (2 << m_superblock.log_block_size);
+ return data.blocks / (2 << state.superblock.log_block_size);
}
- auto filesystem::update_inode_block_count(inode_data & data, uint32_t delta) -> void
+ auto filesystem::update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void
{
- data.blocks += delta * (2 << m_superblock.log_block_size);
+ data.blocks += delta * (2 << state.superblock.log_block_size);
}
- auto filesystem::block_group_descriptor_table_offset() const -> kstd::bytes
+ auto filesystem::block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes
{
- return block_size() == 1024_B ? 2 * block_size() : block_size();
+ 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 c6f8b04a..ef7afdfb 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.hpp
@@ -3,6 +3,7 @@
#include <kernel/filesystem/ext2/block_group_descriptor.hpp>
#include <kernel/filesystem/ext2/inode.hpp>
+#include <kernel/filesystem/ext2/mount_state.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/inode.hpp>
@@ -88,71 +89,81 @@ namespace kernel::filesystem::ext2
//! Get the size of a block in the filesystem.
//!
//! @return The size of a block in bytes.
- [[nodiscard]] auto block_size() const -> kstd::bytes;
+ [[nodiscard]] auto block_size(mount_state const & state) const -> kstd::bytes;
//! Get the revision level of the filesystem.
//!
//! @return The revision level.
- [[nodiscard]] auto revision_level() const -> uint32_t;
+ [[nodiscard]] auto revision_level(mount_state const & state) const -> uint32_t;
//! 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.
- auto read_block(uint32_t block_number, void * buffer) const -> kstd::result<kstd::bytes>;
+ auto read_block(uint32_t block_number, void * buffer, mount_state & 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.
- auto write_block(uint32_t block_number, void const * buffer) -> kstd::result<kstd::bytes>;
+ auto write_block(uint32_t block_number, void 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.
//! @return A vector of the allocated block numbers.
- auto allocate_blocks(size_t count) -> kstd::result<kstd::vector<uint32_t>>;
+ auto allocate_blocks(size_t count, mount_state & state) -> kstd::result<kstd::vector<uint32_t>>;
//! Get the size of an inode in the filesystem.
//!
//! @return The size of an inode in bytes.
- [[nodiscard]] auto inode_size() const -> kstd::bytes;
+ [[nodiscard]] auto inode_size(mount_state const & state) const -> kstd::bytes;
//! Get the number of blocks allocated to an inode.
//!
//! @param data The inode data.
+ //! @param state The state to operate on.
//! @return The number of blocks allocated to the inode.
- [[nodiscard]] auto inode_block_count(inode_data const & data) const -> uint32_t;
+ [[nodiscard]] auto inode_block_count(inode_data const & data, mount_state const & state) const -> 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) -> void;
+ 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) -> kstd::result<void>;
+ 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.
//!
//! @param inode_block_index The index of the block within 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) const
+ [[nodiscard]] auto map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data,
+ 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 state The state to operate on.
//! @param data The inode data.
//! @param global_block_number The global block number to write.
auto write_global_block_number_to_inode_block_index(size_t block_index, inode_data & data,
- uint32_t global_block_number) -> kstd::result<void>;
+ uint32_t global_block_number, mount_state & state)
+ -> kstd::result<void>;
//! Get the backing inode of the file system.
//!
@@ -166,36 +177,37 @@ namespace kernel::filesystem::ext2
size_t capacity;
};
- [[nodiscard]] auto indirect_levels() const -> std::array<indirect_level, 3>;
+ [[nodiscard]] auto indirect_levels(mount_state const & state) const -> std::array<indirect_level, 3>;
- auto allocate_inode() -> kstd::result<uint32_t>;
- auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode)
+ auto allocate_inode(mount_state & state) -> kstd::result<uint32_t>;
+ auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode,
+ mount_state & state) -> kstd::result<void>;
+ auto init_directory(kstd::shared_ptr<inode> const & new_inode, inode * parent_inode, mount_state & state)
-> kstd::result<void>;
- auto init_directory(kstd::shared_ptr<inode> const & new_inode, inode * parent_inode) -> kstd::result<void>;
auto write_directory_entry_to_buffer(uint8_t * block_buffer, kstd::bytes offset, uint32_t child_inode_number,
- std::string_view name, uint8_t file_type) -> void;
+ std::string_view name, uint8_t file_type, mount_state & state) -> void;
- [[nodiscard]] auto calculate_inode_offset(uint32_t inode_number) const -> kstd::result<kstd::bytes>;
- [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>;
- [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result<uint32_t>;
+ [[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() const -> kstd::bytes;
+ [[nodiscard]] auto block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes;
- [[nodiscard]] auto block_numbers_per_block() const -> size_t;
- [[nodiscard]] auto block_numbers_per_singly_indirect_block() const -> size_t;
- [[nodiscard]] auto block_numbers_per_doubly_indirect_block() const -> size_t;
- [[nodiscard]] auto block_numbers_per_triply_indirect_block() const -> size_t;
+ [[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) const -> kstd::result<void>;
- [[nodiscard]] auto write_superblock() const -> kstd::result<void>;
+ 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) -> uint8_t;
auto map_vfs_inode_type_into_inode_mode(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t;
-
- superblock m_superblock{};
- kstd::vector<block_group_descriptor> m_block_group_descriptors;
- inode_ptr m_backing_inode;
};
} // namespace kernel::filesystem::ext2
diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
index 0b815584..752dd010 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp
@@ -5,6 +5,7 @@
#include <kernel/filesystem/ext2/block_group_descriptor.hpp>
#include <kernel/filesystem/ext2/error.hpp>
#include <kernel/filesystem/ext2/inode.hpp>
+#include <kernel/filesystem/ext2/mount_state.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/mount.hpp>
@@ -207,7 +208,10 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
- REQUIRE(fs->mount(dev_inode));
+ auto mount = fs->mount(dev_inode);
+ REQUIRE(mount);
+ auto mount_state = static_pointer_cast<kernel::filesystem::ext2::mount_state>(mount->second);
+ REQUIRE(mount_state);
auto inode_data = kernel::filesystem::ext2::inode_data{};
inode_data.block[0] = 7;
@@ -231,16 +235,16 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys
THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
{
- REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data) == 7);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data) == 31);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data) == 42);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53);
+ 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);
}
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));
+ REQUIRE(!fs->map_inode_block_index_to_global_block_number(beyond_triply, inode_data, *mount_state));
}
}
}
@@ -279,7 +283,10 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys
kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock, block_group_descriptor);
auto fs = kstd::make_shared<kernel::filesystem::ext2::filesystem>();
- REQUIRE(fs->mount(dev_inode));
+ auto mount = fs->mount(dev_inode);
+ REQUIRE(mount);
+ auto mount_state = static_pointer_cast<kernel::filesystem::ext2::mount_state>(mount->second);
+ REQUIRE(mount_state);
auto read_u32 = [&](kstd::bytes offset) -> uint32_t {
auto value = uint32_t{0};
@@ -301,26 +308,30 @@ 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;
- REQUIRE(fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number));
+ REQUIRE(
+ fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number, *mount_state));
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));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number,
+ *mount_state));
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));
+ singly_global_block_number + 1, *mount_state));
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));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number,
+ *mount_state));
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));
+ REQUIRE(fs->write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number,
+ *mount_state));
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);
@@ -328,10 +339,14 @@ 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) == direct_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data) == singly_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data) == doubly_global_block_number);
- REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data) == 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);
}
}
}
diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp
index b04be99a..561bf9de 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -2,6 +2,7 @@
#include <kernel/filesystem/error.hpp>
#include <kernel/filesystem/ext2/filesystem.hpp>
+#include <kernel/filesystem/ext2/mount_state.hpp>
#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/mount.hpp>
@@ -46,20 +47,30 @@ namespace kernel::filesystem::ext2
return kstd::failure(filesystem.error());
}
- auto block_index = offset / (*filesystem)->block_size();
- auto in_block_offset = offset % (*filesystem)->block_size();
+ auto driver_data = get_driver_data();
+ if (!driver_data)
+ {
+ return kstd::failure(driver_data.error());
+ }
+
+ auto state = static_pointer_cast<mount_state const>(*driver_data);
+
+ auto block_size = (*filesystem)->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 = (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data);
+ auto const block_number =
+ (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, *state);
if (!block_number)
{
break;
}
- auto const bytes_to_read = std::min(requested_size - bytes_read, (*filesystem)->block_size() - in_block_offset);
+ 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);
@@ -73,7 +84,7 @@ namespace kernel::filesystem::ext2
return kstd::failure(inode.error());
}
- auto const block_start_offset = block_number.value() * (*filesystem)->block_size();
+ auto const block_start_offset = block_number.value() * block_size;
auto const read_offset = block_start_offset + in_block_offset;
auto const read_result = (*inode)->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset);
@@ -110,14 +121,22 @@ namespace kernel::filesystem::ext2
return kstd::failure(filesystem.error());
}
- auto const current_block_count = (*filesystem)->inode_block_count(m_data);
- auto const max_new_inode_size_without_new_blocks = current_block_count * (*filesystem)->block_size();
+ auto driver_data = get_driver_data();
+ if (!driver_data)
+ {
+ return kstd::failure(driver_data.error());
+ }
+
+ auto state = static_pointer_cast<mount_state>(*driver_data);
+ auto block_size = (*filesystem)->block_size(*state);
+
+ auto const current_block_count = (*filesystem)->inode_block_count(m_data, *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)
{
auto const additional_blocks_needed =
- (new_inode_size - max_new_inode_size_without_new_blocks + (*filesystem)->block_size() - 1_B) /
- (*filesystem)->block_size();
+ (new_inode_size - max_new_inode_size_without_new_blocks + block_size - 1_B) / block_size;
if (!append_blocks(additional_blocks_needed))
{
@@ -126,24 +145,24 @@ namespace kernel::filesystem::ext2
}
}
- auto block_index = offset / (*filesystem)->block_size();
- auto in_block_offset = offset % (*filesystem)->block_size();
+ auto block_index = offset / block_size;
+ auto in_block_offset = offset % block_size;
auto bytes_written = 0_B;
while (bytes_written < kstd::bytes{buffer.size()})
{
- auto const block_number = (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data);
+ auto const block_number =
+ (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, *state);
// TODO BA-FS26 if blocknumber == 0 --> handle sparse file
if (!block_number)
{
return kstd::failure(block_number.error());
}
- auto const bytes_to_write =
- std::min(kstd::bytes{buffer.size()} - bytes_written, (*filesystem)->block_size() - in_block_offset);
+ auto const bytes_to_write = std::min(kstd::bytes{buffer.size()} - bytes_written, block_size - in_block_offset);
- auto const block_start_offset = block_number.value() * (*filesystem)->block_size();
+ auto const block_start_offset = block_number.value() * block_size;
auto const write_offset = block_start_offset + in_block_offset;
auto inode = backing_inode();
@@ -166,7 +185,7 @@ namespace kernel::filesystem::ext2
}
set_size(std::max(this->size(), offset + bytes_written));
- if (auto write_result = (*filesystem)->write_inode(m_inode_number, m_data); !write_result)
+ if (auto write_result = (*filesystem)->write_inode(m_inode_number, m_data, *state); !write_result)
{
return kstd::failure(write_result.error());
}
@@ -182,7 +201,15 @@ namespace kernel::filesystem::ext2
return false;
}
- auto new_blocks = (*filesystem)->allocate_blocks(count);
+ auto driver_data = get_driver_data();
+ if (!driver_data)
+ {
+ return false;
+ }
+
+ auto state = static_pointer_cast<mount_state>(*driver_data);
+
+ auto new_blocks = (*filesystem)->allocate_blocks(count, *state);
if (!new_blocks)
{
return false;
@@ -190,18 +217,19 @@ namespace kernel::filesystem::ext2
for (auto i = 0uz; i < new_blocks->size(); ++i)
{
- auto const block_index = (*filesystem)->inode_block_count(m_data) + i;
+ auto const block_index = (*filesystem)->inode_block_count(m_data, *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, global_block_number);
+ (*filesystem)
+ ->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number, *state);
!write_result)
{
return false;
}
}
- (*filesystem)->update_inode_block_count(m_data, count);
+ (*filesystem)->update_inode_block_count(m_data, count, *state);
return true;
}
@@ -281,7 +309,15 @@ namespace kernel::filesystem::ext2
return 0_B;
}
- if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular())
+ auto driver_data = get_driver_data();
+ if (!driver_data)
+ {
+ return 0_B;
+ }
+
+ auto state = static_pointer_cast<mount_state const>(*driver_data);
+
+ if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular())
{
size |= static_cast<uint64_t>(m_data.dir_acl) << 32;
}
@@ -297,7 +333,15 @@ namespace kernel::filesystem::ext2
return;
}
- if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular())
+ auto driver_data = get_driver_data();
+ if (!driver_data)
+ {
+ return;
+ }
+
+ auto state = static_pointer_cast<mount_state>(*driver_data);
+
+ if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular())
{
m_data.dir_acl = static_cast<uint32_t>(new_size.value >> 32);
}
@@ -349,4 +393,24 @@ namespace kernel::filesystem::ext2
return kstd::failure(vfs_errc::not_mounted);
}
+ auto inode::get_driver_data() -> kstd::result<kstd::shared_ptr<void>>
+ {
+ if (auto mount = owning_mount().lock())
+ {
+ return mount->driver_data();
+ }
+
+ return kstd::failure(vfs_errc::not_mounted);
+ }
+
+ auto inode::get_driver_data() const -> kstd::result<kstd::shared_ptr<void const>>
+ {
+ if (auto mount = owning_mount().lock())
+ {
+ return mount->driver_data();
+ }
+
+ return kstd::failure(vfs_errc::not_mounted);
+ }
+
} // namespace kernel::filesystem::ext2
diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp
index cae1d801..6ca2f1b5 100644
--- a/kernel/kernel/filesystem/ext2/inode.hpp
+++ b/kernel/kernel/filesystem/ext2/inode.hpp
@@ -109,6 +109,10 @@ namespace kernel::filesystem::ext2
[[nodiscard]] auto backing_inode() const -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode const>>;
+ [[nodiscard]] auto get_driver_data() -> kstd::result<kstd::shared_ptr<void>>;
+
+ [[nodiscard]] auto get_driver_data() const -> kstd::result<kstd::shared_ptr<void const>>;
+
//! The inode number on disk.
uint32_t m_inode_number{};
//! The inode data.
diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp
index 356e44ed..a6a88fc8 100644
--- a/kernel/kernel/filesystem/ext2/inode.tests.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp
@@ -4,6 +4,7 @@
#include <kernel/filesystem/device_inode.hpp>
#include <kernel/filesystem/ext2/block_group_descriptor.hpp>
#include <kernel/filesystem/ext2/filesystem.hpp>
+#include <kernel/filesystem/ext2/mount_state.hpp>
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/mount.hpp>
@@ -326,6 +327,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
(*file)->set_owning_mount(*mount);
+ auto mount_state = static_pointer_cast<kernel::filesystem::ext2::mount_state>(driver_data);
+ REQUIRE(mount_state);
+
THEN("writing to the inode updates backing device and the inode size")
{
auto write_buffer = kstd::vector<std::byte>{std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'},
@@ -350,8 +354,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
{
auto inode_data = static_cast<kernel::filesystem::ext2::inode *>(file.value().get())->data();
- auto const block_size = fs->block_size();
- auto const expected_allocated_blocks = 32 * fs->inode_block_count(inode_data);
+ auto const block_size = fs->block_size(*mount_state);
+ auto const expected_allocated_blocks = 32 * fs->inode_block_count(inode_data, *mount_state);
auto write_buffer = kstd::vector<std::byte>(block_size.value * expected_allocated_blocks, std::byte{'A'});
@@ -365,7 +369,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in
auto new_inode_data = static_cast<kernel::filesystem::ext2::inode *>(file.value().get())->data();
REQUIRE(new_inode_data.size == write_buffer.size());
- REQUIRE(fs->inode_block_count(new_inode_data) == expected_allocated_blocks);
+ REQUIRE(fs->inode_block_count(new_inode_data, *mount_state) == expected_allocated_blocks);
}
THEN("writing to a an inode of type directory panics")
@@ -413,6 +417,8 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode);
auto root = (*mount)->root_dentry()->inode();
REQUIRE(mount);
+ auto mount_state = static_pointer_cast<kernel::filesystem::ext2::mount_state>((*mount)->driver_data());
+ REQUIRE(mount_state);
auto inode_data = kernel::filesystem::ext2::inode_data{};
inode_data.size = 5;
@@ -423,7 +429,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]"
uint32_t inode_number = 3;
auto const inode_data_offset =
- block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs->inode_size();
+ block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs->inode_size(*mount_state);
auto inode = kernel::filesystem::ext2::inode{inode_number, inode_data};
inode.set_owning_mount(*mount);
diff --git a/kernel/kernel/filesystem/ext2/mount_state.hpp b/kernel/kernel/filesystem/ext2/mount_state.hpp
index b9c2d5f7..e8ae8fd7 100644
--- a/kernel/kernel/filesystem/ext2/mount_state.hpp
+++ b/kernel/kernel/filesystem/ext2/mount_state.hpp
@@ -13,9 +13,9 @@ namespace kernel::filesystem::ext2
struct mount_state
{
- struct superblock superblock;
- kstd::vector<block_group_descriptor> block_group_descriptors;
- kstd::shared_ptr<kernel::filesystem::inode> backing_inode;
+ struct superblock superblock{};
+ kstd::vector<block_group_descriptor> block_group_descriptors{};
+ kstd::shared_ptr<kernel::filesystem::inode> backing_inode{};
};
} // namespace kernel::filesystem::ext2