diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-08-23 14:49:44 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-08-26 11:16:17 +0200 |
| commit | 815cca56b68767ea6e223d7c6c671e57a9e31fb4 (patch) | |
| tree | 37ba370bc435658504194e81876eeb9332fea0e1 /kernel | |
| parent | f3d7fc902e2e1000dd202859cad892f821b98380 (diff) | |
| download | kernel-815cca56b68767ea6e223d7c6c671e57a9e31fb4.tar.xz kernel-815cca56b68767ea6e223d7c6c671e57a9e31fb4.zip | |
kernel/fs: ext2: externalize mount state
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.cpp | 308 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.hpp | 72 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 47 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.cpp | 108 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.hpp | 4 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.tests.cpp | 14 | ||||
| -rw-r--r-- | kernel/kernel/filesystem/ext2/mount_state.hpp | 6 |
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 |
