From c2f73da69d368f4488b878c5b4e957be630a3a7b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 13:47:30 +0200 Subject: kernel/fs: remove raw filesystem pointer from inode. --- kernel/kernel/filesystem/error.cpp | 4 + kernel/kernel/filesystem/error.hpp | 1 + kernel/kernel/filesystem/ext2/filesystem.cpp | 16 +-- kernel/kernel/filesystem/ext2/filesystem.hpp | 3 +- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 97 ++++++++--------- kernel/kernel/filesystem/ext2/inode.cpp | 114 ++++++++++++++------ kernel/kernel/filesystem/ext2/inode.hpp | 9 +- kernel/kernel/filesystem/ext2/inode.tests.cpp | 116 ++++++++++++--------- 8 files changed, 220 insertions(+), 140 deletions(-) diff --git a/kernel/kernel/filesystem/error.cpp b/kernel/kernel/filesystem/error.cpp index 80ad1097..d288693e 100644 --- a/kernel/kernel/filesystem/error.cpp +++ b/kernel/kernel/filesystem/error.cpp @@ -54,6 +54,8 @@ namespace kernel::filesystem return "no such device"; case vfs_errc::invalid_argument: return "invalid argument"; + case vfs_errc::not_mounted: + return "filesystem is not mounted"; default: return "unknown VFS error"; } @@ -91,6 +93,8 @@ namespace kernel::filesystem return make_error_condition(kstd::errc::file_exists); case vfs_errc::no_such_device: return make_error_condition(kstd::errc::no_such_device); + case vfs_errc::not_mounted: + return make_error_condition(kstd::errc::not_connected); default: return kstd::error_condition{value, *this}; } diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp index 83b11902..41009bb7 100644 --- a/kernel/kernel/filesystem/error.hpp +++ b/kernel/kernel/filesystem/error.hpp @@ -27,6 +27,7 @@ namespace kernel::filesystem file_exists, no_such_device, invalid_argument, + not_mounted, }; [[nodiscard]] auto vfs_category() noexcept -> kstd::error_category const &; diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index c6180fe1..58d24fc1 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -134,7 +134,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(read_result.error()); } - auto root = read_inode(constants::root_inode_number); + auto root = read_inode(constants::root_inode_number, nullptr); if (!root) { @@ -187,7 +187,7 @@ namespace kernel::filesystem::ext2 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, ext2_parent->owning_mount().lock()); } bytes_read += kstd::bytes{entry->rec_len}; @@ -223,7 +223,7 @@ namespace kernel::filesystem::ext2 auto * ext2_parent = static_cast(parent.get()); if (!ext2_parent) { - return nullptr; + return kstd::failure(vfs_errc::invalid_argument); } auto maybe_inode_number = allocate_inode(); @@ -257,7 +257,8 @@ namespace kernel::filesystem::ext2 return kstd::failure(result.error()); } - auto new_inode = kstd::make_shared(this, inode_number, new_inode_data); + auto new_inode = kstd::make_shared(inode_number, new_inode_data); + new_inode->set_owning_mount(ext2_parent->owning_mount().lock()); if (new_inode->is_directory()) { @@ -394,7 +395,8 @@ namespace kernel::filesystem::ext2 kstd::libc::memcpy(entry->name.data(), name.data(), name_len); } - auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result> + auto filesystem::read_inode(uint32_t inode_number, kstd::shared_ptr const & mount) const + -> kstd::result> { if (auto inode_offset = calculate_inode_offset(inode_number)) { @@ -407,7 +409,9 @@ namespace kernel::filesystem::ext2 } else { - return kstd::make_shared(const_cast(this), inode_number, new_inode_data); + auto inode = kstd::make_shared(inode_number, new_inode_data); + inode->set_owning_mount(mount); + return inode; } } else diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 23629928..2f9d0d58 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -178,7 +178,8 @@ namespace kernel::filesystem::ext2 std::string_view name, uint8_t file_type) -> void; [[nodiscard]] auto calculate_inode_offset(uint32_t inode_number) const -> kstd::result; - [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result>; + [[nodiscard]] auto read_inode(uint32_t inode_number, kstd::shared_ptr const & mount) const + -> kstd::result>; [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result; [[nodiscard]] auto block_group_descriptor_table_offset() const -> kstd::bytes; diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index bf7c89ae..5feea017 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -47,38 +48,39 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto dev_inode = kstd::make_shared(boot_device); - auto fs = kernel::filesystem::ext2::filesystem{}; - auto root = fs.mount(dev_inode); - REQUIRE(root); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); THEN("the root inode is available and is a directory") { - REQUIRE(*root); - REQUIRE((*root)->is_directory()); + REQUIRE(root); + REQUIRE((root)->is_directory()); } THEN("lookup resolves known entries from the image") { - auto information = fs.lookup(*root, "information"); + auto information = fs->lookup(root, "information"); REQUIRE(information); REQUIRE(information.value()->is_directory()); - auto info_1 = fs.lookup(*information, "info_1.txt"); + auto info_1 = fs->lookup(*information, "info_1.txt"); REQUIRE(info_1); REQUIRE(info_1.value()->is_regular()); } THEN("lookup returns null for invalid inputs") { - REQUIRE(!fs.lookup(nullptr, "information")); + REQUIRE(!fs->lookup(nullptr, "information")); - auto information = fs.lookup(*root, "information"); + auto information = fs->lookup(root, "information"); REQUIRE(information); - auto info_1 = fs.lookup(*information, "info_1.txt"); + auto info_1 = fs->lookup(*information, "info_1.txt"); REQUIRE(info_1); - REQUIRE(!fs.lookup(*info_1, "anything")); - REQUIRE(!fs.lookup(*root, "does_not_exist")); + REQUIRE(!fs->lookup(*info_1, "anything")); + REQUIRE(!fs->lookup(root, "does_not_exist")); } } } @@ -98,52 +100,53 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto dev_inode = kstd::make_shared(boot_device); - auto fs = kernel::filesystem::ext2::filesystem{}; - auto root = fs.mount(dev_inode); - REQUIRE(root); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); THEN("a file can be created") { - auto lookup_result = fs.lookup(*root, "blub"); + auto lookup_result = fs->lookup(root, "blub"); REQUIRE(!lookup_result); - auto new_inode = fs.create_inode(*root, "blub", kapi::filesystem::file_type::regular); + auto new_inode = fs->create_inode(root, "blub", kapi::filesystem::file_type::regular); REQUIRE(new_inode); REQUIRE(new_inode.value()->is_regular()); - lookup_result = fs.lookup(*root, "blub"); + lookup_result = fs->lookup(root, "blub"); REQUIRE(lookup_result); } THEN("a directory can be created") { - auto lookup_result = fs.lookup(*root, "blub"); + auto lookup_result = fs->lookup(root, "blub"); REQUIRE(!lookup_result); - auto new_directory = fs.create_inode(*root, "blub", kapi::filesystem::file_type::directory); + auto new_directory = fs->create_inode(root, "blub", kapi::filesystem::file_type::directory); REQUIRE(new_directory); REQUIRE(new_directory.value()->is_directory()); - lookup_result = fs.lookup(*root, "blub"); + lookup_result = fs->lookup(root, "blub"); REQUIRE(lookup_result); } THEN("a directory and a file within can be created") { - auto new_directory = fs.create_inode(*root, "blub", kapi::filesystem::file_type::directory); + auto new_directory = fs->create_inode(root, "blub", kapi::filesystem::file_type::directory); REQUIRE(new_directory); - auto new_file = fs.create_inode(new_directory.value(), "blub_file", kapi::filesystem::file_type::regular); + auto new_file = fs->create_inode(new_directory.value(), "blub_file", kapi::filesystem::file_type::regular); REQUIRE(new_file); - auto lookup_result = fs.lookup(new_directory.value(), "blub_file"); + auto lookup_result = fs->lookup(new_directory.value(), "blub_file"); REQUIRE(lookup_result); REQUIRE(lookup_result.value()->is_regular()); } THEN("a file can be created and written to") { - auto new_inode = fs.create_inode(*root, "blub", kapi::filesystem::file_type::regular); + auto new_inode = fs->create_inode(root, "blub", kapi::filesystem::file_type::regular); REQUIRE(new_inode); auto buffer = @@ -162,7 +165,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("a symbolic link is not implemented yet") { - REQUIRE_THROWS_AS(fs.create_inode(*root, "blub", kapi::filesystem::file_type::symbolic_link), + REQUIRE_THROWS_AS(fs->create_inode(root, "blub", kapi::filesystem::file_type::symbolic_link), kernel::tests::cpu::halt); } } @@ -178,11 +181,11 @@ SCENARIO("Ext2 filesystem rejects invalid magic", "[filesystem][ext2][filesystem auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; + auto fs = kstd::make_shared(); THEN("mount fails with invalid_magic_number") { - REQUIRE(fs.mount(dev_inode).error() == kernel::filesystem::ext2::ext2_errc::invalid_magic_number); + REQUIRE(fs->mount(dev_inode).error() == kernel::filesystem::ext2::ext2_errc::invalid_magic_number); } } } @@ -200,8 +203,8 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + REQUIRE(fs->mount(dev_inode)); auto inode_data = kernel::filesystem::ext2::inode_data{}; inode_data.block[0] = 7; @@ -225,16 +228,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) == 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); } 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)); } } } @@ -272,8 +275,8 @@ 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 = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + REQUIRE(fs->mount(dev_inode)); auto read_u32 = [&](kstd::bytes offset) -> uint32_t { auto value = uint32_t{0}; @@ -295,26 +298,26 @@ 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)); 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)); REQUIRE(inode_data.block[12] == 16); REQUIRE(read_u32(static_cast(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)); + REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start + 1, inode_data, + singly_global_block_number + 1)); REQUIRE(read_u32(static_cast(inode_data.block[12]) * block_size.value + 1 * kstd::size_of()) == 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)); REQUIRE(inode_data.block[13] == 17); auto const doubly_leaf_table = read_u32(static_cast(inode_data.block[13]) * block_size); REQUIRE(doubly_leaf_table == 18); REQUIRE(read_u32(static_cast(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)); REQUIRE(inode_data.block[14] == 19); auto const triply_middle_table = read_u32(static_cast(inode_data.block[14]) * block_size); REQUIRE(triply_middle_table == 20); @@ -322,10 +325,10 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys REQUIRE(triply_leaf_table == 21); REQUIRE(read_u32(static_cast(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) == 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); } } } diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 8da80191..5e80f40b 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -1,12 +1,15 @@ #include +#include #include #include +#include #include #include #include +#include #include #include @@ -20,16 +23,10 @@ using namespace kstd::units_literals; namespace kernel::filesystem::ext2 { - inode::inode(filesystem * fs, uint32_t inode_number, inode_data const & data) - : m_filesystem(fs) - , m_inode_number(inode_number) + inode::inode(uint32_t inode_number, inode_data const & data) + : m_inode_number(inode_number) , m_data(data) - { - if (!m_filesystem) - { - kapi::system::panic("[EXT2] ext2::inode constructed with filesystem null pointer"); - } - } + {} auto inode::read(std::span buffer, kstd::bytes offset) const -> kstd::result { @@ -43,20 +40,26 @@ namespace kernel::filesystem::ext2 return requested_size; } - auto block_index = offset / m_filesystem->block_size(); - auto in_block_offset = offset % m_filesystem->block_size(); + auto filesystem = get_filesystem(); + if (!filesystem) + { + return kstd::failure(filesystem.error()); + } + + auto block_index = offset / (*filesystem)->block_size(); + auto in_block_offset = offset % (*filesystem)->block_size(); auto bytes_read = 0_B; while (bytes_read < requested_size) { - auto const block_number = m_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); if (!block_number) { break; } - auto const bytes_to_read = std::min(requested_size - bytes_read, m_filesystem->block_size() - in_block_offset); + auto const bytes_to_read = std::min(requested_size - bytes_read, (*filesystem)->block_size() - in_block_offset); if (block_number == 0) { kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value); @@ -64,10 +67,10 @@ namespace kernel::filesystem::ext2 } else { - auto const block_start_offset = block_number.value() * m_filesystem->block_size(); + auto const block_start_offset = block_number.value() * (*filesystem)->block_size(); auto const read_offset = block_start_offset + in_block_offset; auto const read_result = - m_filesystem->backing_inode()->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); + (*filesystem)->backing_inode()->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); if (!read_result) { return kstd::failure(read_result.error()); @@ -95,14 +98,20 @@ namespace kernel::filesystem::ext2 auto const new_inode_size = std::max(this->size(), offset + kstd::bytes{buffer.size()}); - auto const current_block_count = m_filesystem->inode_block_count(m_data); - auto const max_new_inode_size_without_new_blocks = current_block_count * m_filesystem->block_size(); + auto filesystem = get_filesystem(); + if (!filesystem) + { + 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(); 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 + m_filesystem->block_size() - 1_B) / - m_filesystem->block_size(); + (new_inode_size - max_new_inode_size_without_new_blocks + (*filesystem)->block_size() - 1_B) / + (*filesystem)->block_size(); if (!append_blocks(additional_blocks_needed)) { @@ -111,14 +120,14 @@ namespace kernel::filesystem::ext2 } } - auto block_index = offset / m_filesystem->block_size(); - auto in_block_offset = offset % m_filesystem->block_size(); + auto block_index = offset / (*filesystem)->block_size(); + auto in_block_offset = offset % (*filesystem)->block_size(); auto bytes_written = 0_B; while (bytes_written < kstd::bytes{buffer.size()}) { - auto const block_number = m_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); // TODO BA-FS26 if blocknumber == 0 --> handle sparse file if (!block_number) { @@ -126,13 +135,14 @@ namespace kernel::filesystem::ext2 } auto const bytes_to_write = - std::min(kstd::bytes{buffer.size()} - bytes_written, m_filesystem->block_size() - in_block_offset); + std::min(kstd::bytes{buffer.size()} - bytes_written, (*filesystem)->block_size() - in_block_offset); - auto const block_start_offset = block_number.value() * m_filesystem->block_size(); + auto const block_start_offset = block_number.value() * (*filesystem)->block_size(); auto const write_offset = block_start_offset + in_block_offset; - auto const write_result = - m_filesystem->backing_inode()->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); + auto const write_result = (*filesystem) + ->backing_inode() + ->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); if (!write_result) { return kstd::failure(write_result.error()); @@ -145,7 +155,7 @@ namespace kernel::filesystem::ext2 } set_size(std::max(this->size(), offset + bytes_written)); - if (auto write_result = m_filesystem->write_inode(m_inode_number, m_data); !write_result) + if (auto write_result = (*filesystem)->write_inode(m_inode_number, m_data); !write_result) { return kstd::failure(write_result.error()); } @@ -155,7 +165,13 @@ namespace kernel::filesystem::ext2 auto inode::append_blocks(size_t count) -> bool { - auto new_blocks = m_filesystem->allocate_blocks(count); + auto filesystem = get_filesystem(); + if (!filesystem) + { + return false; + } + + auto new_blocks = (*filesystem)->allocate_blocks(count); if (!new_blocks) { return false; @@ -163,18 +179,18 @@ namespace kernel::filesystem::ext2 for (auto i = 0uz; i < new_blocks->size(); ++i) { - auto const block_index = m_filesystem->inode_block_count(m_data) + i; + auto const block_index = (*filesystem)->inode_block_count(m_data) + i; auto const global_block_number = new_blocks->at(i); if (auto write_result = - m_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); !write_result) { return false; } } - m_filesystem->update_inode_block_count(m_data, count); + (*filesystem)->update_inode_block_count(m_data, count); return true; } @@ -248,7 +264,13 @@ namespace kernel::filesystem::ext2 { uint64_t size = m_data.size; - if (m_filesystem->revision_level() > constants::good_old_revision && is_regular()) + auto filesystem = get_filesystem(); + if (!filesystem) + { + return 0_B; + } + + if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular()) { size |= static_cast(m_data.dir_acl) << 32; } @@ -258,7 +280,13 @@ namespace kernel::filesystem::ext2 auto inode::set_size(kstd::bytes new_size) -> void { - if (m_filesystem->revision_level() > constants::good_old_revision && is_regular()) + auto filesystem = get_filesystem(); + if (!filesystem) + { + return; + } + + if ((*filesystem)->revision_level() > constants::good_old_revision && is_regular()) { m_data.dir_acl = static_cast(new_size.value >> 32); } @@ -270,4 +298,24 @@ namespace kernel::filesystem::ext2 return m_inode_number; } + auto inode::get_filesystem() -> kstd::result> + { + if (auto mount = owning_mount().lock()) + { + return static_pointer_cast(mount->get_filesystem()); + } + + return kstd::failure(vfs_errc::not_mounted); + } + + auto inode::get_filesystem() const -> kstd::result> + { + if (auto mount = owning_mount().lock()) + { + return static_pointer_cast(mount->get_filesystem()); + } + + 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 61961f6c..41231cab 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -46,10 +46,9 @@ namespace kernel::filesystem::ext2 { //! Create an ext2 inode associated with the given filesystem. //! - //! @param fs The ext2 filesystem that this inode belongs to. //! @param inode_number The inode number on disk. //! @param data The data associated with this inode, read from the disk. - explicit inode(filesystem * fs, uint32_t inode_number, inode_data const & data); + explicit inode(uint32_t inode_number, inode_data const & data); [[nodiscard]] auto read(std::span buffer, kstd::bytes offset) const -> kstd::result override; @@ -102,8 +101,10 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto number() const -> uint32_t; private: - //! The filesystem this inode belongs to. - filesystem * m_filesystem; + [[nodiscard]] auto get_filesystem() -> kstd::result>; + + [[nodiscard]] auto get_filesystem() const -> kstd::result>; + //! 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 d110c16a..ecfc76ba 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]" THEN("the inode is initialized with regular file mode in data and has the kind regular") { data.mode = kernel::filesystem::ext2::constants::mode_regular; - auto inode = kernel::filesystem::ext2::inode(&fs, 42, data); + auto inode = kernel::filesystem::ext2::inode(42, data); REQUIRE(inode.is_regular()); REQUIRE_FALSE(inode.is_directory()); @@ -53,7 +54,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]" THEN("the inode is initialized with directory mode in data and has the kind directory") { data.mode = kernel::filesystem::ext2::constants::mode_directory; - auto inode = kernel::filesystem::ext2::inode(&fs, 42, data); + auto inode = kernel::filesystem::ext2::inode(42, data); REQUIRE_FALSE(inode.is_regular()); REQUIRE(inode.is_directory()); @@ -64,7 +65,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]" THEN("the inode is initialized with symbolic link mode in data and has the kind symbolic link") { data.mode = kernel::filesystem::ext2::constants::mode_symbolic_link; - auto inode = kernel::filesystem::ext2::inode(&fs, 42, data); + auto inode = kernel::filesystem::ext2::inode(42, data); REQUIRE_FALSE(inode.is_regular()); REQUIRE_FALSE(inode.is_directory()); @@ -75,7 +76,7 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]" THEN("the inode is initialized with zero mode in data and has no specific kind") { data.mode = 0; - auto inode = kernel::filesystem::ext2::inode(&fs, 42, data); + auto inode = kernel::filesystem::ext2::inode(42, data); REQUIRE_FALSE(inode.is_regular()); REQUIRE_FALSE(inode.is_directory()); @@ -83,14 +84,6 @@ SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]" REQUIRE_FALSE(inode.is_symbolic_link()); } } - - GIVEN("no filesystem (null pointer)") - { - THEN("constructing an inode with a null filesystem pointer panics") - { - REQUIRE_THROWS_AS(kernel::filesystem::ext2::inode(nullptr, 42, {}), kernel::tests::cpu::halt); - } - } } SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 inode reads from real image", @@ -108,13 +101,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto dev_inode = kstd::make_shared(boot_device); - auto fs = kernel::filesystem::ext2::filesystem{}; - auto root = fs.mount(dev_inode); - REQUIRE(root); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); - auto information = fs.lookup(*root, "information"); + auto information = fs->lookup(root, "information"); REQUIRE(information); - auto file = fs.lookup(*information, "info_1.txt"); + auto file = fs->lookup(*information, "info_1.txt"); REQUIRE(file); REQUIRE(file.value()->is_regular()); @@ -151,8 +145,10 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; data.block[0] = 30; @@ -163,7 +159,8 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5_B); kernel::tests::filesystem::ext2::write_bytes(*device, 31 * block_size, "World!", 6_B); - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; + auto inode = kernel::filesystem::ext2::inode{42, data}; + inode.set_owning_mount(*mount); auto buffer = kstd::vector(data.size, std::byte{0xAB}); @@ -189,8 +186,10 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; data.block[0] = 30; @@ -205,7 +204,8 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste kernel::tests::filesystem::ext2::write_bytes(*device, 50 * block_size, "Blub", 4_B); kernel::tests::filesystem::ext2::write_bytes(*device, 51 * block_size, "World!", 6_B); - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; + auto inode = kernel::filesystem::ext2::inode{42, data}; + inode.set_owning_mount(*mount); auto buffer = kstd::vector(data.size, std::byte{0xAB}); @@ -234,14 +234,17 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; data.block[12] = 0; data.size = block_size.value * 15; - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; + auto inode = kernel::filesystem::ext2::inode{42, data}; + inode.set_owning_mount(*mount); auto buffer = kstd::vector(block_size.value * 15, std::byte{0xAB}); @@ -265,8 +268,10 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]") auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto inode_data = kernel::filesystem::ext2::inode_data{}; inode_data.size = block_size.value * 2; @@ -274,7 +279,8 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]") kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size - 6_B, "Hello ", 6_B); inode_data.block[1] = 21; kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size, "World!", 6_B); - auto inode = kernel::filesystem::ext2::inode{&fs, 42, inode_data}; + auto inode = kernel::filesystem::ext2::inode{42, inode_data}; + inode.set_owning_mount(*mount); auto buffer = kstd::vector(12, std::byte{0x00}); @@ -303,13 +309,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto dev_inode = kstd::make_shared(boot_device); - auto fs = kernel::filesystem::ext2::filesystem{}; - auto root = fs.mount(dev_inode); - REQUIRE(root); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); - auto information = fs.lookup(*root, "information"); + auto information = fs->lookup(root, "information"); REQUIRE(information); - auto file = fs.lookup(*information, "info_1.txt"); + auto file = fs->lookup(*information, "info_1.txt"); REQUIRE(file); REQUIRE(file.value()->is_regular()); @@ -337,8 +344,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in { auto inode_data = static_cast(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(); + auto const expected_allocated_blocks = 32 * fs->inode_block_count(inode_data); auto write_buffer = kstd::vector(block_size.value * expected_allocated_blocks, std::byte{'A'}); @@ -352,7 +359,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto new_inode_data = static_cast(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) == expected_allocated_blocks); } THEN("writing to a an inode of type directory panics") @@ -396,8 +403,10 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" REQUIRE(dev_inode->write(block_bitmap, block_group_descriptor.block_bitmap * block_size)); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto inode_data = kernel::filesystem::ext2::inode_data{}; inode_data.size = 5; @@ -407,9 +416,11 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" inode_data.mode = kernel::filesystem::ext2::constants::mode_regular; uint32_t inode_number = 3; - auto const inode_data_offset = block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs.inode_size(); + auto const inode_data_offset = + block_group_descriptor.inode_table * block_size + (inode_number - 1) * fs->inode_size(); - auto inode = kernel::filesystem::ext2::inode{&fs, inode_number, inode_data}; + auto inode = kernel::filesystem::ext2::inode{inode_number, inode_data}; + inode.set_owning_mount(*mount); REQUIRE(dev_inode->write(as_bytes(std::span{&inode, 1}), inode_data_offset)); auto const buffer = @@ -421,7 +432,8 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" auto do_read_inode = [&]() { auto inode_data = kernel::filesystem::ext2::inode_data{}; REQUIRE(dev_inode->read(as_writable_bytes(std::span{&inode_data, 1}), inode_data_offset)); - auto read_inode = kernel::filesystem::ext2::inode{&fs, inode_number, inode_data}; + auto read_inode = kernel::filesystem::ext2::inode{inode_number, inode_data}; + read_inode.set_owning_mount(*mount); return read_inode; }; @@ -530,8 +542,10 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; data.size = 256; @@ -541,7 +555,8 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending uint32_t expected_dir_acl_after_set_size) { data.mode = mode; - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; + auto inode = kernel::filesystem::ext2::inode{42, data}; + inode.set_owning_mount(*mount); REQUIRE(inode.size() == expected_initial_size); @@ -573,8 +588,10 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending auto dev_inode = kstd::make_shared(device); - auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + auto root = (*mount)->root_dentry()->get_inode(); + REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; data.size = 256; @@ -584,7 +601,8 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending uint32_t expected_dir_acl_after_set_size) { data.mode = mode; - auto inode = kernel::filesystem::ext2::inode{&fs, 42, data}; + auto inode = kernel::filesystem::ext2::inode{42, data}; + inode.set_owning_mount(*mount); REQUIRE(inode.size() == expected_initial_size); @@ -617,7 +635,7 @@ SCENARIO("Ext2 inode status()", "[filesystem][ext2][inode]") data.block[0] = (1 << 8); data.links_count = 1; - auto inode = kernel::filesystem::ext2::inode(&fs, 42, data); + auto inode = kernel::filesystem::ext2::inode(42, data); THEN("status() reports the real inode number, link count, and decoded raw device") { -- cgit v1.2.3