From 0a03abd3d367384c1ae1ad6709f97a9c42ec8a7d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Aug 2026 19:32:55 +0200 Subject: kernel/fs: add back-link from inodes to their mount --- kernel/kernel/filesystem/inode.cpp | 11 +++++++++++ kernel/kernel/filesystem/inode.hpp | 21 +++++++++++++++++++++ kernel/kernel/filesystem/vfs.cpp | 4 ++++ 3 files changed, 36 insertions(+) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/inode.cpp b/kernel/kernel/filesystem/inode.cpp index d0762472..26f523c6 100644 --- a/kernel/kernel/filesystem/inode.cpp +++ b/kernel/kernel/filesystem/inode.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -77,4 +78,14 @@ namespace kernel::filesystem return std::nullopt; } + auto inode::owning_mount() const noexcept -> kstd::weak_ptr + { + return m_owning_mount; + } + + auto inode::set_owning_mount(kstd::shared_ptr const & source) noexcept -> void + { + m_owning_mount = source; + } + } // namespace kernel::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/inode.hpp b/kernel/kernel/filesystem/inode.hpp index afe15e7d..677c5155 100644 --- a/kernel/kernel/filesystem/inode.hpp +++ b/kernel/kernel/filesystem/inode.hpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -12,6 +13,8 @@ namespace kernel::filesystem { + struct mount; + //! An inode in the filesystem. //! //! Specific filesystems, or other subsystems, may provide their own implementation of this abstract base class. For @@ -102,6 +105,24 @@ namespace kernel::filesystem [[nodiscard]] virtual auto raw_device() const -> std::optional; //! @} + + //! @name Mount Resolution + //! @{ + + //! Get the mount this inode belongs to. + //! + //! @return The mount this inode belongs to. + [[nodiscard]] auto owning_mount() const noexcept -> kstd::weak_ptr; + + //! Define which mount this inode belongs to. + //! + //! @param source The mount this inode belongs to. + auto set_owning_mount(kstd::shared_ptr const & source) noexcept -> void; + + //! @} + + private: + kstd::weak_ptr m_owning_mount{}; }; } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 0cb46cac..02c577f2 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -282,6 +282,8 @@ namespace kernel::filesystem { if (auto new_inode = fs->create_inode(parent_dentry->get_inode(), name, type, raw_device)) { + (*new_inode)->set_owning_mount(mount_context); + auto new_dentry = kstd::make_shared(parent_dentry, *new_inode, name); parent_dentry->add_child(new_dentry); @@ -385,6 +387,8 @@ namespace kernel::filesystem return kstd::failure(found_inode.error()); } + (*found_inode)->set_owning_mount(current_mount); + next_dentry = kstd::make_shared(current_dentry, *found_inode, part); current_dentry->add_child(next_dentry); } -- cgit v1.2.3 From a73f238cb6491b040db3b7cd79fe772fcf0a7fdd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Aug 2026 21:04:21 +0200 Subject: kernel/fs: remove the root inode from the base. --- kernel/kernel/filesystem/devfs/filesystem.cpp | 5 +-- kernel/kernel/filesystem/devfs/filesystem.hpp | 4 ++- .../kernel/filesystem/devfs/filesystem.tests.cpp | 37 +++++++++++----------- kernel/kernel/filesystem/ext2/filesystem.cpp | 16 ++++++---- kernel/kernel/filesystem/ext2/filesystem.hpp | 3 +- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 34 ++++++++++---------- kernel/kernel/filesystem/ext2/inode.tests.cpp | 10 +++--- kernel/kernel/filesystem/filesystem.cpp | 23 +++++--------- kernel/kernel/filesystem/filesystem.hpp | 15 +++------ kernel/kernel/filesystem/rootfs/filesystem.cpp | 7 ++-- kernel/kernel/filesystem/rootfs/filesystem.hpp | 3 +- .../kernel/filesystem/rootfs/filesystem.tests.cpp | 11 +++---- kernel/kernel/filesystem/vfs.cpp | 37 ++++++++++++---------- kernel/kernel/filesystem/vfs.hpp | 6 ++-- .../kernel/test_support/filesystem/filesystem.cpp | 6 ++++ .../kernel/test_support/filesystem/filesystem.hpp | 3 ++ 16 files changed, 118 insertions(+), 102 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 92756a65..5d8ef7f2 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -48,7 +48,8 @@ namespace kernel::filesystem::devfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result + auto filesystem::mount(kstd::shared_ptr const &) + -> kstd::result> { m_root_inode = kstd::make_shared(); @@ -61,7 +62,7 @@ namespace kernel::filesystem::devfs device_number_registry::get().subscribe(shared_from_this()); - return kstd::success(); + return m_root_inode; } auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 2b0221d0..accc8a49 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -30,7 +30,8 @@ namespace kernel::filesystem::devfs kstd::enable_shared_from_this, device_number_registry_observer { - auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result override; + auto mount(kstd::shared_ptr const & backing_inode) + -> kstd::result> override; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; @@ -46,6 +47,7 @@ namespace kernel::filesystem::devfs auto on_device_numbered(device_number_registry::entry const & numbered) -> void override; auto on_device_unnumbered(device_number_registry::entry const & numbered) -> void override; + kstd::shared_ptr m_root_inode{}; kstd::flat_map> m_inodes{}; }; } // namespace kernel::filesystem::devfs diff --git a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp index b5a07a22..7a0de2d9 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp @@ -25,39 +25,39 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, setup_modules(1); auto fs = kstd::make_shared(); - auto result = fs->mount(nullptr); + auto root = fs->mount(nullptr); THEN("mount succeeds") { - REQUIRE(result); - REQUIRE(fs->root_inode()); + REQUIRE(root); } THEN("lookup on root finds ram0 device inode") { - auto inode = fs->lookup(fs->root_inode(), "ram0"); + auto inode = fs->lookup(*root, "ram0"); REQUIRE(inode); REQUIRE(inode.value()->is_device()); } THEN("lookup of an unknown device returns error") { - auto inode = fs->lookup(fs->root_inode(), "ram99"); + auto inode = fs->lookup(*root, "ram99"); REQUIRE(!inode); } THEN("lookup with wrong parent returns error") { auto other_fs = kstd::make_shared(); - CHECK(other_fs->mount(nullptr)); + auto other_root = other_fs->mount(nullptr); + CHECK(other_root); - auto inode = fs->lookup(other_fs->root_inode(), "ram0"); + auto inode = fs->lookup(*other_root, "ram0"); REQUIRE(!inode); } THEN("lookup with a non-directory parent returns error") { - auto non_directory_inode = fs->lookup(fs->root_inode(), "ram0"); + auto non_directory_inode = fs->lookup(*root, "ram0"); REQUIRE(non_directory_inode); REQUIRE_FALSE(non_directory_inode.value()->is_directory()); @@ -67,7 +67,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("create_inode always returns an error") { - auto result = fs->create_inode(fs->root_inode(), "new_device", kapi::filesystem::file_type::regular); + auto result = fs->create_inode(*root, "new_device", kapi::filesystem::file_type::regular); REQUIRE(!result); } } @@ -77,14 +77,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, setup_modules(3, 2048); auto fs = kstd::make_shared(); - auto result = fs->mount(nullptr); - REQUIRE(result); + auto root = fs->mount(nullptr); + REQUIRE(root); THEN("lookup finds all generated RAM devices") { - REQUIRE(fs->lookup(fs->root_inode(), "ram0")); - REQUIRE(fs->lookup(fs->root_inode(), "ram1")); - REQUIRE(fs->lookup(fs->root_inode(), "ram2")); + REQUIRE(fs->lookup(*root, "ram0")); + REQUIRE(fs->lookup(*root, "ram1")); + REQUIRE(fs->lookup(*root, "ram2")); } } } @@ -94,12 +94,13 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") GIVEN("A mounted devfs, and a bus attached to the root without a device attached") { auto fs = kstd::make_shared(); - REQUIRE(fs->mount(nullptr)); + auto root = fs->mount(nullptr); + REQUIRE(root); auto bus = kstd::make_shared("devfs_live_update_bus"); kapi::devices::get_root_bus()->add_child(bus); - REQUIRE_FALSE(fs->lookup(fs->root_inode(), "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(*root, "devfs_live_update_device_node")); WHEN("a device is attached, bound, and published") { @@ -112,7 +113,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs finds it immediately") { - REQUIRE(fs->lookup(fs->root_inode(), "devfs_live_update_device_node")); + REQUIRE(fs->lookup(*root, "devfs_live_update_device_node")); } WHEN("the device is detached") @@ -121,7 +122,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs does not find it anymore") { - REQUIRE_FALSE(fs->lookup(fs->root_inode(), "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(*root, "devfs_live_update_device_node")); } } } diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index fcccad8f..c5808a60 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include using namespace kstd::units_literals; @@ -106,9 +105,10 @@ namespace kernel::filesystem::ext2 }; } - auto filesystem::mount(kstd::shared_ptr const & backing_inode) -> kstd::result + auto filesystem::mount(kstd::shared_ptr const & backing_inode) + -> kstd::result> { - std::ignore = kernel::filesystem::filesystem::mount(backing_inode); + m_backing_inode = backing_inode; if (auto read_result = m_backing_inode->read(std::as_writable_bytes(std::span{&m_superblock, 1}), constants::superblock_offset); @@ -134,17 +134,19 @@ namespace kernel::filesystem::ext2 return kstd::failure(read_result.error()); } - if (auto root_inode = read_inode(constants::root_inode_number)) + auto root = read_inode(constants::root_inode_number); + + if (!root) { - m_root_inode = root_inode.value(); + return kstd::failure(root.error()); } - if (!m_root_inode || !m_root_inode->is_directory()) + if (!(*root)->is_directory()) { return kstd::failure(ext2_errc::invalid_root_inode); } - return {}; + return root; } auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index d70358fd..f53e74da 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -75,7 +75,8 @@ namespace kernel::filesystem::ext2 //! The Second Extended Filesystem (ext2) struct filesystem final : kernel::filesystem::filesystem { - auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result override; + auto mount(kstd::shared_ptr const & backing_inode) + -> kstd::result> override; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 51ba2f30..bf7c89ae 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -48,17 +48,18 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto dev_inode = kstd::make_shared(boot_device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto root = fs.mount(dev_inode); + REQUIRE(root); THEN("the root inode is available and is a directory") { - REQUIRE(fs.root_inode()); - REQUIRE(fs.root_inode()->is_directory()); + REQUIRE(*root); + REQUIRE((*root)->is_directory()); } THEN("lookup resolves known entries from the image") { - auto information = fs.lookup(fs.root_inode(), "information"); + auto information = fs.lookup(*root, "information"); REQUIRE(information); REQUIRE(information.value()->is_directory()); @@ -71,13 +72,13 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, { REQUIRE(!fs.lookup(nullptr, "information")); - auto information = fs.lookup(fs.root_inode(), "information"); + auto information = fs.lookup(*root, "information"); REQUIRE(information); auto info_1 = fs.lookup(*information, "info_1.txt"); REQUIRE(info_1); REQUIRE(!fs.lookup(*info_1, "anything")); - REQUIRE(!fs.lookup(fs.root_inode(), "does_not_exist")); + REQUIRE(!fs.lookup(*root, "does_not_exist")); } } } @@ -98,37 +99,38 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto dev_inode = kstd::make_shared(boot_device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode)); + auto root = fs.mount(dev_inode); + REQUIRE(root); THEN("a file can be created") { - auto lookup_result = fs.lookup(fs.root_inode(), "blub"); + auto lookup_result = fs.lookup(*root, "blub"); REQUIRE(!lookup_result); - auto new_inode = fs.create_inode(fs.root_inode(), "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(fs.root_inode(), "blub"); + lookup_result = fs.lookup(*root, "blub"); REQUIRE(lookup_result); } THEN("a directory can be created") { - auto lookup_result = fs.lookup(fs.root_inode(), "blub"); + auto lookup_result = fs.lookup(*root, "blub"); REQUIRE(!lookup_result); - auto new_directory = fs.create_inode(fs.root_inode(), "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(fs.root_inode(), "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(fs.root_inode(), "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); @@ -141,7 +143,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("a file can be created and written to") { - auto new_inode = fs.create_inode(fs.root_inode(), "blub", kapi::filesystem::file_type::regular); + auto new_inode = fs.create_inode(*root, "blub", kapi::filesystem::file_type::regular); REQUIRE(new_inode); auto buffer = @@ -160,7 +162,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("a symbolic link is not implemented yet") { - REQUIRE_THROWS_AS(fs.create_inode(fs.root_inode(), "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); } } diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 13e9d414..d110c16a 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -109,9 +109,10 @@ 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{}; - REQUIRE(fs.mount(dev_inode)); + auto root = fs.mount(dev_inode); + REQUIRE(root); - auto information = fs.lookup(fs.root_inode(), "information"); + auto information = fs.lookup(*root, "information"); REQUIRE(information); auto file = fs.lookup(*information, "info_1.txt"); REQUIRE(file); @@ -303,9 +304,10 @@ 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{}; - REQUIRE(fs.mount(dev_inode)); + auto root = fs.mount(dev_inode); + REQUIRE(root); - auto information = fs.lookup(fs.root_inode(), "information"); + auto information = fs.lookup(*root, "information"); REQUIRE(information); auto file = fs.lookup(*information, "info_1.txt"); REQUIRE(file); diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp index 84bbdef6..1d222888 100644 --- a/kernel/kernel/filesystem/filesystem.cpp +++ b/kernel/kernel/filesystem/filesystem.cpp @@ -8,11 +8,13 @@ #include #include +#include + namespace kernel::filesystem { auto filesystem::probe_and_mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> + -> kstd::result, kstd::shared_ptr>> { for (auto & type : type_registry::get().all()) { @@ -22,27 +24,18 @@ namespace kernel::filesystem } auto fs = type->make_instance(); - - if (fs->mount(backing_inode)) + auto root = fs->mount(backing_inode); + if (!root) { - return fs; + continue; } + + return std::pair{fs, *root}; } return kstd::failure(vfs_errc::unsupported_filesystem); } - auto filesystem::mount(kstd::shared_ptr const & backing_inode) -> kstd::result - { - m_backing_inode = backing_inode; - return kstd::success(); - } - - auto filesystem::root_inode() const -> kstd::shared_ptr const & - { - return m_root_inode; - } - auto filesystem::backing_inode() const -> kstd::shared_ptr const & { return m_backing_inode; diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index 1a66c11c..f18422b2 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace kernel::filesystem { @@ -29,9 +30,9 @@ namespace kernel::filesystem //! @warning This function panics if @p backing_inode is null. //! //! @param backing_inode The inode to probe and mount. - //! @return A pointer to the mounted filesystem instance on success, an error otherwise. + //! @return A pointer to the mounted filesystem and the root of it on success, an error otherwise. auto static probe_and_mount(kstd::shared_ptr const & backing_inode) - -> kstd::result>; + -> kstd::result, kstd::shared_ptr>>; //! Initializes the filesystem with the given inode. //! @@ -39,8 +40,8 @@ namespace kernel::filesystem //! filesystem data (e.g. a file on an already mounted filesystem). //! //! @param backing_inode The inode to use as the backing inode for the filesystem. - //! @return Nothing on success, and error otherwise. - virtual auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result; + //! @return The root inode of the mounted filesystem on success, and error otherwise. + virtual auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result> = 0; //! Find a child inode below the given parent inode with the specified name. //! @@ -65,18 +66,12 @@ namespace kernel::filesystem std::optional raw_device = std::nullopt) -> kstd::result> = 0; - //! Get the root inode of the file system. - //! - //! @return A reference to the root inode. - [[nodiscard]] auto root_inode() const -> kstd::shared_ptr const &; - //! Get the backing inode of the file system. //! //! @return A reference to the backing inode. [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; protected: - kstd::shared_ptr m_root_inode{}; kstd::shared_ptr m_backing_inode{}; }; diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index cccfa63c..e7a05d55 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -45,10 +45,11 @@ namespace kernel::filesystem::rootfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result + auto filesystem::mount(kstd::shared_ptr const &) + -> kstd::result> { - m_root_inode = kstd::make_shared(); - return kstd::success(); + auto root = kstd::make_shared(); + return root; } auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 2a861747..5a2a93c0 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -25,7 +25,8 @@ namespace kernel::filesystem::rootfs struct filesystem : kernel::filesystem::filesystem { //! @copydoc kernel::filesystem::filesystem::mount - auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result override; + auto mount(kstd::shared_ptr const & backing_inode) + -> kstd::result> override; //! @copydoc kernel::filesystem::filesystem::lookup. //! @return Always returns an error, as rootfs is always empty. diff --git a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp index ba1aab0e..cbf8f744 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp @@ -15,19 +15,18 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] GIVEN("a mounted rootfs filesystem") { auto fs = kernel::filesystem::rootfs::filesystem{}; - auto result = fs.mount(nullptr); + auto root = fs.mount(nullptr); THEN("the filesystem can be mounted successfully") { - REQUIRE(result); - REQUIRE(fs.root_inode()); + REQUIRE(root); } THEN("looking up a non-existent directory returns an error") { - auto non_existent_inode_1 = fs.lookup(fs.root_inode(), ""); + auto non_existent_inode_1 = fs.lookup(*root, ""); REQUIRE(!non_existent_inode_1); - auto non_existent_inode_2 = fs.lookup(fs.root_inode(), "nonexistent"); + auto non_existent_inode_2 = fs.lookup(*root, "nonexistent"); REQUIRE(!non_existent_inode_2); } @@ -39,7 +38,7 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] THEN("create_inode always returns an error") { - auto result = fs.create_inode(fs.root_inode(), "new_device", kapi::filesystem::file_type::directory); + auto result = fs.create_inode(*root, "new_device", kapi::filesystem::file_type::directory); REQUIRE(!result); } } diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 02c577f2..57ae6c70 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -60,12 +60,13 @@ namespace kernel::filesystem } auto root_fs = (*root_fs_descriptor)->make_instance(); - if (auto result = root_fs->mount(nullptr); !result) + auto root_fs_root_inode = root_fs->mount(nullptr); + if (!root_fs_root_inode) { - kapi::system::panic("[FILESYSTEM] failed to mount root FS", result.error()); + kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_fs_root_inode.error()); } - auto root_fs_root_dentry = kstd::make_shared(nullptr, root_fs->root_inode(), "/"); + auto root_fs_root_dentry = kstd::make_shared(nullptr, *root_fs_root_inode, "/"); auto root_mount = kstd::make_shared(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr); m_mount_table.add_mount(root_mount); @@ -77,23 +78,26 @@ namespace kernel::filesystem } auto device_fs = (*device_fs_descriptor)->make_instance(); - if (auto result = device_fs->mount(nullptr); !result) + auto device_fs_root_inode = device_fs->mount(nullptr); + if (!device_fs_root_inode) { - kapi::system::panic("[FILESYSTEM] failed to mount device FS", result.error()); + kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_root_inode.error()); } - graft_persistent_device_fs(device_fs); + graft_persistent_device_fs(device_fs, *device_fs_root_inode); // mount boot fs at / (shadows rootfs), re-graft devfs auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { - if (auto boot_root_fs = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode())) + if (auto result = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode())) { + auto [boot_root_fs, boot_root_fs_root_inode] = *result; + if (auto root_dentry = resolve_path("/")) { - do_mount_internal(*root_dentry, root_mount, *boot_root_fs, boot_device_mount_context); - graft_persistent_device_fs(device_fs); + do_mount_internal(*root_dentry, root_mount, boot_root_fs, boot_root_fs_root_inode, boot_device_mount_context); + graft_persistent_device_fs(device_fs, *device_fs_root_inode); } } } @@ -183,7 +187,8 @@ namespace kernel::filesystem return kstd::failure(fs.error()); } - do_mount_internal(mount_point_dentry, mount_context, *fs, source_mount_context); + auto [filesystem, root_inode] = *fs; + do_mount_internal(mount_point_dentry, mount_context, filesystem, root_inode, source_mount_context); return kstd::success(); } @@ -295,15 +300,15 @@ namespace kernel::filesystem } auto vfs::do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, - mount_ptr const & source_mount) -> void + kstd::shared_ptr const & root_inode, mount_ptr const & source_mount) -> void { - auto new_fs_root = - kstd::make_shared(mount_point_dentry->parent(), fs->root_inode(), mount_point_dentry->name()); + auto new_fs_root = kstd::make_shared(mount_point_dentry->parent(), root_inode, mount_point_dentry->name()); auto new_mount = kstd::make_shared(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount); m_mount_table.add_mount(new_mount); } - auto vfs::graft_persistent_device_fs(kstd::shared_ptr const & device_fs) -> void + auto vfs::graft_persistent_device_fs(kstd::shared_ptr const & device_fs, + kstd::shared_ptr const & root_inode) -> void { auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/").value_or(std::pair{nullptr, nullptr}); if (root_mount_point_dentry && root_mount) @@ -311,11 +316,11 @@ namespace kernel::filesystem auto dev_dentry = root_mount_point_dentry->find_child("dev"); if (!dev_dentry) { - dev_dentry = kstd::make_shared(root_mount_point_dentry, device_fs->root_inode(), "dev"); + dev_dentry = kstd::make_shared(root_mount_point_dentry, root_inode, "dev"); root_mount_point_dentry->add_child(dev_dentry); } - do_mount_internal(dev_dentry, root_mount, device_fs); + do_mount_internal(dev_dentry, root_mount, device_fs, root_inode); } } diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index 2f30539b..0f29608c 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -112,9 +112,11 @@ namespace kernel::filesystem [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::result; auto do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, - mount_ptr const & source_mount = nullptr) -> void; + kstd::shared_ptr const & root_inode, mount_ptr const & source_mount = nullptr) + -> void; - auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs) -> void; + auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs, + kstd::shared_ptr const & root_inode) -> void; auto create_inode(std::string_view path, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) -> kstd::result; diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index cd08f961..51ce1e9f 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -14,6 +14,12 @@ namespace kernel::tests::filesystem { + auto filesystem::mount(kstd::shared_ptr const &) + -> kstd::result> + { + return kstd::make_shared(); + } + auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const -> kstd::result> { diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index 7aa14a9f..fa03f176 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -19,6 +19,9 @@ namespace kernel::tests::filesystem { filesystem() = default; + auto mount(kstd::shared_ptr const & backing_inode) + -> kstd::result> override; + [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; -- cgit v1.2.3 From 528fdc5cc26cd16dc889a11fdc994ae6b0e08e37 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Aug 2026 22:35:11 +0200 Subject: kernel/fs: introduce mount factory --- kernel/kernel/filesystem/filesystem.cpp | 13 ++---- kernel/kernel/filesystem/filesystem.hpp | 12 ++---- kernel/kernel/filesystem/mount.cpp | 36 ++++++++++++++++ kernel/kernel/filesystem/mount.hpp | 33 ++++++++++++-- kernel/kernel/filesystem/mount.tests.cpp | 59 +++++++++++++------------- kernel/kernel/filesystem/mount_table.tests.cpp | 40 ++++++++--------- kernel/kernel/filesystem/vfs.cpp | 38 +++++++++-------- kernel/kernel/filesystem/vfs.hpp | 4 -- 8 files changed, 142 insertions(+), 93 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp index 1d222888..362c4d1e 100644 --- a/kernel/kernel/filesystem/filesystem.cpp +++ b/kernel/kernel/filesystem/filesystem.cpp @@ -8,13 +8,10 @@ #include #include -#include - namespace kernel::filesystem { - auto filesystem::probe_and_mount(kstd::shared_ptr const & backing_inode) - -> kstd::result, kstd::shared_ptr>> + auto filesystem::probe(kstd::shared_ptr const & backing_inode) -> kstd::result> { for (auto & type : type_registry::get().all()) { @@ -23,14 +20,10 @@ namespace kernel::filesystem continue; } - auto fs = type->make_instance(); - auto root = fs->mount(backing_inode); - if (!root) + if (auto fs = type->make_instance()) { - continue; + return fs; } - - return std::pair{fs, *root}; } return kstd::failure(vfs_errc::unsupported_filesystem); diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index f18422b2..dccc9434 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -12,7 +12,6 @@ #include #include -#include namespace kernel::filesystem { @@ -25,14 +24,11 @@ namespace kernel::filesystem //! Virtual destructor enabling polymorphic destruction. virtual ~filesystem() = default; - //! Probes the given inode to determine if it contains a recognizable filesystem, and if so, mount it. + //! Probes the given inode to determine if it contains a recognizable filesystem. //! - //! @warning This function panics if @p backing_inode is null. - //! - //! @param backing_inode The inode to probe and mount. - //! @return A pointer to the mounted filesystem and the root of it on success, an error otherwise. - auto static probe_and_mount(kstd::shared_ptr const & backing_inode) - -> kstd::result, kstd::shared_ptr>>; + //! @param backing_inode The inode to probe and mount, if any. + //! @return A pointer to the instantiated filesystem and the root of it on success, an error otherwise. + auto static probe(kstd::shared_ptr const & backing_inode) -> kstd::result>; //! Initializes the filesystem with the given inode. //! diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index 009ab230..b1335735 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -29,6 +30,41 @@ namespace kernel::filesystem } } + auto mount::attach(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, + kstd::shared_ptr const & root_inode, kstd::shared_ptr const & parent_mount, + kstd::shared_ptr const & source_mount) -> kstd::shared_ptr + { + auto root_dentry = mount_dentry + ? kstd::make_shared(mount_dentry->parent(), root_inode, mount_dentry->name()) + : kstd::make_shared(nullptr, root_inode, "/"); + + auto instance = kstd::shared_ptr{ + new mount{mount_dentry, root_dentry, fs, parent_mount, source_mount} + }; + + root_inode->set_owning_mount(instance); + + return instance; + } + + auto mount::create(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, + kstd::shared_ptr const & parent_mount, kstd::shared_ptr const & source_mount, + kstd::shared_ptr const & backing_inode) -> kstd::result> + { + if (!fs) + { + kapi::system::panic("[OS:FS] Tried to mount a null filesystem!"); + } + + auto root_inode = fs->mount(backing_inode); + if (!root_inode) + { + return kstd::failure(root_inode.error()); + } + + return attach(mount_dentry, fs, *root_inode, parent_mount, source_mount); + } + auto mount::mount_dentry() const -> kstd::shared_ptr const & { return m_mount_dentry; diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index b906def5..c07de071 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -12,19 +13,32 @@ namespace kernel::filesystem { + struct inode; + //! A mounted filesystem struct mount { + //! Attach a mounted filesystem with a known root inode + //! + //! @param mount_dentry The directory entry where the filesystem is mounted. + //! @param fs The filesystem instance being mounted. + //! @param root_inode The backing inode for the filesystem, must not be null. + //! @param parent_mount The parent mount which contains the mount_dentry. + //! @param source_mount The mount that the filesystem originates from. + auto static attach(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, + kstd::shared_ptr const & root_inode, kstd::shared_ptr const & parent_mount, + kstd::shared_ptr const & source_mount) -> kstd::shared_ptr; + //! Create a new mount with the given parameters. //! //! @param mount_dentry The directory entry where the filesystem is mounted. - //! @param root_dentry The root directory entry of the mounted filesystem. //! @param fs The filesystem instance being mounted. //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. - mount(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & root_dentry, - kstd::shared_ptr const & fs, kstd::shared_ptr const & parent_mount, - kstd::shared_ptr const & source_mount); + //! @param backing_inode The backing inode for the filesystem, if any. + auto static create(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, + kstd::shared_ptr const & parent_mount, kstd::shared_ptr const & source_mount, + kstd::shared_ptr const & backing_inode) -> kstd::result>; //! Get the directory entry where the filesystem is mounted. [[nodiscard]] auto mount_dentry() const -> kstd::shared_ptr const &; @@ -63,6 +77,17 @@ namespace kernel::filesystem [[nodiscard]] auto ref_count() const -> size_t; private: + //! Create a new mount with the given parameters. + //! + //! @param mount_dentry The directory entry where the filesystem is mounted. + //! @param root_dentry The root directory entry of the mounted filesystem. + //! @param fs The filesystem instance being mounted. + //! @param parent_mount The parent mount which contains the mount_dentry. + //! @param source_mount The mount that the filesystem originates from. + mount(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & root_dentry, + kstd::shared_ptr const & fs, kstd::shared_ptr const & parent_mount, + kstd::shared_ptr const & source_mount); + kstd::shared_ptr m_mount_dentry{}; kstd::shared_ptr m_root_dentry{}; kstd::shared_ptr m_filesystem{}; diff --git a/kernel/kernel/filesystem/mount.tests.cpp b/kernel/kernel/filesystem/mount.tests.cpp index 800a0cfc..3337a172 100644 --- a/kernel/kernel/filesystem/mount.tests.cpp +++ b/kernel/kernel/filesystem/mount.tests.cpp @@ -15,29 +15,29 @@ SCENARIO("Mount construction", "[filesystem][mount]") { - GIVEN("a filesystem and a root dentry") + GIVEN("a filesystem and a root inode") { auto fs = kstd::make_shared(); auto root_inode = kstd::make_shared(); - auto root_dentry = kstd::make_shared(nullptr, root_inode, "/"); - WHEN("constructing a mount with the filesystem and root dentry") + WHEN("attaching a mount with no mount point") { - auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; + auto mount = kernel::filesystem::mount::attach(nullptr, fs, root_inode, nullptr, nullptr); THEN("the mount has the correct filesystem, root dentry, mount dentry, and mount path") { - REQUIRE(mount.get_filesystem() == fs); - REQUIRE(mount.root_dentry() == root_dentry); - REQUIRE(mount.mount_dentry() == root_dentry); - REQUIRE(mount.mount_path() == "/"); - REQUIRE(mount.is_ready_to_unmount()); + REQUIRE(mount->get_filesystem() == fs); + REQUIRE(mount->root_dentry()->get_inode() == root_inode); + REQUIRE(mount->root_dentry()->name() == "/"); + REQUIRE(mount->mount_dentry() == nullptr); + REQUIRE(mount->mount_path() == "/"); + REQUIRE(mount->is_ready_to_unmount()); } THEN("the mount has no parent mount and no source mount") { - REQUIRE(mount.parent_mount() == nullptr); - REQUIRE(mount.source_mount() == nullptr); + REQUIRE(mount->parent_mount() == nullptr); + REQUIRE(mount->source_mount() == nullptr); } } @@ -45,7 +45,7 @@ SCENARIO("Mount construction", "[filesystem][mount]") { THEN("the constructor panics") { - REQUIRE_THROWS_AS((kernel::filesystem::mount{root_dentry, root_dentry, nullptr, nullptr, nullptr}), + REQUIRE_THROWS_AS((kernel::filesystem::mount::create(nullptr, nullptr, nullptr, nullptr, nullptr)), kernel::tests::cpu::halt); } } @@ -63,32 +63,33 @@ SCENARIO("Mount reference counting", "[filesystem][mount]") THEN("reference count can be incremented and decremented, the mount is ready to unmount when the reference " "count == 0") { - auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; + auto mount = kernel::filesystem::mount::create(root_dentry, fs, nullptr, nullptr, nullptr); + REQUIRE(mount); - mount.increment_ref_count(); - REQUIRE(mount.ref_count() == 1); - REQUIRE_FALSE(mount.is_ready_to_unmount()); + (*mount)->increment_ref_count(); + REQUIRE((*mount)->ref_count() == 1); + REQUIRE_FALSE((*mount)->is_ready_to_unmount()); - mount.increment_ref_count(); - REQUIRE(mount.ref_count() == 2); - REQUIRE_FALSE(mount.is_ready_to_unmount()); + (*mount)->increment_ref_count(); + REQUIRE((*mount)->ref_count() == 2); + REQUIRE_FALSE((*mount)->is_ready_to_unmount()); - mount.decrement_ref_count(); - REQUIRE(mount.ref_count() == 1); - REQUIRE_FALSE(mount.is_ready_to_unmount()); + (*mount)->decrement_ref_count(); + REQUIRE((*mount)->ref_count() == 1); + REQUIRE_FALSE((*mount)->is_ready_to_unmount()); - mount.decrement_ref_count(); - REQUIRE(mount.ref_count() == 0); - REQUIRE(mount.is_ready_to_unmount()); + (*mount)->decrement_ref_count(); + REQUIRE((*mount)->ref_count() == 0); + REQUIRE((*mount)->is_ready_to_unmount()); } THEN("decrementing reference count when it is already zero does not decrement it below zero") { - auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; + auto mount = kernel::filesystem::mount::create(root_dentry, fs, nullptr, nullptr, nullptr); - REQUIRE_THROWS_AS(mount.decrement_ref_count(), std::runtime_error); - REQUIRE(mount.ref_count() == 0); - REQUIRE(mount.is_ready_to_unmount()); + REQUIRE_THROWS_AS((*mount)->decrement_ref_count(), std::runtime_error); + REQUIRE((*mount)->ref_count() == 0); + REQUIRE((*mount)->is_ready_to_unmount()); } } } \ No newline at end of file diff --git a/kernel/kernel/filesystem/mount_table.tests.cpp b/kernel/kernel/filesystem/mount_table.tests.cpp index 39ad6b01..bed6cd9d 100644 --- a/kernel/kernel/filesystem/mount_table.tests.cpp +++ b/kernel/kernel/filesystem/mount_table.tests.cpp @@ -38,17 +38,17 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared(), "/"); auto mount_dentry1 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); - auto mount1 = kstd::make_shared(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); + auto mount1 = kernel::filesystem::mount::create(mount_dentry1, fs1, nullptr, nullptr, nullptr); auto fs2 = kstd::make_shared(); auto root_dentry2 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); auto mount_dentry2 = kstd::make_shared( nullptr, kstd::make_shared(), "/mnt"); - auto mount2 = kstd::make_shared(mount_dentry2, root_dentry2, fs2, nullptr, nullptr); + auto mount2 = kernel::filesystem::mount::create(mount_dentry2, fs2, nullptr, nullptr, nullptr); - table.add_mount(mount1); - table.add_mount(mount2); + table.add_mount(*mount1); + table.add_mount(*mount2); THEN("dentry flags are set correctly for mounted dentries") { @@ -89,17 +89,17 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared(), "/"); auto mount_dentry1 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); - auto mount1 = kstd::make_shared(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); + auto mount1 = kernel::filesystem::mount::create(mount_dentry1, fs1, nullptr, nullptr, nullptr); auto fs2 = kstd::make_shared(); auto root_dentry2 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); auto mount_dentry2 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); - auto mount2 = kstd::make_shared(mount_dentry2, root_dentry2, fs2, nullptr, nullptr); + auto mount2 = kernel::filesystem::mount::create(mount_dentry2, fs2, nullptr, nullptr, nullptr); - table.add_mount(mount1); - table.add_mount(mount2); + table.add_mount(*mount1); + table.add_mount(*mount2); THEN("finding mounts by exact valid path returns the correct mount") { @@ -122,25 +122,25 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared(), "/"); auto mount_dentry1 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); - auto mount1 = kstd::make_shared(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); + auto mount1 = kernel::filesystem::mount::create(mount_dentry1, fs1, nullptr, nullptr, nullptr); auto fs2 = kstd::make_shared(); auto root_dentry2 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); auto mount_dentry2 = kstd::make_shared( mount_dentry1, kstd::make_shared(), "mnt"); - auto mount2 = kstd::make_shared(mount_dentry2, root_dentry2, fs2, mount1, nullptr); + auto mount2 = kernel::filesystem::mount::create(mount_dentry2, fs2, *mount1, nullptr, nullptr); auto fs3 = kstd::make_shared(); auto root_dentry3 = kstd::make_shared( nullptr, kstd::make_shared(), "/"); auto mount_dentry3 = kstd::make_shared( mount_dentry2, kstd::make_shared(), "submnt"); - auto mount3 = kstd::make_shared(mount_dentry3, root_dentry3, fs3, mount2, nullptr); + auto mount3 = kernel::filesystem::mount::create(mount_dentry3, fs3, *mount2, nullptr, nullptr); - table.add_mount(mount1); - table.add_mount(mount2); - table.add_mount(mount3); + table.add_mount(*mount1); + table.add_mount(*mount2); + table.add_mount(*mount3); THEN("removing a mount with child mounts returns has_child_mounts") { @@ -166,19 +166,19 @@ SCENARIO("Mount reference counting", "[filesystem][mount_table]") auto root_inode = kstd::make_shared(); auto root_dentry = kstd::make_shared(nullptr, root_inode, "/"); - auto source_mount = kstd::make_shared(root_dentry, root_dentry, fs, nullptr, nullptr); - auto mount = kstd::make_shared(root_dentry, root_dentry, fs, nullptr, source_mount); + auto source_mount = kernel::filesystem::mount::create(root_dentry, fs, nullptr, nullptr, nullptr); + auto mount = kernel::filesystem::mount::create(root_dentry, fs, nullptr, *source_mount, nullptr); THEN("reference count of source mount is incremented when a mount is added to the mount table and decremented when " "the mount is removed") { - REQUIRE(source_mount->ref_count() == 0); + REQUIRE((*source_mount)->ref_count() == 0); - table.add_mount(mount); - REQUIRE(source_mount->ref_count() == 1); + table.add_mount(*mount); + REQUIRE((*source_mount)->ref_count() == 1); REQUIRE(table.remove_mount("/") == kernel::filesystem::mount_table::operation_result::removed); - REQUIRE(source_mount->ref_count() == 0); + REQUIRE((*source_mount)->ref_count() == 0); } } } diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 57ae6c70..21ac3752 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -66,8 +66,7 @@ namespace kernel::filesystem kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_fs_root_inode.error()); } - auto root_fs_root_dentry = kstd::make_shared(nullptr, *root_fs_root_inode, "/"); - auto root_mount = kstd::make_shared(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr); + auto root_mount = mount::attach(nullptr, root_fs, *root_fs_root_inode, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) @@ -90,13 +89,17 @@ namespace kernel::filesystem resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { - if (auto result = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode())) + if (auto result = kernel::filesystem::filesystem::probe(boot_device_dentry->get_inode())) { - auto [boot_root_fs, boot_root_fs_root_inode] = *result; - if (auto root_dentry = resolve_path("/")) { - do_mount_internal(*root_dentry, root_mount, boot_root_fs, boot_root_fs_root_inode, boot_device_mount_context); + auto mount = mount::create(*root_dentry, *result, root_mount, boot_device_mount_context, + boot_device_dentry->get_inode()); + if (!mount) + { + kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); + } + m_mount_table.add_mount(*mount); graft_persistent_device_fs(device_fs, *device_fs_root_inode); } } @@ -181,14 +184,20 @@ namespace kernel::filesystem } auto [source_dentry, source_mount_context] = *resolved_source; - auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode()); + auto fs = kernel::filesystem::filesystem::probe(source_dentry->get_inode()); if (!fs) { return kstd::failure(fs.error()); } - auto [filesystem, root_inode] = *fs; - do_mount_internal(mount_point_dentry, mount_context, filesystem, root_inode, source_mount_context); + auto mount = + mount::create(mount_point_dentry, *fs, mount_context, source_mount_context, source_dentry->get_inode()); + if (!mount) + { + return kstd::failure(mount.error()); + } + m_mount_table.add_mount(*mount); + return kstd::success(); } @@ -299,14 +308,6 @@ namespace kernel::filesystem return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto vfs::do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, - kstd::shared_ptr const & root_inode, mount_ptr const & source_mount) -> void - { - auto new_fs_root = kstd::make_shared(mount_point_dentry->parent(), root_inode, mount_point_dentry->name()); - auto new_mount = kstd::make_shared(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount); - m_mount_table.add_mount(new_mount); - } - auto vfs::graft_persistent_device_fs(kstd::shared_ptr const & device_fs, kstd::shared_ptr const & root_inode) -> void { @@ -320,7 +321,8 @@ namespace kernel::filesystem root_mount_point_dentry->add_child(dev_dentry); } - do_mount_internal(dev_dentry, root_mount, device_fs, root_inode); + auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, root_mount, nullptr); + m_mount_table.add_mount(new_mount); } } diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index 0f29608c..1975ac8a 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -111,10 +111,6 @@ namespace kernel::filesystem [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::result; - auto do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, - kstd::shared_ptr const & root_inode, mount_ptr const & source_mount = nullptr) - -> void; - auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs, kstd::shared_ptr const & root_inode) -> void; -- cgit v1.2.3 From f3183a93826b1dabe4a446c2d834eae7de06b3e0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 12:59:11 +0200 Subject: kernel/fs: remove backing inode from base --- kernel/kernel/filesystem/ext2/filesystem.cpp | 5 +++++ kernel/kernel/filesystem/ext2/filesystem.hpp | 6 ++++++ kernel/kernel/filesystem/filesystem.cpp | 4 ---- kernel/kernel/filesystem/filesystem.hpp | 8 -------- 4 files changed, 11 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index c5808a60..c6180fe1 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -725,6 +725,11 @@ namespace kernel::filesystem::ext2 return kstd::success(); } + auto filesystem::backing_inode() const -> kstd::shared_ptr const & + { + return m_backing_inode; + } + auto filesystem::read_block(uint32_t block_number, void * buffer) const -> kstd::result { auto const block_offset = static_cast(block_number) * block_size(); diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index f53e74da..23629928 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -155,6 +155,11 @@ namespace kernel::filesystem::ext2 auto write_global_block_number_to_inode_block_index(size_t block_index, inode_data & data, uint32_t global_block_number) -> kstd::result; + //! Get the backing inode of the file system. + //! + //! @return A reference to the backing inode. + [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; + private: struct indirect_level { @@ -192,6 +197,7 @@ namespace kernel::filesystem::ext2 superblock m_superblock{}; kstd::vector m_block_group_descriptors; + kstd::shared_ptr m_backing_inode; }; } // namespace kernel::filesystem::ext2 diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp index 362c4d1e..d2e3adde 100644 --- a/kernel/kernel/filesystem/filesystem.cpp +++ b/kernel/kernel/filesystem/filesystem.cpp @@ -29,8 +29,4 @@ namespace kernel::filesystem return kstd::failure(vfs_errc::unsupported_filesystem); } - auto filesystem::backing_inode() const -> kstd::shared_ptr const & - { - return m_backing_inode; - } } // namespace kernel::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index dccc9434..cae36967 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -61,14 +61,6 @@ namespace kernel::filesystem kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) -> kstd::result> = 0; - - //! Get the backing inode of the file system. - //! - //! @return A reference to the backing inode. - [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; - - protected: - kstd::shared_ptr m_backing_inode{}; }; } // namespace kernel::filesystem -- cgit v1.2.3 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(-) (limited to 'kernel') 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 From c1678823d808932c065942e9aa0f7d7fe0246b8a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 14:30:33 +0200 Subject: kernel/fs: add backing inode to mount --- kernel/kernel/filesystem/ext2/inode.cpp | 41 +++++++++++++++++++++++++++++---- kernel/kernel/filesystem/ext2/inode.hpp | 4 ++++ kernel/kernel/filesystem/mount.cpp | 10 +++++++- kernel/kernel/filesystem/mount.hpp | 4 ++++ 4 files changed, 53 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 5e80f40b..7059527a 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -67,10 +67,16 @@ namespace kernel::filesystem::ext2 } else { + auto inode = backing_inode(); + if (!inode) + { + return kstd::failure(inode.error()); + } + 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 = - (*filesystem)->backing_inode()->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); + + auto const read_result = (*inode)->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); if (!read_result) { return kstd::failure(read_result.error()); @@ -140,9 +146,14 @@ namespace kernel::filesystem::ext2 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 = (*filesystem) - ->backing_inode() - ->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); + auto inode = backing_inode(); + if (!inode) + { + return kstd::failure(inode.error()); + } + + auto const write_result = + (*inode)->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); if (!write_result) { return kstd::failure(write_result.error()); @@ -318,4 +329,24 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } + auto inode::backing_inode() -> kstd::result> + { + if (auto mount = owning_mount().lock()) + { + return mount->backing_inode(); + } + + return kstd::failure(vfs_errc::not_mounted); + } + + auto inode::backing_inode() const -> kstd::result> + { + if (auto mount = owning_mount().lock()) + { + return mount->backing_inode(); + } + + 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 41231cab..cae1d801 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -105,6 +105,10 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto get_filesystem() const -> kstd::result>; + [[nodiscard]] auto backing_inode() -> kstd::result>; + + [[nodiscard]] auto backing_inode() const -> kstd::result>; + //! The inode number on disk. uint32_t m_inode_number{}; //! The inode data. diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index b1335735..995c12c8 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -62,7 +62,10 @@ namespace kernel::filesystem return kstd::failure(root_inode.error()); } - return attach(mount_dentry, fs, *root_inode, parent_mount, source_mount); + auto instance = attach(mount_dentry, fs, *root_inode, parent_mount, source_mount); + instance->m_backing_inode = backing_inode; + + return instance; } auto mount::mount_dentry() const -> kstd::shared_ptr const & @@ -75,6 +78,11 @@ namespace kernel::filesystem return m_filesystem; } + auto mount::backing_inode() const -> kstd::shared_ptr const & + { + return m_backing_inode; + } + auto mount::root_dentry() const -> kstd::shared_ptr const & { return m_root_dentry; diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index c07de071..d8d9c625 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -49,6 +49,9 @@ namespace kernel::filesystem //! Get the filesystem instance being mounted. [[nodiscard]] auto get_filesystem() const -> kstd::shared_ptr const &; + //! Get the backing inode, if any, of this mount. + [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; + //! Get the path at which the filesystem is mounted. [[nodiscard]] auto mount_path() const -> kstd::string; @@ -91,6 +94,7 @@ namespace kernel::filesystem kstd::shared_ptr m_mount_dentry{}; kstd::shared_ptr m_root_dentry{}; kstd::shared_ptr m_filesystem{}; + kstd::shared_ptr m_backing_inode{}; kstd::shared_ptr m_parent_mount{}; kstd::weak_ptr m_source_mount{}; std::atomic_size_t m_ref_count{0}; -- cgit v1.2.3 From f9877bcf8faf8a216bbe95d82c546581c093b3cb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 19:44:19 +0200 Subject: kernel/fs: ext2: let VFS associate the owning mount --- kernel/kernel/filesystem/ext2/filesystem.cpp | 11 ++++------- kernel/kernel/filesystem/ext2/filesystem.hpp | 3 +-- kernel/kernel/filesystem/ext2/inode.tests.cpp | 4 ++++ 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 58d24fc1..115f6028 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, nullptr); + auto root = read_inode(constants::root_inode_number); 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, ext2_parent->owning_mount().lock()); + return read_inode(entry->inode); } bytes_read += kstd::bytes{entry->rec_len}; @@ -395,8 +395,7 @@ namespace kernel::filesystem::ext2 kstd::libc::memcpy(entry->name.data(), name.data(), name_len); } - auto filesystem::read_inode(uint32_t inode_number, kstd::shared_ptr const & mount) const - -> kstd::result> + auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result> { if (auto inode_offset = calculate_inode_offset(inode_number)) { @@ -409,9 +408,7 @@ namespace kernel::filesystem::ext2 } else { - auto inode = kstd::make_shared(inode_number, new_inode_data); - inode->set_owning_mount(mount); - return inode; + return kstd::make_shared(inode_number, new_inode_data); } } else diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 2f9d0d58..23629928 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -178,8 +178,7 @@ 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, kstd::shared_ptr const & mount) const - -> kstd::result>; + [[nodiscard]] auto read_inode(uint32_t inode_number) 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/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index ecfc76ba..48af4d75 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -112,6 +112,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in REQUIRE(file); REQUIRE(file.value()->is_regular()); + (*file)->set_owning_mount(*mount); + THEN("reading from offset zero returns expected file prefix") { auto buffer = kstd::vector(6); @@ -320,6 +322,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in REQUIRE(file); REQUIRE(file.value()->is_regular()); + (*file)->set_owning_mount(*mount); + THEN("writing to the inode updates backing device and the inode size") { auto write_buffer = kstd::vector{std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, -- cgit v1.2.3 From 0967e2140eca2caa8dc4c3412218c6f593878471 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 20:06:20 +0200 Subject: kernel/fs: clean up API --- kernel/kernel/filesystem/dentry.cpp | 5 ++- kernel/kernel/filesystem/dentry.hpp | 17 +++++---- kernel/kernel/filesystem/dentry.tests.cpp | 4 +- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 4 +- kernel/kernel/filesystem/ext2/inode.cpp | 4 +- kernel/kernel/filesystem/ext2/inode.tests.cpp | 18 ++++----- kernel/kernel/filesystem/mount.cpp | 29 +++++++------- kernel/kernel/filesystem/mount.hpp | 44 +++++++++++----------- kernel/kernel/filesystem/mount.tests.cpp | 4 +- kernel/kernel/filesystem/open_file_descriptor.cpp | 6 +-- kernel/kernel/filesystem/vfs.cpp | 29 +++++++------- kernel/kernel/filesystem/vfs.tests.cpp | 4 +- 12 files changed, 86 insertions(+), 82 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/dentry.cpp b/kernel/kernel/filesystem/dentry.cpp index 9321453a..e82c5419 100644 --- a/kernel/kernel/filesystem/dentry.cpp +++ b/kernel/kernel/filesystem/dentry.cpp @@ -13,7 +13,8 @@ namespace kernel::filesystem { - dentry::dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & inode, std::string_view name) + dentry::dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & inode, + std::string_view name) : m_name(name) , m_parent(parent) , m_inode(inode) @@ -29,7 +30,7 @@ namespace kernel::filesystem } } - auto dentry::get_inode() const -> kstd::shared_ptr const & + auto dentry::inode() const -> kstd::shared_ptr const & { return m_inode; } diff --git a/kernel/kernel/filesystem/dentry.hpp b/kernel/kernel/filesystem/dentry.hpp index a33ff22d..f7897764 100644 --- a/kernel/kernel/filesystem/dentry.hpp +++ b/kernel/kernel/filesystem/dentry.hpp @@ -15,6 +15,9 @@ namespace kernel::filesystem //! A directory entry in the filesystem. struct dentry { + using dentry_ptr = kstd::shared_ptr; + using inode_ptr = kstd::shared_ptr; + //! Flags for the dentry. enum class dentry_flags : uint32_t { @@ -28,17 +31,17 @@ namespace kernel::filesystem //! @param parent The parent directory entry, if any. //! @param inode The associated inode for this dentry. //! @param name The name of the dentry. - dentry(kstd::shared_ptr const & parent, kstd::shared_ptr const & inode, std::string_view name); + dentry(dentry_ptr const & parent, inode_ptr const & inode, std::string_view name); //! Get this entrys associated inode. //! //! @return The inode associated with this directory entry. - [[nodiscard]] auto get_inode() const -> kstd::shared_ptr const &; + [[nodiscard]] auto inode() const -> inode_ptr const &; //! Get this entrys parent directory entry. //! //! @return The parent directory entry, or @p nullptr if this entry has no parent. - [[nodiscard]] auto parent() const -> kstd::shared_ptr; + [[nodiscard]] auto parent() const -> dentry_ptr; //! Get this entrys name. //! @@ -56,7 +59,7 @@ namespace kernel::filesystem //! Add a child to this entry. //! //! @param child The child directory entry to add. - auto add_child(kstd::shared_ptr const & child) -> void; + auto add_child(dentry_ptr const & child) -> void; //! Find a child entry with the given name. //! @@ -65,7 +68,7 @@ namespace kernel::filesystem //! //! @param name The name of the child directory entry to find. //! @return A pointer to the child dentry if it exists, a null pointer otherwise. - [[nodiscard]] auto find_child(std::string_view name) const -> kstd::shared_ptr; + [[nodiscard]] auto find_child(std::string_view name) const -> dentry_ptr; //! Set a flag for this entry. //! @@ -86,8 +89,8 @@ namespace kernel::filesystem private: kstd::string m_name; kstd::weak_ptr m_parent; - kstd::vector> m_children; - kstd::shared_ptr m_inode; + kstd::vector m_children; + inode_ptr m_inode; uint32_t m_flags; }; } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/dentry.tests.cpp b/kernel/kernel/filesystem/dentry.tests.cpp index 55cdf21e..cf3915de 100644 --- a/kernel/kernel/filesystem/dentry.tests.cpp +++ b/kernel/kernel/filesystem/dentry.tests.cpp @@ -22,7 +22,7 @@ SCENARIO("Dentry construction", "[filesystem][dentry]") THEN("the dentry has the correct parent, inode, and name") { REQUIRE(child_dentry.parent() == parent_dentry); - REQUIRE(child_dentry.get_inode() == inode); + REQUIRE(child_dentry.inode() == inode); REQUIRE(child_dentry.name() == "child"); } @@ -47,7 +47,7 @@ SCENARIO("Dentry construction", "[filesystem][dentry]") THEN("the dentry has a null parent, the correct inode, and the correct name") { REQUIRE(child_dentry.parent() == nullptr); - REQUIRE(child_dentry.get_inode() == inode); + REQUIRE(child_dentry.inode() == inode); REQUIRE(child_dentry.name() == "child"); } diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 5feea017..708f83df 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -50,7 +50,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); THEN("the root inode is available and is a directory") @@ -102,7 +102,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); THEN("a file can be created") diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 7059527a..b04be99a 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -313,7 +313,7 @@ namespace kernel::filesystem::ext2 { if (auto mount = owning_mount().lock()) { - return static_pointer_cast(mount->get_filesystem()); + return static_pointer_cast(mount->filesystem()); } return kstd::failure(vfs_errc::not_mounted); @@ -323,7 +323,7 @@ namespace kernel::filesystem::ext2 { if (auto mount = owning_mount().lock()) { - return static_pointer_cast(mount->get_filesystem()); + return static_pointer_cast(mount->filesystem()); } return kstd::failure(vfs_errc::not_mounted); diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 48af4d75..9a602a28 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -103,7 +103,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto information = fs->lookup(root, "information"); @@ -149,7 +149,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; @@ -190,7 +190,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; @@ -238,7 +238,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; @@ -272,7 +272,7 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][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(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto inode_data = kernel::filesystem::ext2::inode_data{}; @@ -313,7 +313,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto information = fs->lookup(root, "information"); @@ -409,7 +409,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][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(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto inode_data = kernel::filesystem::ext2::inode_data{}; @@ -548,7 +548,7 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; @@ -594,7 +594,7 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); - auto root = (*mount)->root_dentry()->get_inode(); + auto root = (*mount)->root_dentry()->inode(); REQUIRE(mount); auto data = kernel::filesystem::ext2::inode_data{}; diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index 995c12c8..2f0e0d58 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -14,9 +14,8 @@ namespace kernel::filesystem { - mount::mount(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & root_dentry, - kstd::shared_ptr const & fs, kstd::shared_ptr const & parent_mount, - kstd::shared_ptr const & source_mount) + mount::mount(dentry_ptr const & mount_dentry, dentry_ptr const & root_dentry, filesystem_ptr const & fs, + mount_ptr const & parent_mount, mount_ptr const & source_mount) : m_mount_dentry(mount_dentry) , m_root_dentry(root_dentry) , m_filesystem(fs) @@ -30,15 +29,15 @@ namespace kernel::filesystem } } - auto mount::attach(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, - kstd::shared_ptr const & root_inode, kstd::shared_ptr const & parent_mount, - kstd::shared_ptr const & source_mount) -> kstd::shared_ptr + auto mount::attach(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, + kstd::shared_ptr const & root_inode, mount_ptr const & parent_mount, + mount_ptr const & source_mount) -> mount_ptr { auto root_dentry = mount_dentry ? kstd::make_shared(mount_dentry->parent(), root_inode, mount_dentry->name()) : kstd::make_shared(nullptr, root_inode, "/"); - auto instance = kstd::shared_ptr{ + auto instance = mount_ptr{ new mount{mount_dentry, root_dentry, fs, parent_mount, source_mount} }; @@ -47,9 +46,9 @@ namespace kernel::filesystem return instance; } - auto mount::create(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, - kstd::shared_ptr const & parent_mount, kstd::shared_ptr const & source_mount, - kstd::shared_ptr const & backing_inode) -> kstd::result> + auto mount::create(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, mount_ptr const & parent_mount, + mount_ptr const & source_mount, kstd::shared_ptr const & backing_inode) + -> kstd::result { if (!fs) { @@ -68,12 +67,12 @@ namespace kernel::filesystem return instance; } - auto mount::mount_dentry() const -> kstd::shared_ptr const & + auto mount::mount_dentry() const -> dentry_ptr const & { return m_mount_dentry; } - auto mount::get_filesystem() const -> kstd::shared_ptr const & + auto mount::filesystem() const -> filesystem_ptr const & { return m_filesystem; } @@ -83,7 +82,7 @@ namespace kernel::filesystem return m_backing_inode; } - auto mount::root_dentry() const -> kstd::shared_ptr const & + auto mount::root_dentry() const -> dentry_ptr const & { return m_root_dentry; } @@ -97,12 +96,12 @@ namespace kernel::filesystem return "/"; } - auto mount::parent_mount() const -> kstd::shared_ptr const & + auto mount::parent_mount() const -> mount_ptr const & { return m_parent_mount; } - auto mount::source_mount() const -> kstd::shared_ptr + auto mount::source_mount() const -> mount_ptr { return m_source_mount.lock(); } diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index d8d9c625..ac6dae21 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -18,6 +18,11 @@ namespace kernel::filesystem //! A mounted filesystem struct mount { + using dentry_ptr = kstd::shared_ptr; + using filesystem_ptr = kstd::shared_ptr; + using mount_ptr = kstd::shared_ptr; + using inode_ptr = kstd::shared_ptr; + //! Attach a mounted filesystem with a known root inode //! //! @param mount_dentry The directory entry where the filesystem is mounted. @@ -25,9 +30,8 @@ namespace kernel::filesystem //! @param root_inode The backing inode for the filesystem, must not be null. //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. - auto static attach(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, - kstd::shared_ptr const & root_inode, kstd::shared_ptr const & parent_mount, - kstd::shared_ptr const & source_mount) -> kstd::shared_ptr; + auto static attach(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, inode_ptr const & root_inode, + mount_ptr const & parent_mount, mount_ptr const & source_mount) -> mount_ptr; //! Create a new mount with the given parameters. //! @@ -36,30 +40,29 @@ namespace kernel::filesystem //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. //! @param backing_inode The backing inode for the filesystem, if any. - auto static create(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & fs, - kstd::shared_ptr const & parent_mount, kstd::shared_ptr const & source_mount, - kstd::shared_ptr const & backing_inode) -> kstd::result>; + auto static create(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, mount_ptr const & parent_mount, + mount_ptr const & source_mount, inode_ptr const & backing_inode) -> kstd::result; //! Get the directory entry where the filesystem is mounted. - [[nodiscard]] auto mount_dentry() const -> kstd::shared_ptr const &; + [[nodiscard]] auto mount_dentry() const -> dentry_ptr const &; //! Get the root directory entry of the mounted filesystem. - [[nodiscard]] auto root_dentry() const -> kstd::shared_ptr const &; + [[nodiscard]] auto root_dentry() const -> dentry_ptr const &; //! Get the filesystem instance being mounted. - [[nodiscard]] auto get_filesystem() const -> kstd::shared_ptr const &; + [[nodiscard]] auto filesystem() const -> filesystem_ptr const &; //! Get the backing inode, if any, of this mount. - [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; + [[nodiscard]] auto backing_inode() const -> inode_ptr const &; //! Get the path at which the filesystem is mounted. [[nodiscard]] auto mount_path() const -> kstd::string; //! Get the parent mount that this mount was attached beneath. - [[nodiscard]] auto parent_mount() const -> kstd::shared_ptr const &; + [[nodiscard]] auto parent_mount() const -> mount_ptr const &; //! Get the source mount where this mount originates from. - [[nodiscard]] auto source_mount() const -> kstd::shared_ptr; + [[nodiscard]] auto source_mount() const -> mount_ptr; //! Increment the reference count for this mount. auto increment_ref_count() -> void; @@ -87,15 +90,14 @@ namespace kernel::filesystem //! @param fs The filesystem instance being mounted. //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. - mount(kstd::shared_ptr const & mount_dentry, kstd::shared_ptr const & root_dentry, - kstd::shared_ptr const & fs, kstd::shared_ptr const & parent_mount, - kstd::shared_ptr const & source_mount); - - kstd::shared_ptr m_mount_dentry{}; - kstd::shared_ptr m_root_dentry{}; - kstd::shared_ptr m_filesystem{}; - kstd::shared_ptr m_backing_inode{}; - kstd::shared_ptr m_parent_mount{}; + mount(dentry_ptr const & mount_dentry, dentry_ptr const & root_dentry, filesystem_ptr const & fs, + mount_ptr const & parent_mount, mount_ptr const & source_mount); + + dentry_ptr m_mount_dentry{}; + dentry_ptr m_root_dentry{}; + filesystem_ptr m_filesystem{}; + inode_ptr m_backing_inode{}; + mount_ptr m_parent_mount{}; kstd::weak_ptr m_source_mount{}; std::atomic_size_t m_ref_count{0}; }; diff --git a/kernel/kernel/filesystem/mount.tests.cpp b/kernel/kernel/filesystem/mount.tests.cpp index 3337a172..2c67a7cb 100644 --- a/kernel/kernel/filesystem/mount.tests.cpp +++ b/kernel/kernel/filesystem/mount.tests.cpp @@ -26,8 +26,8 @@ SCENARIO("Mount construction", "[filesystem][mount]") THEN("the mount has the correct filesystem, root dentry, mount dentry, and mount path") { - REQUIRE(mount->get_filesystem() == fs); - REQUIRE(mount->root_dentry()->get_inode() == root_inode); + REQUIRE(mount->filesystem() == fs); + REQUIRE(mount->root_dentry()->inode() == root_inode); REQUIRE(mount->root_dentry()->name() == "/"); REQUIRE(mount->mount_dentry() == nullptr); REQUIRE(mount->mount_path() == "/"); diff --git a/kernel/kernel/filesystem/open_file_descriptor.cpp b/kernel/kernel/filesystem/open_file_descriptor.cpp index 98520aa8..64c47461 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.cpp +++ b/kernel/kernel/filesystem/open_file_descriptor.cpp @@ -26,7 +26,7 @@ namespace kernel::filesystem auto open_file_descriptor::read(std::span buffer) -> kstd::result { - if (auto result = m_dentry->get_inode()->read(buffer, m_offset); !result) + if (auto result = m_dentry->inode()->read(buffer, m_offset); !result) { return kstd::failure(result.error()); } @@ -40,7 +40,7 @@ namespace kernel::filesystem auto open_file_descriptor::write(std::span buffer) -> kstd::result { - if (auto result = m_dentry->get_inode()->write(buffer, m_offset); !result) + if (auto result = m_dentry->inode()->write(buffer, m_offset); !result) { return kstd::failure(result.error()); } @@ -68,7 +68,7 @@ namespace kernel::filesystem } case kapi::filesystem::seek_origin::end: { - return m_dentry->get_inode()->status()->size; + return m_dentry->inode()->status()->size; } default: { diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 21ac3752..c39a28c4 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -89,12 +89,12 @@ namespace kernel::filesystem resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { - if (auto result = kernel::filesystem::filesystem::probe(boot_device_dentry->get_inode())) + if (auto result = kernel::filesystem::filesystem::probe(boot_device_dentry->inode())) { if (auto root_dentry = resolve_path("/")) { - auto mount = mount::create(*root_dentry, *result, root_mount, boot_device_mount_context, - boot_device_dentry->get_inode()); + auto mount = + mount::create(*root_dentry, *result, root_mount, boot_device_mount_context, boot_device_dentry->inode()); if (!mount) { kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); @@ -125,7 +125,7 @@ namespace kernel::filesystem } auto [dentry, mount] = resolved_path.value(); - auto inode = dentry->get_inode(); + auto inode = dentry->inode(); if (inode->is_device()) { @@ -184,14 +184,13 @@ namespace kernel::filesystem } auto [source_dentry, source_mount_context] = *resolved_source; - auto fs = kernel::filesystem::filesystem::probe(source_dentry->get_inode()); + auto fs = kernel::filesystem::filesystem::probe(source_dentry->inode()); if (!fs) { return kstd::failure(fs.error()); } - auto mount = - mount::create(mount_point_dentry, *fs, mount_context, source_mount_context, source_dentry->get_inode()); + auto mount = mount::create(mount_point_dentry, *fs, mount_context, source_mount_context, source_dentry->inode()); if (!mount) { return kstd::failure(mount.error()); @@ -247,7 +246,7 @@ namespace kernel::filesystem return kstd::failure(resolved.error()); } - return (*resolved)->get_inode()->status(); + return (*resolved)->inode()->status(); } auto vfs::create_device_node(std::string_view path, std::uint32_t mode, kapi::filesystem::device_number device) @@ -292,9 +291,9 @@ namespace kernel::filesystem auto [parent_dentry, mount_context] = *resolved_parent; - if (auto fs = mount_context->get_filesystem()) + if (auto fs = mount_context->filesystem()) { - if (auto new_inode = fs->create_inode(parent_dentry->get_inode(), name, type, raw_device)) + if (auto new_inode = fs->create_inode(parent_dentry->inode(), name, type, raw_device)) { (*new_inode)->set_owning_mount(mount_context); @@ -352,7 +351,7 @@ namespace kernel::filesystem auto part = path_parts_vector.back(); path_parts_vector.pop_back(); - if (!current_dentry->get_inode()->is_directory()) + if (!current_dentry->inode()->is_directory()) { return kstd::failure(vfs_errc::not_a_directory); } @@ -387,8 +386,8 @@ namespace kernel::filesystem auto next_dentry = current_dentry->find_child(part); if (!next_dentry) { - auto current_fs = current_mount->get_filesystem(); - auto found_inode = current_fs->lookup(current_dentry->get_inode(), part); + auto current_fs = current_mount->filesystem(); + auto found_inode = current_fs->lookup(current_dentry->inode(), part); if (!found_inode) { return kstd::failure(found_inode.error()); @@ -410,7 +409,7 @@ namespace kernel::filesystem next_dentry = current_mount->root_dentry(); } - if (next_dentry->get_inode()->is_symbolic_link()) + if (next_dentry->inode()->is_symbolic_link()) { if (symlink_counter++ > constants::symloop_max) { @@ -418,7 +417,7 @@ namespace kernel::filesystem } kstd::vector buffer(constants::symlink_max_path_length); - auto const bytes_read = next_dentry->get_inode()->read(buffer, 0_B); + auto const bytes_read = next_dentry->inode()->read(buffer, 0_B); if (!bytes_read) { return kstd::failure(bytes_read.error()); diff --git a/kernel/kernel/filesystem/vfs.tests.cpp b/kernel/kernel/filesystem/vfs.tests.cpp index a035e083..5b7ea621 100644 --- a/kernel/kernel/filesystem/vfs.tests.cpp +++ b/kernel/kernel/filesystem/vfs.tests.cpp @@ -665,11 +665,11 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS REQUIRE(via_persistent_fs != nullptr); auto marker = kstd::vector{std::byte{'M'}, std::byte{'K'}, std::byte{'N'}, std::byte{'O'}, std::byte{'D'}}; - auto written = (*via_persistent_fs)->get_inode()->write(marker, 0_B); + auto written = (*via_persistent_fs)->inode()->write(marker, 0_B); REQUIRE(written == kstd::bytes{marker.size()}); auto read_back = kstd::vector(marker.size()); - auto read = (*via_devfs)->get_inode()->read(read_back, 0_B); + auto read = (*via_devfs)->inode()->read(read_back, 0_B); REQUIRE(read == kstd::bytes{marker.size()}); REQUIRE(read_back == marker); -- cgit v1.2.3 From 9c32495771901e5a8a668aa45801c89daacd5ec4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 22 Aug 2026 22:32:32 +0200 Subject: kernel/fs: prepare for driver state extraction --- kernel/kernel/filesystem/devfs/filesystem.cpp | 5 ++--- kernel/kernel/filesystem/devfs/filesystem.hpp | 2 +- .../kernel/filesystem/devfs/filesystem.tests.cpp | 22 ++++++++++----------- kernel/kernel/filesystem/ext2/filesystem.cpp | 6 ++++-- kernel/kernel/filesystem/ext2/filesystem.hpp | 2 +- kernel/kernel/filesystem/ext2/mount_state.hpp | 23 ++++++++++++++++++++++ kernel/kernel/filesystem/filesystem.hpp | 5 ++++- kernel/kernel/filesystem/mount.cpp | 19 ++++++++++-------- kernel/kernel/filesystem/mount.hpp | 11 +++++++++-- kernel/kernel/filesystem/mount.tests.cpp | 2 +- kernel/kernel/filesystem/rootfs/filesystem.cpp | 5 ++--- kernel/kernel/filesystem/rootfs/filesystem.hpp | 2 +- .../kernel/filesystem/rootfs/filesystem.tests.cpp | 6 +++--- kernel/kernel/filesystem/vfs.cpp | 23 ++++++++++++---------- .../kernel/test_support/filesystem/filesystem.cpp | 6 +++--- .../kernel/test_support/filesystem/filesystem.hpp | 2 +- 16 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 kernel/kernel/filesystem/ext2/mount_state.hpp (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 5d8ef7f2..60d174fe 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -48,8 +48,7 @@ namespace kernel::filesystem::devfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) - -> kstd::result> + auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result { m_root_inode = kstd::make_shared(); @@ -62,7 +61,7 @@ namespace kernel::filesystem::devfs device_number_registry::get().subscribe(shared_from_this()); - return m_root_inode; + return mount_result{m_root_inode, nullptr}; } auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index accc8a49..875f3957 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -31,7 +31,7 @@ namespace kernel::filesystem::devfs device_number_registry_observer { auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> override; + -> kstd::result override; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; diff --git a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp index 7a0de2d9..20523b71 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp @@ -34,14 +34,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("lookup on root finds ram0 device inode") { - auto inode = fs->lookup(*root, "ram0"); + auto inode = fs->lookup(root->first, "ram0"); REQUIRE(inode); REQUIRE(inode.value()->is_device()); } THEN("lookup of an unknown device returns error") { - auto inode = fs->lookup(*root, "ram99"); + auto inode = fs->lookup(root->first, "ram99"); REQUIRE(!inode); } @@ -51,13 +51,13 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto other_root = other_fs->mount(nullptr); CHECK(other_root); - auto inode = fs->lookup(*other_root, "ram0"); + auto inode = fs->lookup(other_root->first, "ram0"); REQUIRE(!inode); } THEN("lookup with a non-directory parent returns error") { - auto non_directory_inode = fs->lookup(*root, "ram0"); + auto non_directory_inode = fs->lookup(root->first, "ram0"); REQUIRE(non_directory_inode); REQUIRE_FALSE(non_directory_inode.value()->is_directory()); @@ -67,7 +67,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("create_inode always returns an error") { - auto result = fs->create_inode(*root, "new_device", kapi::filesystem::file_type::regular); + auto result = fs->create_inode(root->first, "new_device", kapi::filesystem::file_type::regular); REQUIRE(!result); } } @@ -82,9 +82,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("lookup finds all generated RAM devices") { - REQUIRE(fs->lookup(*root, "ram0")); - REQUIRE(fs->lookup(*root, "ram1")); - REQUIRE(fs->lookup(*root, "ram2")); + REQUIRE(fs->lookup(root->first, "ram0")); + REQUIRE(fs->lookup(root->first, "ram1")); + REQUIRE(fs->lookup(root->first, "ram2")); } } } @@ -100,7 +100,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") auto bus = kstd::make_shared("devfs_live_update_bus"); kapi::devices::get_root_bus()->add_child(bus); - REQUIRE_FALSE(fs->lookup(*root, "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(root->first, "devfs_live_update_device_node")); WHEN("a device is attached, bound, and published") { @@ -113,7 +113,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs finds it immediately") { - REQUIRE(fs->lookup(*root, "devfs_live_update_device_node")); + REQUIRE(fs->lookup(root->first, "devfs_live_update_device_node")); } WHEN("the device is detached") @@ -122,7 +122,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs does not find it anymore") { - REQUIRE_FALSE(fs->lookup(*root, "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(root->first, "devfs_live_update_device_node")); } } } diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 115f6028..a0a0dbf1 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,7 @@ namespace kernel::filesystem::ext2 } auto filesystem::mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> + -> kstd::result { m_backing_inode = backing_inode; @@ -146,7 +147,8 @@ namespace kernel::filesystem::ext2 return kstd::failure(ext2_errc::invalid_root_inode); } - return root; + return mount_result{*root, + kstd::make_shared(m_superblock, m_block_group_descriptors, m_backing_inode)}; } auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 23629928..fd304c00 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -76,7 +76,7 @@ namespace kernel::filesystem::ext2 struct filesystem final : kernel::filesystem::filesystem { auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> override; + -> kstd::result override; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; diff --git a/kernel/kernel/filesystem/ext2/mount_state.hpp b/kernel/kernel/filesystem/ext2/mount_state.hpp new file mode 100644 index 00000000..b9c2d5f7 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/mount_state.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_MOUNT_STATE_HPP +#define TEACHOS_KERNEL_FILESYSTEM_EXT2_MOUNT_STATE_HPP + +#include +#include +#include + +#include +#include + +namespace kernel::filesystem::ext2 +{ + + struct mount_state + { + struct superblock superblock; + kstd::vector block_group_descriptors; + kstd::shared_ptr backing_inode; + }; + +} // namespace kernel::filesystem::ext2 + +#endif \ No newline at end of file diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index cae36967..83f9b54d 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace kernel::filesystem { @@ -21,6 +22,8 @@ namespace kernel::filesystem //! Filesystem implementations must derive from this class. struct filesystem { + using mount_result = std::pair, kstd::shared_ptr>; + //! Virtual destructor enabling polymorphic destruction. virtual ~filesystem() = default; @@ -37,7 +40,7 @@ namespace kernel::filesystem //! //! @param backing_inode The inode to use as the backing inode for the filesystem. //! @return The root inode of the mounted filesystem on success, and error otherwise. - virtual auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result> = 0; + virtual auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result = 0; //! Find a child inode below the given parent inode with the specified name. //! diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index 2f0e0d58..d808ff52 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -15,12 +15,13 @@ namespace kernel::filesystem { mount::mount(dentry_ptr const & mount_dentry, dentry_ptr const & root_dentry, filesystem_ptr const & fs, - mount_ptr const & parent_mount, mount_ptr const & source_mount) + mount_ptr const & parent_mount, mount_ptr const & source_mount, kstd::shared_ptr driver_data) : m_mount_dentry(mount_dentry) , m_root_dentry(root_dentry) , m_filesystem(fs) , m_parent_mount(parent_mount) , m_source_mount(source_mount) + , m_driver_data(driver_data) , m_ref_count(0) { if (!m_filesystem) @@ -30,15 +31,15 @@ namespace kernel::filesystem } auto mount::attach(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, - kstd::shared_ptr const & root_inode, mount_ptr const & parent_mount, - mount_ptr const & source_mount) -> mount_ptr + kstd::shared_ptr const & root_inode, kstd::shared_ptr driver_data, + mount_ptr const & parent_mount, mount_ptr const & source_mount) -> mount_ptr { auto root_dentry = mount_dentry ? kstd::make_shared(mount_dentry->parent(), root_inode, mount_dentry->name()) : kstd::make_shared(nullptr, root_inode, "/"); auto instance = mount_ptr{ - new mount{mount_dentry, root_dentry, fs, parent_mount, source_mount} + new mount{mount_dentry, root_dentry, fs, parent_mount, source_mount, driver_data} }; root_inode->set_owning_mount(instance); @@ -55,13 +56,15 @@ namespace kernel::filesystem kapi::system::panic("[OS:FS] Tried to mount a null filesystem!"); } - auto root_inode = fs->mount(backing_inode); - if (!root_inode) + auto mount_result = fs->mount(backing_inode); + if (!mount_result) { - return kstd::failure(root_inode.error()); + return kstd::failure(mount_result.error()); } - auto instance = attach(mount_dentry, fs, *root_inode, parent_mount, source_mount); + auto [root_inode, driver_data] = *mount_result; + + auto instance = attach(mount_dentry, fs, root_inode, driver_data, parent_mount, source_mount); instance->m_backing_inode = backing_inode; return instance; diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index ac6dae21..e8d9cf6a 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -28,10 +28,12 @@ namespace kernel::filesystem //! @param mount_dentry The directory entry where the filesystem is mounted. //! @param fs The filesystem instance being mounted. //! @param root_inode The backing inode for the filesystem, must not be null. + //! @param driver_data The filesystem specific driver data. //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. auto static attach(dentry_ptr const & mount_dentry, filesystem_ptr const & fs, inode_ptr const & root_inode, - mount_ptr const & parent_mount, mount_ptr const & source_mount) -> mount_ptr; + kstd::shared_ptr driver_data, mount_ptr const & parent_mount, + mount_ptr const & source_mount) -> mount_ptr; //! Create a new mount with the given parameters. //! @@ -64,6 +66,9 @@ namespace kernel::filesystem //! Get the source mount where this mount originates from. [[nodiscard]] auto source_mount() const -> mount_ptr; + //! Get the data of the attached filesystem driver. + [[nodiscard]] auto driver_data() const -> kstd::shared_ptr; + //! Increment the reference count for this mount. auto increment_ref_count() -> void; @@ -90,8 +95,9 @@ namespace kernel::filesystem //! @param fs The filesystem instance being mounted. //! @param parent_mount The parent mount which contains the mount_dentry. //! @param source_mount The mount that the filesystem originates from. + //! @param driver_data The driver specific state data. mount(dentry_ptr const & mount_dentry, dentry_ptr const & root_dentry, filesystem_ptr const & fs, - mount_ptr const & parent_mount, mount_ptr const & source_mount); + mount_ptr const & parent_mount, mount_ptr const & source_mount, kstd::shared_ptr driver_data); dentry_ptr m_mount_dentry{}; dentry_ptr m_root_dentry{}; @@ -99,6 +105,7 @@ namespace kernel::filesystem inode_ptr m_backing_inode{}; mount_ptr m_parent_mount{}; kstd::weak_ptr m_source_mount{}; + kstd::shared_ptr m_driver_data{}; std::atomic_size_t m_ref_count{0}; }; } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/mount.tests.cpp b/kernel/kernel/filesystem/mount.tests.cpp index 2c67a7cb..a77134e5 100644 --- a/kernel/kernel/filesystem/mount.tests.cpp +++ b/kernel/kernel/filesystem/mount.tests.cpp @@ -22,7 +22,7 @@ SCENARIO("Mount construction", "[filesystem][mount]") WHEN("attaching a mount with no mount point") { - auto mount = kernel::filesystem::mount::attach(nullptr, fs, root_inode, nullptr, nullptr); + auto mount = kernel::filesystem::mount::attach(nullptr, fs, root_inode, nullptr, nullptr, nullptr); THEN("the mount has the correct filesystem, root dentry, mount dentry, and mount path") { diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index e7a05d55..298e8c94 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -45,11 +45,10 @@ namespace kernel::filesystem::rootfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) - -> kstd::result> + auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result { auto root = kstd::make_shared(); - return root; + return mount_result{root, nullptr}; } auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 5a2a93c0..9f609106 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -26,7 +26,7 @@ namespace kernel::filesystem::rootfs { //! @copydoc kernel::filesystem::filesystem::mount auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> override; + -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::lookup. //! @return Always returns an error, as rootfs is always empty. diff --git a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp index cbf8f744..b4297582 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp @@ -24,9 +24,9 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] THEN("looking up a non-existent directory returns an error") { - auto non_existent_inode_1 = fs.lookup(*root, ""); + auto non_existent_inode_1 = fs.lookup(root->first, ""); REQUIRE(!non_existent_inode_1); - auto non_existent_inode_2 = fs.lookup(*root, "nonexistent"); + auto non_existent_inode_2 = fs.lookup(root->first, "nonexistent"); REQUIRE(!non_existent_inode_2); } @@ -38,7 +38,7 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] THEN("create_inode always returns an error") { - auto result = fs.create_inode(*root, "new_device", kapi::filesystem::file_type::directory); + auto result = fs.create_inode(root->first, "new_device", kapi::filesystem::file_type::directory); REQUIRE(!result); } } diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index c39a28c4..6a15d211 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -60,13 +60,15 @@ namespace kernel::filesystem } auto root_fs = (*root_fs_descriptor)->make_instance(); - auto root_fs_root_inode = root_fs->mount(nullptr); - if (!root_fs_root_inode) + auto root_mount_result = root_fs->mount(nullptr); + if (!root_mount_result) { - kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_fs_root_inode.error()); + kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_mount_result.error()); } - auto root_mount = mount::attach(nullptr, root_fs, *root_fs_root_inode, nullptr, nullptr); + auto [root_inode, root_state] = *root_mount_result; + + auto root_mount = mount::attach(nullptr, root_fs, root_inode, root_state, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) @@ -77,12 +79,13 @@ namespace kernel::filesystem } auto device_fs = (*device_fs_descriptor)->make_instance(); - auto device_fs_root_inode = device_fs->mount(nullptr); - if (!device_fs_root_inode) + auto device_fs_mount_result = device_fs->mount(nullptr); + if (!device_fs_mount_result) { - kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_root_inode.error()); + kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_mount_result.error()); } - graft_persistent_device_fs(device_fs, *device_fs_root_inode); + + graft_persistent_device_fs(device_fs, device_fs_mount_result->first); // mount boot fs at / (shadows rootfs), re-graft devfs auto [boot_device_dentry, boot_device_mount_context] = @@ -100,7 +103,7 @@ namespace kernel::filesystem kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); } m_mount_table.add_mount(*mount); - graft_persistent_device_fs(device_fs, *device_fs_root_inode); + graft_persistent_device_fs(device_fs, device_fs_mount_result->first); } } } @@ -320,7 +323,7 @@ namespace kernel::filesystem root_mount_point_dentry->add_child(dev_dentry); } - auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, root_mount, nullptr); + auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, nullptr, root_mount, nullptr); m_mount_table.add_mount(new_mount); } } diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 51ce1e9f..8bd46e3c 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -11,13 +11,13 @@ #include #include +#include namespace kernel::tests::filesystem { - auto filesystem::mount(kstd::shared_ptr const &) - -> kstd::result> + auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result { - return kstd::make_shared(); + return std::pair{kstd::make_shared(), nullptr}; } auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index fa03f176..d7f64883 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -20,7 +20,7 @@ namespace kernel::tests::filesystem filesystem() = default; auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result> override; + -> kstd::result override; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; -- cgit v1.2.3 From 27cdaef9c79d154630b63adce6b227de370e75dd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 09:38:06 +0200 Subject: kernel/fs: extract convenience aliases --- kernel/kernel/filesystem/devfs/filesystem.cpp | 14 ++++++-------- kernel/kernel/filesystem/devfs/filesystem.hpp | 14 ++++++-------- kernel/kernel/filesystem/ext2/filesystem.hpp | 19 ++++++++----------- kernel/kernel/filesystem/filesystem.hpp | 15 +++++++++------ kernel/kernel/filesystem/rootfs/filesystem.cpp | 15 ++++++--------- kernel/kernel/filesystem/rootfs/filesystem.hpp | 12 +++++------- 6 files changed, 40 insertions(+), 49 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 60d174fe..cc42a5bd 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -29,7 +29,7 @@ namespace kernel::filesystem::devfs return "devfs"; } - [[nodiscard]] auto probe(kstd::shared_ptr const & backing_inode) const noexcept + [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept -> kstd::result override { if (backing_inode) @@ -39,7 +39,7 @@ namespace kernel::filesystem::devfs return 0; } - [[nodiscard]] auto make_instance() const -> kstd::shared_ptr override + [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared(); } @@ -48,7 +48,7 @@ namespace kernel::filesystem::devfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result + auto filesystem::mount(inode_ptr const &) -> kstd::result { m_root_inode = kstd::make_shared(); @@ -64,8 +64,7 @@ namespace kernel::filesystem::devfs return mount_result{m_root_inode, nullptr}; } - auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> + auto filesystem::lookup(inode_ptr const & parent, std::string_view name) const -> kstd::result { if (!parent) { @@ -91,9 +90,8 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, - kapi::filesystem::file_type, std::optional) - -> kstd::result> + auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, + std::optional) -> kstd::result { return kstd::failure(vfs_errc::read_only_file_system); } diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 875f3957..f176a367 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -30,24 +30,22 @@ namespace kernel::filesystem::devfs kstd::enable_shared_from_this, device_number_registry_observer { - auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result override; + auto mount(inode_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const + -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode //! @return Always returns an error, as creating new inodes is not supported in devfs. - [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, + [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) - -> kstd::result> override; + -> kstd::result override; private: auto on_device_numbered(device_number_registry::entry const & numbered) -> void override; auto on_device_unnumbered(device_number_registry::entry const & numbered) -> void override; - kstd::shared_ptr m_root_inode{}; + inode_ptr m_root_inode{}; kstd::flat_map> m_inodes{}; }; } // namespace kernel::filesystem::devfs diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index fd304c00..1f7fe8af 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -75,16 +75,14 @@ namespace kernel::filesystem::ext2 //! The Second Extended Filesystem (ext2) struct filesystem final : kernel::filesystem::filesystem { - auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result override; + auto mount(inode_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const + -> kstd::result override; - [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, + [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) - -> kstd::result> override; + -> kstd::result override; //! Get the size of a block in the filesystem. //! @@ -158,7 +156,7 @@ namespace kernel::filesystem::ext2 //! Get the backing inode of the file system. //! //! @return A reference to the backing inode. - [[nodiscard]] auto backing_inode() const -> kstd::shared_ptr const &; + [[nodiscard]] auto backing_inode() const -> inode_ptr const &; private: struct indirect_level @@ -172,8 +170,7 @@ namespace kernel::filesystem::ext2 auto allocate_inode() -> kstd::result; auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode) -> kstd::result; - auto init_directory(kstd::shared_ptr const & new_inode, - kernel::filesystem::ext2::inode * parent_inode) -> kstd::result; + auto init_directory(kstd::shared_ptr const & new_inode, inode * parent_inode) -> kstd::result; 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; @@ -197,7 +194,7 @@ namespace kernel::filesystem::ext2 superblock m_superblock{}; kstd::vector m_block_group_descriptors; - kstd::shared_ptr m_backing_inode; + inode_ptr m_backing_inode; }; } // namespace kernel::filesystem::ext2 diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index 83f9b54d..f1b39bd4 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -22,7 +22,10 @@ namespace kernel::filesystem //! Filesystem implementations must derive from this class. struct filesystem { - using mount_result = std::pair, kstd::shared_ptr>; + using filesystem_ptr = kstd::shared_ptr; + using driver_data_ptr = kstd::shared_ptr; + using inode_ptr = kstd::shared_ptr; + using mount_result = std::pair; //! Virtual destructor enabling polymorphic destruction. virtual ~filesystem() = default; @@ -31,7 +34,7 @@ namespace kernel::filesystem //! //! @param backing_inode The inode to probe and mount, if any. //! @return A pointer to the instantiated filesystem and the root of it on success, an error otherwise. - auto static probe(kstd::shared_ptr const & backing_inode) -> kstd::result>; + auto static probe(inode_ptr const & backing_inode) -> kstd::result; //! Initializes the filesystem with the given inode. //! @@ -40,7 +43,7 @@ namespace kernel::filesystem //! //! @param backing_inode The inode to use as the backing inode for the filesystem. //! @return The root inode of the mounted filesystem on success, and error otherwise. - virtual auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result = 0; + virtual auto mount(inode_ptr const & backing_inode) -> kstd::result = 0; //! Find a child inode below the given parent inode with the specified name. //! @@ -50,8 +53,8 @@ namespace kernel::filesystem //! @param parent The parent inode. //! @param name The name of the child inode to look up. //! @return A pointer to the requested child inode on success, an error otherwise. - [[nodiscard]] virtual auto lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> = 0; + [[nodiscard]] virtual auto lookup(inode_ptr const & parent, std::string_view name) const + -> kstd::result = 0; //! Create a new inode with the given name below a given parent inode. //! @@ -60,7 +63,7 @@ namespace kernel::filesystem //! @param type The file type of inode to be created. //! @param raw_device The device number the new inode should represent, if any. //! @return A pointer to the created inode on success, an error otherwise. - [[nodiscard]] virtual auto create_inode(kstd::shared_ptr const & parent, std::string_view name, + [[nodiscard]] virtual auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) -> kstd::result> = 0; diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index 298e8c94..147d967a 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -25,7 +24,7 @@ namespace kernel::filesystem::rootfs return "rootfs"; } - [[nodiscard]] auto probe(kstd::shared_ptr const & backing_inode) const noexcept + [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept -> kstd::result override { if (backing_inode) @@ -36,7 +35,7 @@ namespace kernel::filesystem::rootfs return 0; } - [[nodiscard]] auto make_instance() const -> kstd::shared_ptr override + [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared(); } @@ -45,21 +44,19 @@ namespace kernel::filesystem::rootfs [[gnu::used]] constexpr auto registration = type_registration{}; - auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result + auto filesystem::mount(inode_ptr const &) -> kstd::result { auto root = kstd::make_shared(); return mount_result{root, nullptr}; } - auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const - -> kstd::result> + auto filesystem::lookup(inode_ptr const &, std::string_view) const -> kstd::result { return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, - kapi::filesystem::file_type, std::optional) - -> kstd::result> + auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, + std::optional) -> kstd::result { return kstd::failure(vfs_errc::read_only_file_system); } diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 9f609106..5a72ff42 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -25,20 +25,18 @@ namespace kernel::filesystem::rootfs struct filesystem : kernel::filesystem::filesystem { //! @copydoc kernel::filesystem::filesystem::mount - auto mount(kstd::shared_ptr const & backing_inode) - -> kstd::result override; + auto mount(inode_ptr const & backing_inode) -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::lookup. //! @return Always returns an error, as rootfs is always empty. - [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const + -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode. //! @return Always returns an error, as creating new inodes is not supported in rootfs. - [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, + [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) - -> kstd::result> override; + -> kstd::result override; }; } // namespace kernel::filesystem::rootfs -- cgit v1.2.3 From f3d7fc902e2e1000dd202859cad892f821b98380 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 12:50:15 +0200 Subject: kernel/fs: thread driver data through public API --- kernel/kernel/filesystem/devfs/filesystem.cpp | 5 +-- kernel/kernel/filesystem/devfs/filesystem.hpp | 5 +-- kernel/kernel/filesystem/error.cpp | 3 ++ kernel/kernel/filesystem/error.hpp | 1 + kernel/kernel/filesystem/ext2/filesystem.cpp | 29 ++++++++++------ kernel/kernel/filesystem/ext2/filesystem.hpp | 3 +- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 39 ++++++++++++---------- kernel/kernel/filesystem/ext2/inode.tests.cpp | 10 +++--- kernel/kernel/filesystem/filesystem.hpp | 8 +++-- kernel/kernel/filesystem/mount.cpp | 5 +++ kernel/kernel/filesystem/rootfs/filesystem.cpp | 4 +-- kernel/kernel/filesystem/rootfs/filesystem.hpp | 5 +-- kernel/kernel/filesystem/vfs.cpp | 5 +-- .../kernel/test_support/filesystem/filesystem.cpp | 10 +++--- .../kernel/test_support/filesystem/filesystem.hpp | 9 ++--- 15 files changed, 85 insertions(+), 56 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index cc42a5bd..3e94f2ac 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -64,7 +64,8 @@ namespace kernel::filesystem::devfs return mount_result{m_root_inode, nullptr}; } - auto filesystem::lookup(inode_ptr const & parent, std::string_view name) const -> kstd::result + auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr) const + -> kstd::result { if (!parent) { @@ -90,7 +91,7 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, + auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, driver_data_ptr, std::optional) -> kstd::result { return kstd::failure(vfs_errc::read_only_file_system); diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index f176a367..12ac7e83 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -32,12 +32,13 @@ namespace kernel::filesystem::devfs { auto mount(inode_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const - -> kstd::result override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, + driver_data_ptr driver_data = nullptr) const -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode //! @return Always returns an error, as creating new inodes is not supported in devfs. [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, + driver_data_ptr driver_data = nullptr, std::optional raw_device = std::nullopt) -> kstd::result override; diff --git a/kernel/kernel/filesystem/error.cpp b/kernel/kernel/filesystem/error.cpp index d288693e..0d6ae01e 100644 --- a/kernel/kernel/filesystem/error.cpp +++ b/kernel/kernel/filesystem/error.cpp @@ -56,6 +56,8 @@ namespace kernel::filesystem return "invalid argument"; case vfs_errc::not_mounted: return "filesystem is not mounted"; + case vfs_errc::invalid_driver_data: + return "invalid driver data"; default: return "unknown VFS error"; } @@ -69,6 +71,7 @@ namespace kernel::filesystem case vfs_errc::invalid_filesystem: case vfs_errc::invalid_inode: case vfs_errc::invalid_argument: + case vfs_errc::invalid_driver_data: return make_error_condition(kstd::errc::invalid_argument); case vfs_errc::no_such_file_or_directory: case vfs_errc::mount_point_not_found: diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp index 41009bb7..6b167355 100644 --- a/kernel/kernel/filesystem/error.hpp +++ b/kernel/kernel/filesystem/error.hpp @@ -28,6 +28,7 @@ namespace kernel::filesystem no_such_device, invalid_argument, not_mounted, + invalid_driver_data, }; [[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 a0a0dbf1..9275f5a9 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -62,7 +62,7 @@ namespace kernel::filesystem::ext2 return "ext2"; } - [[nodiscard]] auto probe(kstd::shared_ptr const & backing_inode) const noexcept + [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept -> kstd::result override { auto superblock = ext2::superblock{}; @@ -88,7 +88,7 @@ namespace kernel::filesystem::ext2 return 0; } - [[nodiscard]] auto make_instance() const -> kstd::shared_ptr override + [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared(); } @@ -106,8 +106,7 @@ namespace kernel::filesystem::ext2 }; } - auto filesystem::mount(kstd::shared_ptr const & backing_inode) - -> kstd::result + auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result { m_backing_inode = backing_inode; @@ -151,8 +150,8 @@ namespace kernel::filesystem::ext2 kstd::make_shared(m_superblock, m_block_group_descriptors, m_backing_inode)}; } - auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> kstd::result> + auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const + -> kstd::result { if (!parent) { @@ -164,6 +163,12 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_a_directory); } + auto mount_state = static_pointer_cast(driver_data); + if (!mount_state) + { + return kstd::failure(vfs_errc::invalid_driver_data); + } + auto * ext2_parent = static_cast(parent.get()); auto const & inode_data = ext2_parent->data(); kstd::vector buffer(block_size().value); @@ -200,9 +205,8 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::create_inode(kstd::shared_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, - std::optional raw_device) + auto filesystem::create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, + driver_data_ptr driver_data, std::optional raw_device) -> kstd::result> { if (!parent) @@ -216,7 +220,6 @@ namespace kernel::filesystem::ext2 } auto is_device = kapi::filesystem::is_device(type); - if (is_device && !raw_device) { return kstd::failure(vfs_errc::invalid_argument); @@ -228,6 +231,12 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::invalid_argument); } + auto mount_state = static_pointer_cast(driver_data); + if (!mount_state) + { + return kstd::failure(vfs_errc::invalid_driver_data); + } + auto maybe_inode_number = allocate_inode(); if (!maybe_inode_number) { diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 1f7fe8af..c6f8b04a 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -77,10 +77,11 @@ namespace kernel::filesystem::ext2 { auto mount(inode_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const -> kstd::result override; [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, + driver_data_ptr driver_data, std::optional raw_device = std::nullopt) -> kstd::result override; diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 708f83df..0b815584 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -51,6 +51,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); auto root = (*mount)->root_dentry()->inode(); + auto driver_data = (*mount)->driver_data(); REQUIRE(mount); THEN("the root inode is available and is a directory") @@ -61,26 +62,26 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("lookup resolves known entries from the image") { - auto information = fs->lookup(root, "information"); + auto information = fs->lookup(root, "information", driver_data); 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", driver_data); 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", driver_data)); - auto information = fs->lookup(root, "information"); + auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); - auto info_1 = fs->lookup(*information, "info_1.txt"); + auto info_1 = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(info_1); - REQUIRE(!fs->lookup(*info_1, "anything")); - REQUIRE(!fs->lookup(root, "does_not_exist")); + REQUIRE(!fs->lookup(*info_1, "anything", driver_data)); + REQUIRE(!fs->lookup(root, "does_not_exist", driver_data)); } } } @@ -103,50 +104,52 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); auto root = (*mount)->root_dentry()->inode(); + auto driver_data = (*mount)->driver_data(); REQUIRE(mount); THEN("a file can be created") { - auto lookup_result = fs->lookup(root, "blub"); + auto lookup_result = fs->lookup(root, "blub", driver_data); 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, driver_data); REQUIRE(new_inode); REQUIRE(new_inode.value()->is_regular()); - lookup_result = fs->lookup(root, "blub"); + lookup_result = fs->lookup(root, "blub", driver_data); REQUIRE(lookup_result); } THEN("a directory can be created") { - auto lookup_result = fs->lookup(root, "blub"); + auto lookup_result = fs->lookup(root, "blub", driver_data); 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, driver_data); REQUIRE(new_directory); REQUIRE(new_directory.value()->is_directory()); - lookup_result = fs->lookup(root, "blub"); + lookup_result = fs->lookup(root, "blub", driver_data); 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, driver_data); 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, driver_data); REQUIRE(new_file); - auto lookup_result = fs->lookup(new_directory.value(), "blub_file"); + auto lookup_result = fs->lookup(new_directory.value(), "blub_file", driver_data); 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, driver_data); REQUIRE(new_inode); auto buffer = @@ -165,7 +168,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, driver_data), kernel::tests::cpu::halt); } } diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 9a602a28..356e44ed 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -104,11 +104,12 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); auto root = (*mount)->root_dentry()->inode(); + auto driver_data = (*mount)->driver_data(); REQUIRE(mount); - auto information = fs->lookup(root, "information"); + auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); - auto file = fs->lookup(*information, "info_1.txt"); + auto file = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(file); REQUIRE(file.value()->is_regular()); @@ -314,11 +315,12 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto fs = kstd::make_shared(); auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); auto root = (*mount)->root_dentry()->inode(); + auto driver_data = (*mount)->driver_data(); REQUIRE(mount); - auto information = fs->lookup(root, "information"); + auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); - auto file = fs->lookup(*information, "info_1.txt"); + auto file = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(file); REQUIRE(file.value()->is_regular()); diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index f1b39bd4..2e713c89 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -52,19 +52,21 @@ namespace kernel::filesystem //! //! @param parent The parent inode. //! @param name The name of the child inode to look up. + //! @param driver_data The per-mount data used by the driver. //! @return A pointer to the requested child inode on success, an error otherwise. - [[nodiscard]] virtual auto lookup(inode_ptr const & parent, std::string_view name) const - -> kstd::result = 0; + [[nodiscard]] virtual auto lookup(inode_ptr const & parent, std::string_view name, + driver_data_ptr driver_data) const -> kstd::result = 0; //! Create a new inode with the given name below a given parent inode. //! //! @param parent The parent inode. //! @param name The name of the inode to create. //! @param type The file type of inode to be created. + //! @param driver_data The per-mount data used by the driver. //! @param raw_device The device number the new inode should represent, if any. //! @return A pointer to the created inode on success, an error otherwise. [[nodiscard]] virtual auto create_inode(inode_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, + kapi::filesystem::file_type type, driver_data_ptr driver_data, std::optional raw_device = std::nullopt) -> kstd::result> = 0; }; diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index d808ff52..616a9dbd 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -109,6 +109,11 @@ namespace kernel::filesystem return m_source_mount.lock(); } + auto mount::driver_data() const -> kstd::shared_ptr + { + return m_driver_data; + } + auto mount::increment_ref_count() -> void { m_ref_count += 1; diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index 147d967a..994ebaca 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -50,12 +50,12 @@ namespace kernel::filesystem::rootfs return mount_result{root, nullptr}; } - auto filesystem::lookup(inode_ptr const &, std::string_view) const -> kstd::result + auto filesystem::lookup(inode_ptr const &, std::string_view, driver_data_ptr) const -> kstd::result { return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, + auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, driver_data_ptr, std::optional) -> kstd::result { return kstd::failure(vfs_errc::read_only_file_system); diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 5a72ff42..77dc9c46 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -29,12 +29,13 @@ namespace kernel::filesystem::rootfs //! @copydoc kernel::filesystem::filesystem::lookup. //! @return Always returns an error, as rootfs is always empty. - [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name) const - -> kstd::result override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, + driver_data_ptr driver_data = nullptr) const -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode. //! @return Always returns an error, as creating new inodes is not supported in rootfs. [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, + driver_data_ptr driver_data = nullptr, std::optional raw_device = std::nullopt) -> kstd::result override; }; diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 6a15d211..512b7394 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -296,7 +296,8 @@ namespace kernel::filesystem if (auto fs = mount_context->filesystem()) { - if (auto new_inode = fs->create_inode(parent_dentry->inode(), name, type, raw_device)) + if (auto new_inode = + fs->create_inode(parent_dentry->inode(), name, type, mount_context->driver_data(), raw_device)) { (*new_inode)->set_owning_mount(mount_context); @@ -390,7 +391,7 @@ namespace kernel::filesystem if (!next_dentry) { auto current_fs = current_mount->filesystem(); - auto found_inode = current_fs->lookup(current_dentry->inode(), part); + auto found_inode = current_fs->lookup(current_dentry->inode(), part, current_mount->driver_data()); if (!found_inode) { return kstd::failure(found_inode.error()); diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 8bd46e3c..105746e8 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -15,20 +15,18 @@ namespace kernel::tests::filesystem { - auto filesystem::mount(kstd::shared_ptr const &) -> kstd::result + auto filesystem::mount(inode_ptr const &) -> kstd::result { return std::pair{kstd::make_shared(), nullptr}; } - auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const - -> kstd::result> + auto filesystem::lookup(inode_ptr const &, std::string_view, driver_data_ptr) const -> kstd::result { return kstd::make_shared(); } - auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, - kapi::filesystem::file_type, std::optional) - -> kstd::result> + auto filesystem::create_inode(inode_ptr const &, std::string_view, kapi::filesystem::file_type, driver_data_ptr, + std::optional) -> kstd::result { return kstd::make_shared(); } diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index d7f64883..52111a5a 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -22,13 +22,14 @@ namespace kernel::tests::filesystem auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, + driver_data_ptr driver_data = nullptr) const -> kstd::result> override; - [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, - kapi::filesystem::file_type type, + [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, + driver_data_ptr driver_data = nullptr, std::optional = std::nullopt) - -> kstd::result> override; + -> kstd::result override; }; } // namespace kernel::tests::filesystem -- cgit v1.2.3 From 815cca56b68767ea6e223d7c6c671e57a9e31fb4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 14:49:44 +0200 Subject: kernel/fs: ext2: externalize mount state --- kernel/kernel/filesystem/ext2/filesystem.cpp | 308 +++++++++++---------- kernel/kernel/filesystem/ext2/filesystem.hpp | 72 +++-- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 47 ++-- kernel/kernel/filesystem/ext2/inode.cpp | 108 ++++++-- kernel/kernel/filesystem/ext2/inode.hpp | 4 + kernel/kernel/filesystem/ext2/inode.tests.cpp | 14 +- kernel/kernel/filesystem/ext2/mount_state.hpp | 6 +- 7 files changed, 340 insertions(+), 219 deletions(-) (limited to 'kernel') 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{}; - auto filesystem::indirect_levels() const -> std::array + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + + auto filesystem::indirect_levels(mount_state const & state) const -> std::array { 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 { - m_backing_inode = backing_inode; + auto mount_state = kstd::make_shared(); + 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(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(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(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(parent.get()); auto const & inode_data = ext2_parent->data(); - kstd::vector buffer(block_size().value); + kstd::vector 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(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 + [[maybe_unused]] uint16_t mode, mount_state & state) -> kstd::result { - 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 buffer(block_size().value); - if (auto read_result = read_block(*global_block, buffer.data()); !read_result) + kstd::vector 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(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 const & new_inode, - kernel::filesystem::ext2::inode * parent_inode) -> kstd::result + kernel::filesystem::ext2::inode * parent_inode, mount_state & state) + -> kstd::result { 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 buffer(block_size().value, 0); - write_directory_entry_to_buffer(buffer.data(), 0_B, new_inode->number(), ".", 2); + kstd::vector 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((8u + 1 + 3u) & ~3u); auto * entry = reinterpret_cast(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(name.size()); auto * entry = reinterpret_cast(block_buffer + offset); entry->inode = child_inode_number; - entry->rec_len = static_cast(block_size() - offset); + entry->rec_len = static_cast(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> + auto filesystem::read_inode(uint32_t inode_number, mount_state const & state) const + -> kstd::result> { - 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 + auto filesystem::write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) + -> kstd::result { - 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 + auto filesystem::calculate_inode_offset(uint32_t inode_number, mount_state const & state) const + -> kstd::result { - 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> + auto filesystem::allocate_blocks(size_t count, mount_state & state) -> kstd::result> { - 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 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 block_bitmap(block_size().value, 0); - if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap.data()); !read_result) + kstd::vector 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(m_superblock.blocks_per_group) && allocated_blocks.size() < count; ++i) + for (auto i = 0uz; i < static_cast(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 + auto filesystem::allocate_inode(mount_state & state) -> kstd::result { - 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 inode_bitmap(block_size().value, 0); - if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap.data()); !read_result) + kstd::vector 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(m_superblock.inodes_per_group); ++i) + for (auto i = 0uz; i < static_cast(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 { 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 + auto filesystem::read_block_number_at_index(uint32_t block_number, size_t index, mount_state const & state) const + -> kstd::result { 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(); 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 + uint32_t global_block_number, mount_state & state) + -> kstd::result { 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(); + auto const byte_offset = block_number * block_size(state) + idx * kstd::size_of(); 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 const & - { - return m_backing_inode; - } - - auto filesystem::read_block(uint32_t block_number, void * buffer) const -> kstd::result + auto filesystem::read_block(uint32_t block_number, void * buffer, mount_state & state) const + -> kstd::result { - auto const block_offset = static_cast(block_number) * block_size(); - return m_backing_inode->read(std::span{static_cast(buffer), block_size().value}, block_offset); + auto const block_offset = static_cast(block_number) * block_size(state); + return state.backing_inode->read(std::span{static_cast(buffer), block_size(state).value}, + block_offset); } - auto filesystem::write_block(uint32_t block_number, void const * buffer) -> kstd::result + auto filesystem::write_block(uint32_t block_number, void const * buffer, mount_state & state) + -> kstd::result { - auto const block_offset = static_cast(block_number) * block_size(); - return m_backing_inode->write(std::span{static_cast(buffer), block_size().value}, block_offset); + auto const block_offset = static_cast(block_number) * block_size(state); + return state.backing_inode->write(std::span{static_cast(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 + size_t block_group_descriptor_index, mount_state const & state) const + -> kstd::result { // 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 + auto filesystem::write_superblock(mount_state & state) const -> kstd::result { - // 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(); + return block_size(state) / kstd::size_of(); } - 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 #include +#include #include #include #include @@ -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; + auto read_block(uint32_t block_number, void * buffer, mount_state & state) const -> kstd::result; //! 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; + auto write_block(uint32_t block_number, void const * buffer, mount_state & state) -> kstd::result; //! 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>; + auto allocate_blocks(size_t count, mount_state & state) -> kstd::result>; //! 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; + auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result; //! 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; //! 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; + uint32_t global_block_number, mount_state & state) + -> kstd::result; //! 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; + [[nodiscard]] auto indirect_levels(mount_state const & state) const -> std::array; - auto allocate_inode() -> kstd::result; - 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; + auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode, + mount_state & state) -> kstd::result; + auto init_directory(kstd::shared_ptr const & new_inode, inode * parent_inode, mount_state & state) -> kstd::result; - auto init_directory(kstd::shared_ptr const & new_inode, inode * parent_inode) -> kstd::result; 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; - [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result>; - [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result; + [[nodiscard]] auto calculate_inode_offset(uint32_t inode_number, mount_state const & state) const + -> kstd::result; + [[nodiscard]] auto read_inode(uint32_t inode_number, mount_state const & state) const + -> kstd::result>; + [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index, mount_state const & state) const + -> kstd::result; - [[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; - [[nodiscard]] auto write_superblock() const -> kstd::result; + size_t block_group_descriptor_index, + mount_state const & state) const -> kstd::result; + [[nodiscard]] auto write_superblock(mount_state & state) const -> kstd::result; 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 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 #include #include +#include #include #include #include @@ -207,7 +208,10 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys auto dev_inode = kstd::make_shared(device); auto fs = kstd::make_shared(); - REQUIRE(fs->mount(dev_inode)); + auto mount = fs->mount(dev_inode); + REQUIRE(mount); + auto mount_state = static_pointer_cast(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(); - REQUIRE(fs->mount(dev_inode)); + auto mount = fs->mount(dev_inode); + REQUIRE(mount); + auto mount_state = static_pointer_cast(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(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(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, + *mount_state)); 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, + *mount_state)); 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); @@ -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(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 #include +#include #include #include @@ -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(*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(*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(*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(*driver_data); + + if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular()) { size |= static_cast(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(*driver_data); + + if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular()) { m_data.dir_acl = static_cast(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> + { + 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> + { + 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>; + [[nodiscard]] auto get_driver_data() -> kstd::result>; + + [[nodiscard]] auto get_driver_data() 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 356e44ed..a6a88fc8 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -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(driver_data); + REQUIRE(mount_state); + THEN("writing to the inode updates backing device and the inode size") { auto write_buffer = kstd::vector{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(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(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(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((*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_descriptors; - kstd::shared_ptr backing_inode; + struct superblock superblock{}; + kstd::vector block_group_descriptors{}; + kstd::shared_ptr backing_inode{}; }; } // namespace kernel::filesystem::ext2 -- cgit v1.2.3 From 65dc3bd125da94b7faa73e925ea886b617978cd9 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 15:11:51 +0200 Subject: kernel/fs: post-refactor cleanup --- kernel/kernel/filesystem/devfs/filesystem.hpp | 6 +-- .../kernel/filesystem/devfs/filesystem.tests.cpp | 42 ++++++++--------- kernel/kernel/filesystem/ext2/filesystem.hpp | 5 --- kernel/kernel/filesystem/ext2/inode.cpp | 52 +++++++--------------- kernel/kernel/filesystem/ext2/inode.hpp | 4 -- kernel/kernel/filesystem/rootfs/filesystem.hpp | 6 +-- .../kernel/filesystem/rootfs/filesystem.tests.cpp | 17 ++++--- 7 files changed, 54 insertions(+), 78 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 12ac7e83..7529cd28 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -32,13 +32,13 @@ namespace kernel::filesystem::devfs { auto mount(inode_ptr const & backing_inode) -> kstd::result override; - [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, - driver_data_ptr driver_data = nullptr) const -> kstd::result override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const + -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode //! @return Always returns an error, as creating new inodes is not supported in devfs. [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, - driver_data_ptr driver_data = nullptr, + driver_data_ptr driver_data, std::optional raw_device = std::nullopt) -> kstd::result override; diff --git a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp index 20523b71..ec0c1144 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp @@ -25,23 +25,21 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, setup_modules(1); auto fs = kstd::make_shared(); - auto root = fs->mount(nullptr); - - THEN("mount succeeds") - { - REQUIRE(root); - } + auto mount = fs->mount(nullptr); + REQUIRE(mount); + auto [root, driver_data] = *mount; + REQUIRE(root); THEN("lookup on root finds ram0 device inode") { - auto inode = fs->lookup(root->first, "ram0"); + auto inode = fs->lookup(root, "ram0", driver_data); REQUIRE(inode); REQUIRE(inode.value()->is_device()); } THEN("lookup of an unknown device returns error") { - auto inode = fs->lookup(root->first, "ram99"); + auto inode = fs->lookup(root, "ram99", driver_data); REQUIRE(!inode); } @@ -51,23 +49,23 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto other_root = other_fs->mount(nullptr); CHECK(other_root); - auto inode = fs->lookup(other_root->first, "ram0"); + auto inode = fs->lookup(other_root->first, "ram0", driver_data); REQUIRE(!inode); } THEN("lookup with a non-directory parent returns error") { - auto non_directory_inode = fs->lookup(root->first, "ram0"); + auto non_directory_inode = fs->lookup(root, "ram0", driver_data); REQUIRE(non_directory_inode); REQUIRE_FALSE(non_directory_inode.value()->is_directory()); - auto result = fs->lookup(*non_directory_inode, "anything"); + auto result = fs->lookup(*non_directory_inode, "anything", driver_data); REQUIRE(!result); } THEN("create_inode always returns an error") { - auto result = fs->create_inode(root->first, "new_device", kapi::filesystem::file_type::regular); + auto result = fs->create_inode(root, "new_device", kapi::filesystem::file_type::regular, driver_data); REQUIRE(!result); } } @@ -77,14 +75,16 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, setup_modules(3, 2048); auto fs = kstd::make_shared(); - auto root = fs->mount(nullptr); + auto mount = fs->mount(nullptr); + REQUIRE(mount); + auto [root, driver_data] = *mount; REQUIRE(root); THEN("lookup finds all generated RAM devices") { - REQUIRE(fs->lookup(root->first, "ram0")); - REQUIRE(fs->lookup(root->first, "ram1")); - REQUIRE(fs->lookup(root->first, "ram2")); + REQUIRE(fs->lookup(root, "ram0", driver_data)); + REQUIRE(fs->lookup(root, "ram1", driver_data)); + REQUIRE(fs->lookup(root, "ram2", driver_data)); } } } @@ -94,13 +94,15 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") GIVEN("A mounted devfs, and a bus attached to the root without a device attached") { auto fs = kstd::make_shared(); - auto root = fs->mount(nullptr); + auto mount = fs->mount(nullptr); + REQUIRE(mount); + auto [root, driver_data] = *mount; REQUIRE(root); auto bus = kstd::make_shared("devfs_live_update_bus"); kapi::devices::get_root_bus()->add_child(bus); - REQUIRE_FALSE(fs->lookup(root->first, "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(root, "devfs_live_update_device_node", driver_data)); WHEN("a device is attached, bound, and published") { @@ -113,7 +115,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs finds it immediately") { - REQUIRE(fs->lookup(root->first, "devfs_live_update_device_node")); + REQUIRE(fs->lookup(root, "devfs_live_update_device_node", driver_data)); } WHEN("the device is detached") @@ -122,7 +124,7 @@ SCENARIO("Devfs filesystem updates", "[filesystem][devfs]") THEN("devfs does not find it anymore") { - REQUIRE_FALSE(fs->lookup(root->first, "devfs_live_update_device_node")); + REQUIRE_FALSE(fs->lookup(root, "devfs_live_update_device_node", driver_data)); } } } diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index ef7afdfb..9ee737a7 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -165,11 +165,6 @@ namespace kernel::filesystem::ext2 uint32_t global_block_number, mount_state & state) -> kstd::result; - //! Get the backing inode of the file system. - //! - //! @return A reference to the backing inode. - [[nodiscard]] auto backing_inode() const -> inode_ptr const &; - private: struct indirect_level { diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 561bf9de..8c7d0ec0 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -52,9 +52,14 @@ namespace kernel::filesystem::ext2 { return kstd::failure(driver_data.error()); } - auto state = static_pointer_cast(*driver_data); + auto backing_inode = state->backing_inode; + if (!state->backing_inode) + { + return kstd::failure(vfs_errc::not_mounted); + } + auto block_size = (*filesystem)->block_size(*state); auto block_index = offset / block_size; auto in_block_offset = offset % block_size; @@ -78,16 +83,11 @@ namespace kernel::filesystem::ext2 } else { - auto inode = backing_inode(); - if (!inode) - { - return kstd::failure(inode.error()); - } - 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); + auto const read_result = + backing_inode->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); if (!read_result) { return kstd::failure(read_result.error()); @@ -126,8 +126,14 @@ namespace kernel::filesystem::ext2 { return kstd::failure(driver_data.error()); } - auto state = static_pointer_cast(*driver_data); + + auto backing_inode = state->backing_inode; + if (!state->backing_inode) + { + return kstd::failure(vfs_errc::not_mounted); + } + auto block_size = (*filesystem)->block_size(*state); auto const current_block_count = (*filesystem)->inode_block_count(m_data, *state); @@ -165,14 +171,8 @@ namespace kernel::filesystem::ext2 auto const block_start_offset = block_number.value() * block_size; auto const write_offset = block_start_offset + in_block_offset; - auto inode = backing_inode(); - if (!inode) - { - return kstd::failure(inode.error()); - } - auto const write_result = - (*inode)->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); + backing_inode->write(buffer.subspan(bytes_written.value, bytes_to_write.value), write_offset); if (!write_result) { return kstd::failure(write_result.error()); @@ -373,26 +373,6 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - auto inode::backing_inode() -> kstd::result> - { - if (auto mount = owning_mount().lock()) - { - return mount->backing_inode(); - } - - return kstd::failure(vfs_errc::not_mounted); - } - - auto inode::backing_inode() const -> kstd::result> - { - if (auto mount = owning_mount().lock()) - { - return mount->backing_inode(); - } - - return kstd::failure(vfs_errc::not_mounted); - } - auto inode::get_driver_data() -> kstd::result> { if (auto mount = owning_mount().lock()) diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index 6ca2f1b5..7f668833 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -105,10 +105,6 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto get_filesystem() const -> kstd::result>; - [[nodiscard]] auto backing_inode() -> kstd::result>; - - [[nodiscard]] auto backing_inode() const -> kstd::result>; - [[nodiscard]] auto get_driver_data() -> kstd::result>; [[nodiscard]] auto get_driver_data() const -> kstd::result>; diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 77dc9c46..edef76d4 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -29,13 +29,13 @@ namespace kernel::filesystem::rootfs //! @copydoc kernel::filesystem::filesystem::lookup. //! @return Always returns an error, as rootfs is always empty. - [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, - driver_data_ptr driver_data = nullptr) const -> kstd::result override; + [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const + -> kstd::result override; //! @copydoc kernel::filesystem::filesystem::create_inode. //! @return Always returns an error, as creating new inodes is not supported in rootfs. [[nodiscard]] auto create_inode(inode_ptr const & parent, std::string_view name, kapi::filesystem::file_type type, - driver_data_ptr driver_data = nullptr, + driver_data_ptr driver_data, std::optional raw_device = std::nullopt) -> kstd::result override; }; diff --git a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp index b4297582..15c8e313 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp @@ -14,31 +14,34 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] { GIVEN("a mounted rootfs filesystem") { - auto fs = kernel::filesystem::rootfs::filesystem{}; - auto root = fs.mount(nullptr); + auto fs = kstd::make_shared(); + auto mount = fs->mount(nullptr); + REQUIRE(mount); + auto [root, driver_data] = *mount; + REQUIRE(root); THEN("the filesystem can be mounted successfully") { - REQUIRE(root); + REQUIRE(mount); } THEN("looking up a non-existent directory returns an error") { - auto non_existent_inode_1 = fs.lookup(root->first, ""); + auto non_existent_inode_1 = fs->lookup(root, "", driver_data); REQUIRE(!non_existent_inode_1); - auto non_existent_inode_2 = fs.lookup(root->first, "nonexistent"); + auto non_existent_inode_2 = fs->lookup(root, "nonexistent", driver_data); REQUIRE(!non_existent_inode_2); } THEN("looking up with a null parent inode returns an error") { - auto result = fs.lookup(nullptr, "dev"); + auto result = fs->lookup(nullptr, "dev", driver_data); REQUIRE(!result); } THEN("create_inode always returns an error") { - auto result = fs.create_inode(root->first, "new_device", kapi::filesystem::file_type::directory); + auto result = fs->create_inode(root, "new_device", kapi::filesystem::file_type::directory, driver_data); REQUIRE(!result); } } -- cgit v1.2.3 From 5abb324bb68dfc7608919497a725047956e70c14 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 15:23:28 +0200 Subject: kernel/fs: devfs: simplify implementation --- kernel/kernel/filesystem/devfs/filesystem.cpp | 37 ++++++++------------------- kernel/kernel/filesystem/devfs/filesystem.hpp | 9 +------ 2 files changed, 11 insertions(+), 35 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 3e94f2ac..640a01db 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -51,16 +50,6 @@ namespace kernel::filesystem::devfs auto filesystem::mount(inode_ptr const &) -> kstd::result { m_root_inode = kstd::make_shared(); - - std::ranges::for_each(device_number_registry::get().all(), [&](auto const & numbered) { - if (auto device = numbered.device.lock()) - { - m_inodes.emplace(numbered.name, kstd::make_shared(device)); - } - }); - - device_number_registry::get().subscribe(shared_from_this()); - return mount_result{m_root_inode, nullptr}; } @@ -82,10 +71,17 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::invalid_inode); } - auto found = std::ranges::find_if(m_inodes, [&](auto const & entry) { return entry.first == name; }); - if (found != m_inodes.end()) + auto entries = device_number_registry::get().all(); + auto found = std::ranges::find_if(entries, [&](auto const & entry) { return entry.name == name; }); + + if (found == entries.end()) + { + return kstd::failure(vfs_errc::no_such_file_or_directory); + } + + if (auto device = found->device.lock()) { - return found->second; + return kstd::make_shared(device); } return kstd::failure(vfs_errc::no_such_file_or_directory); @@ -97,17 +93,4 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::read_only_file_system); } - auto filesystem::on_device_numbered(device_number_registry::entry const & numbered) -> void - { - if (auto device = numbered.device.lock()) - { - m_inodes.emplace(numbered.name, kstd::make_shared(device)); - } - } - - auto filesystem::on_device_unnumbered(device_number_registry::entry const & numbered) -> void - { - erase_if(m_inodes, [&](auto const & entry) { return entry.first == numbered.name; }); - } - } // namespace kernel::filesystem::devfs \ No newline at end of file diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 7529cd28..147cb692 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -8,7 +8,6 @@ #include -#include #include #include #include @@ -26,9 +25,7 @@ namespace kernel::filesystem::devfs //! applications to interact with devices using standard file operations. The devfs filesystem dynamically creates //! inodes for devices registered in the system, enabling seamless access to device functionality through the //! filesystem interface. - struct filesystem : kernel::filesystem::filesystem, - kstd::enable_shared_from_this, - device_number_registry_observer + struct filesystem : kernel::filesystem::filesystem { auto mount(inode_ptr const & backing_inode) -> kstd::result override; @@ -43,11 +40,7 @@ namespace kernel::filesystem::devfs -> kstd::result override; private: - auto on_device_numbered(device_number_registry::entry const & numbered) -> void override; - auto on_device_unnumbered(device_number_registry::entry const & numbered) -> void override; - inode_ptr m_root_inode{}; - kstd::flat_map> m_inodes{}; }; } // namespace kernel::filesystem::devfs -- cgit v1.2.3 From 5f57170c385c609701f0e3db23395f72eb78f3ea Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 15:28:46 +0200 Subject: kernel/fs: devfs: externalize mount state --- kernel/kernel/filesystem/devfs/filesystem.cpp | 10 ++++++---- kernel/kernel/filesystem/devfs/filesystem.hpp | 3 --- kernel/kernel/filesystem/vfs.cpp | 10 ++++++---- kernel/kernel/filesystem/vfs.hpp | 3 ++- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 640a01db..0e3f3164 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -47,13 +47,15 @@ namespace kernel::filesystem::devfs [[gnu::used]] constexpr auto registration = type_registration{}; + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(devfs::filesystem)); + auto filesystem::mount(inode_ptr const &) -> kstd::result { - m_root_inode = kstd::make_shared(); - return mount_result{m_root_inode, nullptr}; + auto root = kstd::make_shared(); + return mount_result{root, root}; } - auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr) const + auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const -> kstd::result { if (!parent) @@ -66,7 +68,7 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::not_a_directory); } - if (parent.get() != m_root_inode.get()) + if (parent.get() != driver_data.get()) { return kstd::failure(vfs_errc::invalid_inode); } diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 147cb692..56744477 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -38,9 +38,6 @@ namespace kernel::filesystem::devfs driver_data_ptr driver_data, std::optional raw_device = std::nullopt) -> kstd::result override; - - private: - inode_ptr m_root_inode{}; }; } // namespace kernel::filesystem::devfs diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 512b7394..43da7130 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -85,7 +85,8 @@ namespace kernel::filesystem kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_mount_result.error()); } - graft_persistent_device_fs(device_fs, device_fs_mount_result->first); + auto [device_fs_root, device_fs_data] = *device_fs_mount_result; + graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); // mount boot fs at / (shadows rootfs), re-graft devfs auto [boot_device_dentry, boot_device_mount_context] = @@ -103,7 +104,7 @@ namespace kernel::filesystem kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); } m_mount_table.add_mount(*mount); - graft_persistent_device_fs(device_fs, device_fs_mount_result->first); + graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); } } } @@ -312,7 +313,8 @@ namespace kernel::filesystem } auto vfs::graft_persistent_device_fs(kstd::shared_ptr const & device_fs, - kstd::shared_ptr const & root_inode) -> void + kstd::shared_ptr const & root_inode, kstd::shared_ptr driver_data) + -> void { auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/").value_or(std::pair{nullptr, nullptr}); if (root_mount_point_dentry && root_mount) @@ -324,7 +326,7 @@ namespace kernel::filesystem root_mount_point_dentry->add_child(dev_dentry); } - auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, nullptr, root_mount, nullptr); + auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, driver_data, root_mount, nullptr); m_mount_table.add_mount(new_mount); } } diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index 1975ac8a..a53ab532 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -112,7 +112,8 @@ namespace kernel::filesystem [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::result; auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs, - kstd::shared_ptr const & root_inode) -> void; + kstd::shared_ptr const & root_inode, kstd::shared_ptr driver_data) + -> void; auto create_inode(std::string_view path, kapi::filesystem::file_type type, std::optional raw_device = std::nullopt) -> kstd::result; -- cgit v1.2.3 From b253637e5eed149f6e8ad7465cf97dda8bf8483a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 15:35:15 +0200 Subject: kernel/fs: remove backing inode from mount --- kernel/kernel/filesystem/mount.cpp | 6 ------ kernel/kernel/filesystem/mount.hpp | 4 ---- 2 files changed, 10 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index 616a9dbd..7381a160 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -65,7 +65,6 @@ namespace kernel::filesystem auto [root_inode, driver_data] = *mount_result; auto instance = attach(mount_dentry, fs, root_inode, driver_data, parent_mount, source_mount); - instance->m_backing_inode = backing_inode; return instance; } @@ -80,11 +79,6 @@ namespace kernel::filesystem return m_filesystem; } - auto mount::backing_inode() const -> kstd::shared_ptr const & - { - return m_backing_inode; - } - auto mount::root_dentry() const -> dentry_ptr const & { return m_root_dentry; diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index e8d9cf6a..cc032874 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -54,9 +54,6 @@ namespace kernel::filesystem //! Get the filesystem instance being mounted. [[nodiscard]] auto filesystem() const -> filesystem_ptr const &; - //! Get the backing inode, if any, of this mount. - [[nodiscard]] auto backing_inode() const -> inode_ptr const &; - //! Get the path at which the filesystem is mounted. [[nodiscard]] auto mount_path() const -> kstd::string; @@ -102,7 +99,6 @@ namespace kernel::filesystem dentry_ptr m_mount_dentry{}; dentry_ptr m_root_dentry{}; filesystem_ptr m_filesystem{}; - inode_ptr m_backing_inode{}; mount_ptr m_parent_mount{}; kstd::weak_ptr m_source_mount{}; kstd::shared_ptr m_driver_data{}; -- cgit v1.2.3 From 84aac7e26dae2b4364d2f1145d4b2b40f1e37585 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 18:10:10 +0200 Subject: kernel/fs: rework filesystem probing --- kernel/CMakeLists.txt | 3 +- kernel/kernel/filesystem/devfs/filesystem.cpp | 26 ++--- kernel/kernel/filesystem/devfs/filesystem.hpp | 6 +- kernel/kernel/filesystem/driver_registry.cpp | 125 +++++++++++++++++++++ kernel/kernel/filesystem/driver_registry.hpp | 73 ++++++++++++ kernel/kernel/filesystem/ext2/filesystem.cpp | 84 +++++++------- kernel/kernel/filesystem/ext2/filesystem.hpp | 2 + kernel/kernel/filesystem/filesystem.cpp | 32 ------ kernel/kernel/filesystem/filesystem.hpp | 9 +- kernel/kernel/filesystem/rootfs/filesystem.cpp | 29 ++--- kernel/kernel/filesystem/rootfs/filesystem.hpp | 3 + kernel/kernel/filesystem/type.hpp | 48 -------- kernel/kernel/filesystem/type_registry.cpp | 94 ---------------- kernel/kernel/filesystem/type_registry.hpp | 59 ---------- kernel/kernel/filesystem/type_registry.tests.cpp | 81 ------------- kernel/kernel/filesystem/vfs.cpp | 63 ++++++----- kernel/kernel/main.cpp | 4 +- .../test_support/filesystem/driver_registry.hpp | 10 ++ .../kernel/test_support/filesystem/filesystem.cpp | 6 + .../kernel/test_support/filesystem/filesystem.hpp | 3 + .../filesystem/storage_boot_module_fixture.cpp | 2 - .../test_support/filesystem/type_registry.hpp | 10 -- .../kernel/test_support/state_reset_listener.cpp | 9 +- 23 files changed, 345 insertions(+), 436 deletions(-) create mode 100644 kernel/kernel/filesystem/driver_registry.cpp create mode 100644 kernel/kernel/filesystem/driver_registry.hpp delete mode 100644 kernel/kernel/filesystem/filesystem.cpp delete mode 100644 kernel/kernel/filesystem/type.hpp delete mode 100644 kernel/kernel/filesystem/type_registry.cpp delete mode 100644 kernel/kernel/filesystem/type_registry.hpp delete mode 100644 kernel/kernel/filesystem/type_registry.tests.cpp create mode 100644 kernel/kernel/test_support/filesystem/driver_registry.hpp delete mode 100644 kernel/kernel/test_support/filesystem/type_registry.hpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c7cf9498..2cca2dda 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -60,14 +60,13 @@ target_sources("kernel_lib" PRIVATE "kernel/filesystem/dentry.cpp" "kernel/filesystem/device_inode.cpp" "kernel/filesystem/device_number_registry.cpp" + "kernel/filesystem/driver_registry.cpp" "kernel/filesystem/error.cpp" - "kernel/filesystem/filesystem.cpp" "kernel/filesystem/inode.cpp" "kernel/filesystem/mount_table.cpp" "kernel/filesystem/mount.cpp" "kernel/filesystem/open_file_descriptor.cpp" "kernel/filesystem/open_file_table.cpp" - "kernel/filesystem/type_registry.cpp" "kernel/filesystem/vfs.cpp" # DevFS Filesystem diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 0e3f3164..a7c8e50c 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -3,10 +3,10 @@ #include #include #include +#include #include #include #include -#include #include @@ -21,23 +21,13 @@ namespace kernel::filesystem::devfs { - struct type final : kernel::filesystem::type + struct descriptor final : kernel::filesystem::driver_descriptor { [[nodiscard]] auto name() const noexcept -> std::string_view override { return "devfs"; } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result override - { - if (backing_inode) - { - return kstd::failure(vfs_errc::invalid_argument); - } - return 0; - } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared(); @@ -45,10 +35,20 @@ namespace kernel::filesystem::devfs }; [[gnu::used]] - constexpr auto registration = type_registration{}; + constexpr auto registration = driver_module{}; static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(devfs::filesystem)); + auto filesystem::probe(inode_ptr const & inode) const -> kstd::result + { + if (inode) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + return 0; + } + auto filesystem::mount(inode_ptr const &) -> kstd::result { auto root = kstd::make_shared(); diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 56744477..aa33c58b 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -13,6 +14,7 @@ #include #include +#include #include #include @@ -25,8 +27,10 @@ namespace kernel::filesystem::devfs //! applications to interact with devices using standard file operations. The devfs filesystem dynamically creates //! inodes for devices registered in the system, enabling seamless access to device functionality through the //! filesystem interface. - struct filesystem : kernel::filesystem::filesystem + struct filesystem final : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result override; + auto mount(inode_ptr const & backing_inode) -> kstd::result override; [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const diff --git a/kernel/kernel/filesystem/driver_registry.cpp b/kernel/kernel/filesystem/driver_registry.cpp new file mode 100644 index 00000000..22bc306d --- /dev/null +++ b/kernel/kernel/filesystem/driver_registry.cpp @@ -0,0 +1,125 @@ +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kernel::filesystem +{ + + extern "C" + { + // We need to suppress clang-tidy linting warnings here, since these symbols are generated by the linker and we + // cannot choose their names, unless we wanted to extend the linker script needlessly. + // NOLINTBEGIN(readability-identifier-naming) + extern kstd::observer_ptr const __start_filesystem_drivers; + extern kstd::observer_ptr const __stop_filesystem_drivers; + // NOLINTEND(readability-identifier-naming) + } + + namespace + { + auto constinit instance = std::optional{}; + } + + auto driver_registry::init() -> void + { + if (instance) + { + kapi::system::panic("[OS:FS] The filesystem driver registry was already initialized!"); + } + + instance.emplace(); + + auto instances = + std::span{&__start_filesystem_drivers, &__stop_filesystem_drivers} | + std::views::filter([](auto descriptor) { return descriptor != nullptr; }) | + std::views::transform([](auto descriptor) { return std::pair{descriptor, descriptor->make_instance()}; }) | + std::views::filter([](auto entry) { return entry.second != nullptr; }); + + std::ranges::for_each(instances, [](auto entry) { + auto [descriptor, driver] = entry; + kstd::println("[OS:FS] Registering filesystem driver '{}'", descriptor->name()); + instance->add(descriptor->name(), driver); + }); + } + + auto driver_registry::get() -> driver_registry & + { + if (!instance) + { + kapi::system::panic("[OS:FS] The filesystem driver registry has not been initialized!"); + } + + return *instance; + } + + auto driver_registry::find(std::string_view name) const -> std::optional> + { + if (auto it = m_drivers.find(name); it != m_drivers.end()) + { + return it->second; + } + return std::nullopt; + } + + auto driver_registry::add(std::string_view name, kstd::shared_ptr descriptor) -> bool + { + auto result = m_drivers.emplace(name, descriptor); + return result.second; + } + + auto driver_registry::match(kstd::shared_ptr const & inode) const -> kstd::result> + { + struct candidate + { + std::uint32_t priority; + kstd::shared_ptr driver; + }; + + auto candidates = kstd::vector{}; + + for (auto const & entry : m_drivers) + { + auto const & [name, driver] = entry; + auto priority = driver->probe(inode); + if (priority) + { + candidates.push_back({*priority, driver}); + } + } + + std::ranges::stable_sort(candidates, std::ranges::greater{}, &candidate::priority); + + if (candidates.empty()) + { + return kstd::failure(vfs_errc::unsupported_filesystem); + } + + return candidates.front().driver; + } +} // namespace kernel::filesystem + +namespace kernel::tests::filesystem::driver_registry +{ + auto deinit() -> void + { + kernel::filesystem::instance.reset(); + } +} // namespace kernel::tests::filesystem::driver_registry \ No newline at end of file diff --git a/kernel/kernel/filesystem/driver_registry.hpp b/kernel/kernel/filesystem/driver_registry.hpp new file mode 100644 index 00000000..1a6cd47e --- /dev/null +++ b/kernel/kernel/filesystem/driver_registry.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_KERNEL_DRIVER_REGISTRY_HPP +#define TEACHOS_KERNEL_DRIVER_REGISTRY_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace kernel::filesystem +{ + + struct driver_descriptor + { + virtual ~driver_descriptor() = default; + + //! Get the name of the driver. + [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; + + //! Create a new instance of the driver represented by this descriptor. + [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr = 0; + }; + + template Type> + struct driver_module + { + constexpr auto static instance = Type{}; + [[using gnu: section("filesystem_drivers"), used, visibility("hidden")]] constexpr auto static pointer{ + kstd::make_observer(&instance), + }; + }; + + struct driver_registry + { + constexpr driver_registry() noexcept = default; + + auto static init() -> void; + + auto static get() -> driver_registry &; + + //! Register a new filesystem. + //! + //! @param name The name of the filesystem. + //! @param driver The filesystem driver to register. + //! @return @c true iff. the driver was successfully added, @c false if not. + auto add(std::string_view name, kstd::shared_ptr driver) -> bool; + + //! Find a registered filesystem driver + //! + //! @param name The name of the filesystem + [[nodiscard]] auto find(std::string_view name) const -> std::optional>; + + //! Match all currently registered filesystem drivers against a given inode. + //! + //! @param inode The inode to match on, if any. + //! @return a match priority if th + [[nodiscard]] auto match(kstd::shared_ptr const & inode) const -> kstd::result>; + + private: + //! A map from filesystem names to filesystem drivers. + kstd::flat_map> m_drivers{}; + }; + +} // namespace kernel::filesystem + +#endif diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index ef81f6ac..579094e0 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include #include #include @@ -34,6 +34,25 @@ using namespace kstd::units_literals; namespace kernel::filesystem::ext2 { + + struct descriptor final : kernel::filesystem::driver_descriptor + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override + { + return kstd::make_shared(); + } + }; + + [[gnu::used]] + constexpr auto registration = driver_module{}; + + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + namespace { [[nodiscard]] auto bitmap_is_set(kstd::vector const & bitmap, size_t index) -> bool @@ -55,57 +74,38 @@ namespace kernel::filesystem::ext2 read_only_compatible_features::large_file_support; } // namespace - struct type final : kernel::filesystem::type + auto filesystem::indirect_levels(mount_state const & state) const -> std::array { - [[nodiscard]] auto name() const noexcept -> std::string_view override + return { + {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, + {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, + {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} + }; + } + + auto filesystem::probe(inode_ptr const & backing_inode) const -> kstd::result + { + auto superblock = ext2::superblock{}; + auto bytes = std::as_writable_bytes(std::span{&superblock, 1}); + auto read_result = backing_inode->read(bytes, constants::superblock_offset); + + if (!read_result) { - return "ext2"; + return kstd::failure(read_result.error()); } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result override + if (superblock.magic != constants::magic_number) { - auto superblock = ext2::superblock{}; - auto bytes = std::as_writable_bytes(std::span{&superblock, 1}); - auto read_result = backing_inode->read(bytes, constants::superblock_offset); - - if (!read_result) - { - return kstd::failure(read_result.error()); - } - - if (superblock.magic != constants::magic_number) - { - return kstd::failure(ext2_errc::invalid_magic_number); - } - - if (superblock.feature_incompat & std::to_underlying(~supported_incompatible_features) || - superblock.feature_ro_compat & std::to_underlying(~supported_ro_compatible_features)) - { - return kstd::failure(ext2_errc::unsupported_features_present); - } - - return 0; + return kstd::failure(ext2_errc::invalid_magic_number); } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override + if (superblock.feature_incompat & std::to_underlying(~supported_incompatible_features) || + superblock.feature_ro_compat & std::to_underlying(~supported_ro_compatible_features)) { - return kstd::make_shared(); + return kstd::failure(ext2_errc::unsupported_features_present); } - }; - - [[gnu::used]] - constexpr auto registration = type_registration{}; - - static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); - auto filesystem::indirect_levels(mount_state const & state) const -> std::array - { - return { - {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, - {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, - {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} - }; + return 0; } auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 9ee737a7..4b5604e5 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -76,6 +76,8 @@ namespace kernel::filesystem::ext2 //! The Second Extended Filesystem (ext2) struct filesystem final : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & backing_inode) const -> kstd::result override; + auto mount(inode_ptr const & backing_inode) -> kstd::result override; [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp deleted file mode 100644 index d2e3adde..00000000 --- a/kernel/kernel/filesystem/filesystem.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include -#include -#include - -#include -#include -#include - -namespace kernel::filesystem -{ - - auto filesystem::probe(kstd::shared_ptr const & backing_inode) -> kstd::result> - { - for (auto & type : type_registry::get().all()) - { - if (!type || !type->probe(backing_inode)) - { - continue; - } - - if (auto fs = type->make_instance()) - { - return fs; - } - } - - return kstd::failure(vfs_errc::unsupported_filesystem); - } - -} // namespace kernel::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index 2e713c89..f9fb2859 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -30,11 +31,11 @@ namespace kernel::filesystem //! Virtual destructor enabling polymorphic destruction. virtual ~filesystem() = default; - //! Probes the given inode to determine if it contains a recognizable filesystem. + //! Check if the data represented by the given inode is recognized as this filesystem. //! - //! @param backing_inode The inode to probe and mount, if any. - //! @return A pointer to the instantiated filesystem and the root of it on success, an error otherwise. - auto static probe(inode_ptr const & backing_inode) -> kstd::result; + //! @param inode The inode to probe, if any. + //! @return the priority (higher is better) of the match on success, an error otherwise. + [[nodiscard]] virtual auto probe(inode_ptr const & inode) const -> kstd::result = 0; //! Initializes the filesystem with the given inode. //! diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index 994ebaca..a14addba 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -1,9 +1,9 @@ #include +#include #include #include #include -#include #include @@ -17,24 +17,13 @@ namespace kernel::filesystem::rootfs { - struct type final : kernel::filesystem::type + struct descriptor final : kernel::filesystem::driver_descriptor { [[nodiscard]] auto name() const noexcept -> std::string_view override { return "rootfs"; } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result override - { - if (backing_inode) - { - return kstd::failure(vfs_errc::invalid_argument); - } - - return 0; - } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared(); @@ -42,7 +31,19 @@ namespace kernel::filesystem::rootfs }; [[gnu::used]] - constexpr auto registration = type_registration{}; + constexpr auto registration = driver_module{}; + + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(rootfs::filesystem)); + + auto filesystem::probe(inode_ptr const & inode) const -> kstd::result + { + if (inode) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + return 0; + } auto filesystem::mount(inode_ptr const &) -> kstd::result { diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index edef76d4..0195b250 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -24,6 +25,8 @@ namespace kernel::filesystem::rootfs //! hierarchy. It is responsible for providing a stable and consistent interface to the root directory. struct filesystem : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result override; + //! @copydoc kernel::filesystem::filesystem::mount auto mount(inode_ptr const & backing_inode) -> kstd::result override; diff --git a/kernel/kernel/filesystem/type.hpp b/kernel/kernel/filesystem/type.hpp deleted file mode 100644 index c2f2595b..00000000 --- a/kernel/kernel/filesystem/type.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TEACHOS_KERNEL_FILESYSTEM_TYPE_HPP -#define TEACHOS_KERNEL_FILESYSTEM_TYPE_HPP - -#include -#include - -#include -#include - -#include -#include - -namespace kernel::filesystem -{ - - //! A type descriptor for a filesystem driver. - //! - //! Each filesystem must expose an instance of a class derived from this type in order to be registered with the vfs - //! filesystem registry. - struct type - { - virtual ~type() = default; - - //! Get the name of the filesystem represented by this descriptor. - [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; - - //! Check if the filesystem is applicable. - //! - //! @return the priority of this filesystem for the given inode. - [[nodiscard]] virtual auto probe(kstd::shared_ptr const & backing_inode) const noexcept - -> kstd::result = 0; - - //! Create a new instance of the filesystem represented by this descriptor. - [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr = 0; - }; - - template - struct type_registration - { - constexpr auto static instance = Type{}; - [[using gnu: section("fs_types"), used, visibility("hidden")]] constexpr auto static pointer{ - kstd::make_observer(&instance), - }; - }; - -} // namespace kernel::filesystem - -#endif diff --git a/kernel/kernel/filesystem/type_registry.cpp b/kernel/kernel/filesystem/type_registry.cpp deleted file mode 100644 index 05fb116a..00000000 --- a/kernel/kernel/filesystem/type_registry.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace kernel::filesystem -{ - - extern "C" - { - // We need to suppress clang-tidy linting warnings here, since these symbols are generated by the linker and we - // cannot choose their names, unless we wanted to extend the linker script needlessly. - // NOLINTBEGIN(readability-identifier-naming) - extern type_registry::pointer const __start_fs_types; - extern type_registry::pointer const __stop_fs_types; - // NOLINTEND(readability-identifier-naming) - } - - namespace - { - auto constinit instance = std::optional{}; - } - - auto type_registry::init() -> void - { - if (instance) - { - kapi::system::panic("[FILESYSTEM] tried to initialize type registry more than once!"); - } - - instance.emplace(); - - auto type_descriptors = std::span{&__start_fs_types, &__stop_fs_types} | // - std::views::filter([](auto p) { return p != nullptr; }); - - std::ranges::for_each(type_descriptors, [](auto descriptor) { - kstd::println("[FILESYSTEM] registering '{}'", descriptor->name()); - instance->add(descriptor); - }); - } - - auto type_registry::get() -> type_registry & - { - if (!instance) - { - kapi::system::panic("[FILESYSTEM] type registry has not been initialized!"); - } - - return *instance; - } - - auto type_registry::find(std::string_view name) const -> std::optional - { - if (auto it = m_descriptors.find(name); it != m_descriptors.end()) - { - return it->second; - } - return std::nullopt; - } - - auto type_registry::add(pointer descriptor) -> bool - { - auto result = m_descriptors.emplace(descriptor->name(), descriptor); - return result.second; - } - - auto type_registry::all() const noexcept -> kstd::vector - { - return m_descriptors.values(); - } - - auto type_registry::size() const noexcept -> std::size_t - { - return m_descriptors.size(); - } - -} // namespace kernel::filesystem - -namespace kernel::tests::filesystem::type_registry -{ - auto deinit() -> void - { - kernel::filesystem::instance.reset(); - } -} // namespace kernel::tests::filesystem::type_registry \ No newline at end of file diff --git a/kernel/kernel/filesystem/type_registry.hpp b/kernel/kernel/filesystem/type_registry.hpp deleted file mode 100644 index 11669ab3..00000000 --- a/kernel/kernel/filesystem/type_registry.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef TEACHOS_KERNEL_TYPE_REGISTRY_HPP -#define TEACHOS_KERNEL_TYPE_REGISTRY_HPP - -#include - -#include -#include -#include -#include - -#include -#include -#include - -namespace kernel::filesystem -{ - - struct type_registry - { - using value_type = type; - using pointer = kstd::observer_ptr; - - auto static init() -> void; - auto static get() -> type_registry &; - - constexpr type_registry() noexcept = default; - - //! Add a type descriptor to this registry. - //! - //! This function will register the given descriptor with this registry, given that no descriptor for a filesystem - //! with the same name exists in this registry already. - //! - //! @param descriptor The filesystem type descriptor to add to the registry. - //! @return @p true iff. the descriptor was successfully added, @p false if not. - auto add(pointer descriptor) -> bool; - - //! Find a registered type descriptor by name - //! - //! @param name The name of the filesystem - [[nodiscard]] auto find(std::string_view name) const -> std::optional; - - //! Get all currently registered type descriptors. - //! - //! @return A span containing all currently registered filesystem type descriptors. - [[nodiscard]] auto all() const noexcept -> kstd::vector; - - //! Get the number of registered filesystem types. - //! - //! @return The number of filesystem descriptors currently registered with this registry. - [[nodiscard]] auto size() const noexcept -> std::size_t; - - private: - //! A map from filesystem names (identifiers) to filesystem type descriptors. - kstd::flat_map m_descriptors{}; - }; - -} // namespace kernel::filesystem - -#endif diff --git a/kernel/kernel/filesystem/type_registry.tests.cpp b/kernel/kernel/filesystem/type_registry.tests.cpp deleted file mode 100644 index b38c16f8..00000000 --- a/kernel/kernel/filesystem/type_registry.tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -struct test_type final : kernel::filesystem::type -{ - [[nodiscard]] auto name() const noexcept -> std::string_view override - { - return "bht_testfs"; - } - - [[nodiscard]] auto probe(kstd::shared_ptr const &) const noexcept - -> kstd::result override - { - return false; - } - - [[nodiscard]] auto make_instance() const -> kstd::shared_ptr override - { - return nullptr; - } -}; - -SCENARIO("Filesystem type registry initialization and construction", "[filesystem]") -{ - GIVEN("A default constructed type_registry") - { - auto instance = kernel::filesystem::type_registry{}; - - WHEN("getting the span of filesystem descriptors") - { - auto descriptors = instance.all(); - - THEN("the span is empty") - { - REQUIRE(descriptors.empty()); - } - } - } -} - -SCENARIO("Filesystem type registry modifiers", "[filesystem]") -{ - GIVEN("A default constructed type_registry") - { - auto instance = kernel::filesystem::type_registry{}; - - WHEN("adding a type descriptor") - { - auto descriptor = test_type{}; - - instance.add(kstd::make_observer(&descriptor)); - - THEN("the size of the registry is one") - { - REQUIRE(instance.size() == 1); - } - - THEN("the span is not empty") - { - REQUIRE_FALSE(instance.all().empty()); - } - - THEN("the span's size is equal to the registry size") - { - REQUIRE(std::size(instance.all()) == std::size(instance)); - } - } - } -} diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 43da7130..d8bcb6b6 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,12 +12,12 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -53,14 +54,13 @@ namespace kernel::filesystem vfs::vfs() { // mount rootfs at / - auto root_fs_descriptor = type_registry::get().find("rootfs"); - if (!root_fs_descriptor) + auto rootfs = driver_registry::get().find("rootfs"); + if (!rootfs) { kapi::system::panic("[OS:FS] rootfs driver is missing!"); } - auto root_fs = (*root_fs_descriptor)->make_instance(); - auto root_mount_result = root_fs->mount(nullptr); + auto root_mount_result = (*rootfs)->mount(nullptr); if (!root_mount_result) { kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_mount_result.error()); @@ -68,45 +68,53 @@ namespace kernel::filesystem auto [root_inode, root_state] = *root_mount_result; - auto root_mount = mount::attach(nullptr, root_fs, root_inode, root_state, nullptr, nullptr); + auto root_mount = mount::attach(nullptr, *rootfs, root_inode, root_state, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) - auto device_fs_descriptor = type_registry::get().find("devfs"); - if (!device_fs_descriptor) + auto devfs = driver_registry::get().find("devfs"); + if (!devfs) { kapi::system::panic("[OS:FS] devfs driver is missing!"); } - auto device_fs = (*device_fs_descriptor)->make_instance(); - auto device_fs_mount_result = device_fs->mount(nullptr); + auto device_fs_mount_result = (*devfs)->mount(nullptr); if (!device_fs_mount_result) { kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_mount_result.error()); } auto [device_fs_root, device_fs_data] = *device_fs_mount_result; - graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); + graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data); // mount boot fs at / (shadows rootfs), re-graft devfs auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { - if (auto result = kernel::filesystem::filesystem::probe(boot_device_dentry->inode())) + auto driver = driver_registry::get().match(boot_device_dentry->inode()); + if (!driver) { - if (auto root_dentry = resolve_path("/")) - { - auto mount = - mount::create(*root_dentry, *result, root_mount, boot_device_mount_context, boot_device_dentry->inode()); - if (!mount) - { - kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); - } - m_mount_table.add_mount(*mount); - graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); - } + kstd::println(kstd::print_sink::stderr, "[OS:FS] Missing driver for root disk!"); + return; + } + + auto root_dentry = resolve_path("/"); + if (!root_dentry) + { + kapi::system::panic("[OS:FS] No root directory found!"); + } + + auto mount = + mount::create(*root_dentry, *driver, root_mount, boot_device_mount_context, boot_device_dentry->inode()); + + if (!mount) + { + kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); } + m_mount_table.add_mount(*mount); + + graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data); } } @@ -188,13 +196,14 @@ namespace kernel::filesystem } auto [source_dentry, source_mount_context] = *resolved_source; - auto fs = kernel::filesystem::filesystem::probe(source_dentry->inode()); - if (!fs) + auto driver = driver_registry::get().match(source_dentry->inode()); + if (!driver) { - return kstd::failure(fs.error()); + return kstd::failure(driver.error()); } - auto mount = mount::create(mount_point_dentry, *fs, mount_context, source_mount_context, source_dentry->inode()); + auto mount = + mount::create(mount_point_dentry, *driver, mount_context, source_mount_context, source_dentry->inode()); if (!mount) { return kstd::failure(mount.error()); diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp index db47f167..f8322b31 100644 --- a/kernel/kernel/main.cpp +++ b/kernel/kernel/main.cpp @@ -1,4 +1,4 @@ -#include "kernel/filesystem/type_registry.hpp" +#include "kernel/filesystem/driver_registry.hpp" #include #include #include @@ -248,7 +248,7 @@ auto main() -> int kernel::filesystem::open_file_table::init(); kstd::println("[OS] Global open file table initialized."); - kernel::filesystem::type_registry::init(); + kernel::filesystem::driver_registry::init(); kstd::println("[OS] Builtin filesystems registered."); kernel::filesystem::vfs::init(); diff --git a/kernel/kernel/test_support/filesystem/driver_registry.hpp b/kernel/kernel/test_support/filesystem/driver_registry.hpp new file mode 100644 index 00000000..b91acd57 --- /dev/null +++ b/kernel/kernel/test_support/filesystem/driver_registry.hpp @@ -0,0 +1,10 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_DRIVER_REGISTRY_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_DRIVER_REGISTRY_HPP + +namespace kernel::tests::filesystem::driver_registry +{ + //! Deinitialize the FS type registry singleton. + auto deinit() -> void; +} // namespace kernel::tests::filesystem::driver_registry + +#endif \ No newline at end of file diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 105746e8..0d4610ab 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -9,12 +9,18 @@ #include #include +#include #include #include #include namespace kernel::tests::filesystem { + auto filesystem::probe(inode_ptr const &) const -> kstd::result + { + return 0; + } + auto filesystem::mount(inode_ptr const &) -> kstd::result { return std::pair{kstd::make_shared(), nullptr}; diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index 52111a5a..3df2cccb 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -19,6 +20,8 @@ namespace kernel::tests::filesystem { filesystem() = default; + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result override; + auto mount(kstd::shared_ptr const & backing_inode) -> kstd::result override; diff --git a/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp b/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp index 3df23751..b9228c69 100644 --- a/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp +++ b/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include #include diff --git a/kernel/kernel/test_support/filesystem/type_registry.hpp b/kernel/kernel/test_support/filesystem/type_registry.hpp deleted file mode 100644 index 8d5b6029..00000000 --- a/kernel/kernel/test_support/filesystem/type_registry.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_TYPE_REGISTRY_HPP -#define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_TYPE_REGISTRY_HPP - -namespace kernel::tests::filesystem::type_registry -{ - //! Deinitialize the FS type registry singleton. - auto deinit() -> void; -} // namespace kernel::tests::filesystem::type_registry - -#endif \ No newline at end of file diff --git a/kernel/kernel/test_support/state_reset_listener.cpp b/kernel/kernel/test_support/state_reset_listener.cpp index e900b31c..948f2f7e 100644 --- a/kernel/kernel/test_support/state_reset_listener.cpp +++ b/kernel/kernel/test_support/state_reset_listener.cpp @@ -1,13 +1,13 @@ #include #include +#include #include -#include #include #include #include #include +#include #include -#include #include #include @@ -42,15 +42,14 @@ struct state_reset_listener : Catch::EventListenerBase std::ignore = kernel::devices::storage::init(); kernel::filesystem::open_file_table::init(); - kernel::filesystem::type_registry::init(); + kernel::filesystem::driver_registry::init(); } void testCaseEnded(Catch::TestCaseStats const &) override { - kernel::tests::filesystem::type_registry::deinit(); + kernel::tests::filesystem::driver_registry::deinit(); kernel::tests::filesystem::device_number_registry::deinit(); kernel::tests::filesystem::vfs::deinit(); - kernel::tests::filesystem::type_registry::deinit(); kernel::tests::filesystem::open_file_table::deinit(); kapi::test_support::devices::deinit(); -- cgit v1.2.3 From d31aa45ef4fe600ba5ac95958407a83f1610407a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 18:42:53 +0200 Subject: kernel/fs: small post-rework cleanup --- kernel/kernel/filesystem/driver_registry.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/driver_registry.cpp b/kernel/kernel/filesystem/driver_registry.cpp index 22bc306d..9fa2d474 100644 --- a/kernel/kernel/filesystem/driver_registry.cpp +++ b/kernel/kernel/filesystem/driver_registry.cpp @@ -79,9 +79,14 @@ namespace kernel::filesystem return std::nullopt; } - auto driver_registry::add(std::string_view name, kstd::shared_ptr descriptor) -> bool + auto driver_registry::add(std::string_view name, kstd::shared_ptr driver) -> bool { - auto result = m_drivers.emplace(name, descriptor); + auto result = m_drivers.emplace(name, driver); + if (!result.second) + { + kstd::println(kstd::print_sink::stderr, "[OS:FS] Tried to register duplicate filesystem driver '{}'!", name); + } + return result.second; } -- cgit v1.2.3 From 652c7a0e49d1caa3660dd80126f1197ebd3786da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 19:20:21 +0200 Subject: kernel/fs: introduce base read_directory API --- .../kernel/filesystem/directory_listing_cursor.hpp | 23 ++++++++++++++++++++++ .../kernel/filesystem/directory_listing_entry.hpp | 23 ++++++++++++++++++++++ kernel/kernel/filesystem/inode.cpp | 12 +++++++++++ kernel/kernel/filesystem/inode.hpp | 13 ++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 kernel/kernel/filesystem/directory_listing_cursor.hpp create mode 100644 kernel/kernel/filesystem/directory_listing_entry.hpp (limited to 'kernel') diff --git a/kernel/kernel/filesystem/directory_listing_cursor.hpp b/kernel/kernel/filesystem/directory_listing_cursor.hpp new file mode 100644 index 00000000..5eb36c7a --- /dev/null +++ b/kernel/kernel/filesystem/directory_listing_cursor.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_DIRECTORY_LISTING_CURSOR_HPP +#define TEACHOS_KERNEL_FILESYSTEM_DIRECTORY_LISTING_CURSOR_HPP + +#include +#include + +namespace kernel::filesystem +{ + + //! A cursor used to keep track of positions in directory listings. + struct directory_listing_cursor + { + constexpr auto friend operator<=>(directory_listing_cursor const &, directory_listing_cursor const &) noexcept + -> std::strong_ordering = default; + constexpr auto friend operator==(directory_listing_cursor const &, directory_listing_cursor const &) noexcept + -> bool = default; + + std::uint64_t value; + }; + +}; // namespace kernel::filesystem + +#endif \ No newline at end of file diff --git a/kernel/kernel/filesystem/directory_listing_entry.hpp b/kernel/kernel/filesystem/directory_listing_entry.hpp new file mode 100644 index 00000000..f3dcf367 --- /dev/null +++ b/kernel/kernel/filesystem/directory_listing_entry.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_DIRECTORY_LISTING_ENTRY_HPP +#define TEACHOS_KERNEL_FILESYSTEM_DIRECTORY_LISTING_ENTRY_HPP + +#include + +#include + +#include + +namespace kernel::filesystem +{ + + //! An entry in a directory listing. + struct directory_listing_entry + { + kstd::string name; + kapi::filesystem::file_type type; + std::uint64_t inode_number; + }; + +}; // namespace kernel::filesystem + +#endif \ No newline at end of file diff --git a/kernel/kernel/filesystem/inode.cpp b/kernel/kernel/filesystem/inode.cpp index 26f523c6..7b290479 100644 --- a/kernel/kernel/filesystem/inode.cpp +++ b/kernel/kernel/filesystem/inode.cpp @@ -1,11 +1,17 @@ #include +#include +#include +#include + #include #include #include +#include #include +#include #include namespace kernel::filesystem @@ -78,6 +84,12 @@ namespace kernel::filesystem return std::nullopt; } + auto inode::read_directory(directory_listing_cursor, std::span) const + -> kstd::result> + { + return kstd::failure(vfs_errc::not_a_directory); + } + auto inode::owning_mount() const noexcept -> kstd::weak_ptr { return m_owning_mount; diff --git a/kernel/kernel/filesystem/inode.hpp b/kernel/kernel/filesystem/inode.hpp index 677c5155..e7de9276 100644 --- a/kernel/kernel/filesystem/inode.hpp +++ b/kernel/kernel/filesystem/inode.hpp @@ -1,6 +1,9 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_INODE_HPP #define TEACHOS_KERNEL_FILESYSTEM_INODE_HPP +#include +#include + #include #include @@ -10,6 +13,7 @@ #include #include #include +#include namespace kernel::filesystem { @@ -104,6 +108,15 @@ namespace kernel::filesystem //! @return a device number if this inode refers to a device, an empty optional otherwise. [[nodiscard]] virtual auto raw_device() const -> std::optional; + //! List the contents of a directory. + //! + //! @param position The current directory listing position. + //! @param entries An output span to store directory entries. + //! @return A pair of the number or read entries and the next listing position on success, an error otherwise. + [[nodiscard]] virtual auto read_directory(directory_listing_cursor position, + std::span entries) const + -> kstd::result>; + //! @} //! @name Mount Resolution -- cgit v1.2.3 From acaa815a253fffeb06471efc9c550e837c3898d8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 23 Aug 2026 22:07:57 +0200 Subject: kernel/fs: devfs: implement read_directory --- kernel/kernel/filesystem/devfs/inode.cpp | 81 ++++++++++ kernel/kernel/filesystem/devfs/inode.hpp | 9 +- kernel/kernel/filesystem/devfs/inode.tests.cpp | 177 +++++++++++++++++++++ .../kernel/test_support/state_reset_listener.cpp | 2 + 4 files changed, 268 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/inode.cpp b/kernel/kernel/filesystem/devfs/inode.cpp index 4153d3ac..033972ec 100644 --- a/kernel/kernel/filesystem/devfs/inode.cpp +++ b/kernel/kernel/filesystem/devfs/inode.cpp @@ -1,15 +1,35 @@ #include +#include +#include +#include +#include +#include + +#include + #include #include +#include +#include #include +#include +#include +#include +#include #include +#include using namespace kstd::units_literals; namespace kernel::filesystem::devfs { + namespace + { + constexpr auto static sentinel = directory_listing_cursor{0xffff}; + } + auto inode::read(std::span, kstd::bytes) const -> kstd::result { return 0_B; @@ -24,4 +44,65 @@ namespace kernel::filesystem::devfs { return true; } + + auto inode::read_directory(directory_listing_cursor position, std::span entries) const + -> kstd::result> + { + auto requested = entries.size(); + if (requested == 0) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + auto devices = kernel::filesystem::device_number_registry::get().all(); + if (devices.empty()) + { + return std::pair{0, position}; + } + + std::ranges::stable_sort(devices, std::ranges::less{}, &kernel::filesystem::device_number_registry::entry::number); + + auto device_number = std::bit_cast(static_cast(position.value)); + auto begin = std::ranges::lower_bound(devices, device_number, std::ranges::less{}, + &kernel::filesystem::device_number_registry::entry::number); + auto end = std::ranges::end(devices); + auto to_read = std::min(requested, static_cast(std::ranges::distance(begin, end))); + + if (to_read == 0) + { + return std::pair{0, position}; + } + + std::ranges::transform(begin, begin + to_read, std::ranges::begin(entries), [](auto const & entry) { + auto type = [&] { + switch (entry.type) + { + case kernel::filesystem::file_type::block: + return kapi::filesystem::file_type::block_device; + case kernel::filesystem::file_type::character: + return kapi::filesystem::file_type::character_device; + case kernel::filesystem::file_type::pipe: + return kapi::filesystem::file_type::fifo; + case kernel::filesystem::file_type::socket: + return kapi::filesystem::file_type::socket; + default: + return kapi::filesystem::file_type::regular; + } + }(); + + return directory_listing_entry{.name = entry.name, + .type = type, + .inode_number = std::bit_cast(entry.number)}; + }); + + auto last_copied = begin + to_read; + if (last_copied == end) + { + return std::pair{to_read, sentinel}; + } + + auto new_cursor = + directory_listing_cursor{static_cast(std::bit_cast(last_copied->number))}; + return std::pair{to_read, new_cursor}; + } } // namespace kernel::filesystem::devfs \ No newline at end of file diff --git a/kernel/kernel/filesystem/devfs/inode.hpp b/kernel/kernel/filesystem/devfs/inode.hpp index e907c02e..b83d484c 100644 --- a/kernel/kernel/filesystem/devfs/inode.hpp +++ b/kernel/kernel/filesystem/devfs/inode.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_DEVFS_INODE_HPP #define TEACHOS_KERNEL_FILESYSTEM_DEVFS_INODE_HPP +#include +#include #include #include @@ -8,13 +10,14 @@ #include #include +#include namespace kernel::filesystem::devfs { //! Inode implementation for the devfs filesystem. //! //! This inode represents root device node in the /dev directory. - struct inode : kernel::filesystem::inode + struct inode final : kernel::filesystem::inode { [[nodiscard]] auto read(std::span buffer, kstd::bytes offset) const -> kstd::result override; @@ -22,6 +25,10 @@ namespace kernel::filesystem::devfs auto write(std::span buffer, kstd::bytes offset) -> kstd::result override; [[nodiscard]] auto is_directory() const -> bool override; + + [[nodiscard]] auto read_directory(directory_listing_cursor position, + std::span entries) const + -> kstd::result> override; }; } // namespace kernel::filesystem::devfs diff --git a/kernel/kernel/filesystem/devfs/inode.tests.cpp b/kernel/kernel/filesystem/devfs/inode.tests.cpp index 0d8ed5d1..581bf6c5 100644 --- a/kernel/kernel/filesystem/devfs/inode.tests.cpp +++ b/kernel/kernel/filesystem/devfs/inode.tests.cpp @@ -1,16 +1,42 @@ #include +#include +#include +#include +#include +#include + +#include +#include + #include #include +#include #include #include #include +#include #include +#include using namespace kstd::units_literals; +namespace +{ + auto make_and_publish(kstd::shared_ptr const & bus, kstd::string name) + -> kstd::shared_ptr + + { + auto device = kstd::make_shared(name, 512_B); + bus->add_child(device); + REQUIRE(kernel::tests::devices::bind(*device)); + REQUIRE(kapi::devices::publish_facet(device, name)); + return device; + } +} // namespace + SCENARIO("Devfs inode creation", "[filesystem][devfs][inode]") { GIVEN("a devfs inode") @@ -56,3 +82,154 @@ SCENARIO("Devfs inode read/write", "[filesystem][devfs][inode]") } } } + +SCENARIO("Devfs inode directory listing", "[filesystem][devfs][inode]") +{ + GIVEN("a devfs inode and no registered devices") + { + auto root = kernel::filesystem::devfs::inode{}; + + THEN("the directory listing is empty") + { + auto entries = kstd::vector{4}; + auto result = root.read_directory(kernel::filesystem::directory_listing_cursor{}, entries); + + REQUIRE(result); + auto [count, next] = *result; + REQUIRE(count == 0); + } + } + + GIVEN("a devfs inode and three registered devices") + { + auto root = kernel::filesystem::devfs::inode{}; + + auto bus = kstd::make_shared("devfs_readdir_bus"); + kapi::devices::get_root_bus()->add_child(bus); + + auto device1 = make_and_publish(bus, "devfs_readdir_device1"); + auto device2 = make_and_publish(bus, "devfs_readdir_device2"); + auto device3 = make_and_publish(bus, "devfs_readdir_device3"); + + WHEN("the directory listing is requested with a buffer large enough for all of them") + { + auto entries = kstd::vector{4}; + auto result = root.read_directory(kernel::filesystem::directory_listing_cursor{}, entries); + + THEN("all devices are listed") + { + REQUIRE(result); + auto [count, next] = *result; + REQUIRE(count == 3); + + auto names = kstd::vector{3}; + for (auto i = 0uz; i < count; ++i) + { + REQUIRE(entries[i].type == kapi::filesystem::file_type::block_device); + names.push_back(entries[i].name); + } + + REQUIRE(std::ranges::find(names, "devfs_readdir_device1") != names.end()); + REQUIRE(std::ranges::find(names, "devfs_readdir_device2") != names.end()); + REQUIRE(std::ranges::find(names, "devfs_readdir_device3") != names.end()); + + AND_THEN("listing again with the returned cursor reports 'end-of-directory'") + { + auto result = root.read_directory(next, entries); + + REQUIRE(result); + auto [count, cursor] = *result; + REQUIRE(count == 0); + REQUIRE(cursor == next); + } + } + } + + WHEN("read_directory is called one entry at a time, chaining the returned cursor") + { + auto seen = kstd::vector{}; + auto position = kernel::filesystem::directory_listing_cursor{}; + + for (auto guard = 0; guard < 4; ++guard) + { + auto one = kstd::vector(1); + auto result = root.read_directory(position, one); + REQUIRE(result); + auto [count, next] = *result; + if (count == 0) + { + break; + } + seen.push_back(one[0].name); + position = next; + } + + THEN("nothing is skipped or duplicated across the paginated calls") + { + REQUIRE(seen.size() == 3); + auto sorted = seen; + std::ranges::sort(sorted); + std::ignore = std::ranges::unique(sorted); + REQUIRE(sorted.size() == 3); + } + } + + REQUIRE(kapi::devices::remove_device(*bus)); + } +} + +SCENARIO("Devfs inode read_directory orders by device number, not registration order", + "[filesystem][devfs][inode][readdir]") +{ + GIVEN("a device that frees the lowest minor number before a later device reuses it") + { + auto root = kernel::filesystem::devfs::inode{}; + + auto bus = kstd::make_shared("devfs_readdir_reuse_bus"); + kapi::devices::get_root_bus()->add_child(bus); + + auto first_out = make_and_publish(bus, "readdir_reuse_first_out"); + auto still_in = make_and_publish(bus, "readdir_reuse_still_in"); + REQUIRE(kapi::devices::remove_device(*first_out)); + auto later_in = make_and_publish(bus, "readdir_reuse_later_in"); + + WHEN("read_directory is called with room for both remaining entries") + { + auto entries = kstd::vector(2); + auto result = root.read_directory(kernel::filesystem::directory_listing_cursor{}, entries); + + THEN("later_in (the reused, lower device number) comes back before still_in, by number, not by " + "when each was registered") + { + REQUIRE(result); + auto [count, next] = *result; + REQUIRE(count == 2); + REQUIRE(entries[0].name == "readdir_reuse_later_in"); + REQUIRE(entries[1].name == "readdir_reuse_still_in"); + } + } + + REQUIRE(kapi::devices::remove_device(*bus)); + } +} + +SCENARIO("Devfs read_directory rejects non-directory inodes", "[filesystem][devfs][inode][readdir]") +{ + GIVEN("a device_inode, which does not represent a directory") + { + auto bus = kstd::make_shared("devfs_readdir_nondir_bus"); + kapi::devices::get_root_bus()->add_child(bus); + auto device = make_and_publish(bus, "readdir_nondir_device"); + auto node = kernel::filesystem::device_inode{device}; + + THEN("read_directory falls through to the base class default rather than enumerating anything") + { + auto entries = kstd::vector(1); + auto result = node.read_directory(kernel::filesystem::directory_listing_cursor{}, entries); + + REQUIRE_FALSE(result); + } + + REQUIRE(kapi::devices::remove_device(*bus)); + } +} \ No newline at end of file diff --git a/kernel/kernel/test_support/state_reset_listener.cpp b/kernel/kernel/test_support/state_reset_listener.cpp index 948f2f7e..59f103b7 100644 --- a/kernel/kernel/test_support/state_reset_listener.cpp +++ b/kernel/kernel/test_support/state_reset_listener.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ struct state_reset_listener : Catch::EventListenerBase std::ignore = kernel::devices::storage::init(); kernel::filesystem::open_file_table::init(); + std::ignore = kernel::filesystem::device_number_registry::get(); kernel::filesystem::driver_registry::init(); } -- cgit v1.2.3 From 6ddd19c70a127098766807638dbf3bf63fc91f89 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 10:22:47 +0200 Subject: kernel/fs: remove file type --- kernel/kernel/filesystem/devfs/inode.cpp | 19 +------------------ kernel/kernel/filesystem/device_number_registry.cpp | 1 - kernel/kernel/filesystem/device_number_registry.hpp | 4 ++-- .../filesystem/device_number_registry.tests.cpp | 7 +++---- kernel/kernel/filesystem/file_type.hpp | 18 ------------------ kernel/kernel/filesystem/file_type_bindings.hpp | 7 +++---- kernel/kernel/filesystem/vfs.cpp | 4 ++-- 7 files changed, 11 insertions(+), 49 deletions(-) delete mode 100644 kernel/kernel/filesystem/file_type.hpp (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/inode.cpp b/kernel/kernel/filesystem/devfs/inode.cpp index 033972ec..b1ac17c2 100644 --- a/kernel/kernel/filesystem/devfs/inode.cpp +++ b/kernel/kernel/filesystem/devfs/inode.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include @@ -74,24 +73,8 @@ namespace kernel::filesystem::devfs } std::ranges::transform(begin, begin + to_read, std::ranges::begin(entries), [](auto const & entry) { - auto type = [&] { - switch (entry.type) - { - case kernel::filesystem::file_type::block: - return kapi::filesystem::file_type::block_device; - case kernel::filesystem::file_type::character: - return kapi::filesystem::file_type::character_device; - case kernel::filesystem::file_type::pipe: - return kapi::filesystem::file_type::fifo; - case kernel::filesystem::file_type::socket: - return kapi::filesystem::file_type::socket; - default: - return kapi::filesystem::file_type::regular; - } - }(); - return directory_listing_entry{.name = entry.name, - .type = type, + .type = entry.type, .inode_number = std::bit_cast(entry.number)}; }); diff --git a/kernel/kernel/filesystem/device_number_registry.cpp b/kernel/kernel/filesystem/device_number_registry.cpp index 42663dba..64cdb062 100644 --- a/kernel/kernel/filesystem/device_number_registry.cpp +++ b/kernel/kernel/filesystem/device_number_registry.cpp @@ -1,7 +1,6 @@ #include #include -#include #include #include diff --git a/kernel/kernel/filesystem/device_number_registry.hpp b/kernel/kernel/filesystem/device_number_registry.hpp index 2391f179..2f0f0226 100644 --- a/kernel/kernel/filesystem/device_number_registry.hpp +++ b/kernel/kernel/filesystem/device_number_registry.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_DEVICE_NUMBER_REGISTRY_HPP #define TEACHOS_KERNEL_FILESYSTEM_DEVICE_NUMBER_REGISTRY_HPP -#include - #include #include #include @@ -23,6 +21,8 @@ namespace kernel::filesystem //! A registry to assign stable device numbers to published devices. struct device_number_registry final : kapi::devices::facet_registry_observer { + using file_type = kapi::filesystem::file_type; + //! A single numbered device. //! //! Theses entries are used, for example, in devfs to provide access to devices. diff --git a/kernel/kernel/filesystem/device_number_registry.tests.cpp b/kernel/kernel/filesystem/device_number_registry.tests.cpp index 913acf9a..60e17337 100644 --- a/kernel/kernel/filesystem/device_number_registry.tests.cpp +++ b/kernel/kernel/filesystem/device_number_registry.tests.cpp @@ -1,6 +1,5 @@ #include -#include #include #include @@ -66,7 +65,7 @@ SCENARIO("Device number registry resolves and numbers published block devices", AND_THEN("resolve() finds the device by number") { - REQUIRE(registry.resolve(all[0].number, kernel::filesystem::file_type::block)); + REQUIRE(registry.resolve(all[0].number, kapi::filesystem::file_type::block_device)); } AND_THEN("number_of() finds the device number") @@ -79,7 +78,7 @@ SCENARIO("Device number registry resolves and numbers published block devices", auto number = registry.number_of(*device); CHECK(number); - auto resolved = registry.resolve(*number, kernel::filesystem::file_type::block); + auto resolved = registry.resolve(*number, kapi::filesystem::file_type::block_device); CHECK(resolved); REQUIRE(resolved == device); @@ -105,7 +104,7 @@ SCENARIO("Device number registry resolves and numbers published block devices", THEN("resolve() does not report it anymore") { - REQUIRE(!registry.resolve(*number, kernel::filesystem::file_type::block)); + REQUIRE(!registry.resolve(*number, kapi::filesystem::file_type::block_device)); } } } diff --git a/kernel/kernel/filesystem/file_type.hpp b/kernel/kernel/filesystem/file_type.hpp deleted file mode 100644 index 71370ea6..00000000 --- a/kernel/kernel/filesystem/file_type.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_KERNEL_FILESYSTEM_FILE_TYPE_HPP -#define TEACHOS_KERNEL_FILESYSTEM_FILE_TYPE_HPP - -namespace kernel::filesystem -{ - - //! POSIX file types. - enum struct file_type - { - block, - character, - pipe, - socket, - }; - -} // namespace kernel::filesystem - -#endif diff --git a/kernel/kernel/filesystem/file_type_bindings.hpp b/kernel/kernel/filesystem/file_type_bindings.hpp index b4338024..da8e4efc 100644 --- a/kernel/kernel/filesystem/file_type_bindings.hpp +++ b/kernel/kernel/filesystem/file_type_bindings.hpp @@ -1,7 +1,6 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_FILE_TYPE_BINDINGS_HPP #define TEACHOS_KERNEL_FILESYSTEM_FILE_TYPE_BINDINGS_HPP -#include #include #include @@ -15,15 +14,15 @@ namespace kernel::filesystem struct file_type_binding // NOLINT(cppcoreguidelines-pro-type-member-init) { kapi::capabilities::facet_id facet; - file_type posix_type; + kapi::filesystem::file_type posix_type; }; //! Predefined bindings for facet + file type //! //! This array associates published facets with files types. constexpr auto inline file_type_bindings = std::array{ - file_type_binding{kapi::filesystem::character_special_file::id, file_type::character}, - file_type_binding{ kapi::filesystem::block_special_file::id, file_type::block}, + file_type_binding{kapi::filesystem::character_special_file::id, kapi::filesystem::file_type::character_device}, + file_type_binding{ kapi::filesystem::block_special_file::id, kapi::filesystem::file_type::block_device}, }; } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index d8bcb6b6..4645fd54 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -147,7 +146,8 @@ namespace kernel::filesystem return kstd::failure(vfs_errc::no_such_device); } - auto type = inode->is_block_device() ? file_type::block : file_type::character; + auto type = inode->is_block_device() ? kapi::filesystem::file_type::block_device + : kapi::filesystem::file_type::character_device; auto resolved_device = device_number_registry::get().resolve(*number, type); if (!resolved_device) { -- cgit v1.2.3 From 3bf74c2494148f4de14ad0e59e4b2cd473bb650a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 10:32:22 +0200 Subject: kernel/fs: devfs: simplify directory listing --- kernel/kernel/filesystem/devfs/inode.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/inode.cpp b/kernel/kernel/filesystem/devfs/inode.cpp index b1ac17c2..67f03768 100644 --- a/kernel/kernel/filesystem/devfs/inode.cpp +++ b/kernel/kernel/filesystem/devfs/inode.cpp @@ -47,12 +47,17 @@ namespace kernel::filesystem::devfs auto inode::read_directory(directory_listing_cursor position, std::span entries) const -> kstd::result> { - auto requested = entries.size(); + auto const requested = entries.size(); if (requested == 0) { return kstd::failure(vfs_errc::invalid_argument); } + if (position == sentinel) + { + return std::pair{0, sentinel}; + } + auto devices = kernel::filesystem::device_number_registry::get().all(); if (devices.empty()) { @@ -61,11 +66,12 @@ namespace kernel::filesystem::devfs std::ranges::stable_sort(devices, std::ranges::less{}, &kernel::filesystem::device_number_registry::entry::number); - auto device_number = std::bit_cast(static_cast(position.value)); - auto begin = std::ranges::lower_bound(devices, device_number, std::ranges::less{}, - &kernel::filesystem::device_number_registry::entry::number); - auto end = std::ranges::end(devices); - auto to_read = std::min(requested, static_cast(std::ranges::distance(begin, end))); + auto const device_number = kapi::filesystem::device_number{static_cast(position.value >> 8), + static_cast(position.value & 0xff)}; + auto const begin = std::ranges::lower_bound(devices, device_number, std::ranges::less{}, + &kernel::filesystem::device_number_registry::entry::number); + auto const end = std::ranges::end(devices); + auto const to_read = std::min(requested, static_cast(std::ranges::distance(begin, end))); if (to_read == 0) { @@ -78,14 +84,15 @@ namespace kernel::filesystem::devfs .inode_number = std::bit_cast(entry.number)}; }); - auto last_copied = begin + to_read; + auto const last_copied = begin + to_read; if (last_copied == end) { return std::pair{to_read, sentinel}; } - auto new_cursor = - directory_listing_cursor{static_cast(std::bit_cast(last_copied->number))}; + auto const new_device_number = last_copied->number; + auto const new_cursor = directory_listing_cursor{static_cast(new_device_number.minor) | + (static_cast(new_device_number.major) << 8)}; return std::pair{to_read, new_cursor}; } } // namespace kernel::filesystem::devfs \ No newline at end of file -- cgit v1.2.3 From a8bd597ed30f4d57bb8ec348b66f13a90c197b69 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 10:50:05 +0200 Subject: kernel/fs: devfs: fix directory listing sentinel The previous sentinel value would have prevent a device with major:minor 255:255 from showing up, if the read buffer was small enough to just barely not read that device in one go. The new value is an actually invalid device number, so it does not preclude any devices from showing up in directory listings. --- kernel/kernel/filesystem/devfs/inode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/devfs/inode.cpp b/kernel/kernel/filesystem/devfs/inode.cpp index 67f03768..8813eb2a 100644 --- a/kernel/kernel/filesystem/devfs/inode.cpp +++ b/kernel/kernel/filesystem/devfs/inode.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,7 @@ namespace kernel::filesystem::devfs { namespace { - constexpr auto static sentinel = directory_listing_cursor{0xffff}; + constexpr auto static sentinel = directory_listing_cursor{std::numeric_limits::max()}; } auto inode::read(std::span, kstd::bytes) const -> kstd::result -- cgit v1.2.3 From 98fff0dc733050d8bbdfba5235de918ba15fee0e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 10:59:02 +0200 Subject: kernel/fs: extract module registrations --- kernel/CMakeLists.txt | 3 +++ kernel/kernel/filesystem/devfs/filesystem.cpp | 16 --------------- kernel/kernel/filesystem/devfs/module.cpp | 28 ++++++++++++++++++++++++++ kernel/kernel/filesystem/ext2/filesystem.cpp | 21 ++----------------- kernel/kernel/filesystem/ext2/module.cpp | 26 ++++++++++++++++++++++++ kernel/kernel/filesystem/rootfs/filesystem.cpp | 17 ---------------- kernel/kernel/filesystem/rootfs/module.cpp | 28 ++++++++++++++++++++++++++ 7 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 kernel/kernel/filesystem/devfs/module.cpp create mode 100644 kernel/kernel/filesystem/ext2/module.cpp create mode 100644 kernel/kernel/filesystem/rootfs/module.cpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 2cca2dda..6f998084 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -72,15 +72,18 @@ target_sources("kernel_lib" PRIVATE # DevFS Filesystem "kernel/filesystem/devfs/filesystem.cpp" "kernel/filesystem/devfs/inode.cpp" + "kernel/filesystem/devfs/module.cpp" # ext2 Filesystem "kernel/filesystem/ext2/error.cpp" "kernel/filesystem/ext2/filesystem.cpp" "kernel/filesystem/ext2/inode.cpp" + "kernel/filesystem/ext2/module.cpp" # Rootfs Filesystem "kernel/filesystem/rootfs/filesystem.cpp" "kernel/filesystem/rootfs/inode.cpp" + "kernel/filesystem/rootfs/module.cpp" ) file(GLOB_RECURSE KERNEL_HEADERS diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index a7c8e50c..0de513a7 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -21,21 +20,6 @@ namespace kernel::filesystem::devfs { - struct descriptor final : kernel::filesystem::driver_descriptor - { - [[nodiscard]] auto name() const noexcept -> std::string_view override - { - return "devfs"; - } - - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override - { - return kstd::make_shared(); - } - }; - - [[gnu::used]] - constexpr auto registration = driver_module{}; static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(devfs::filesystem)); diff --git a/kernel/kernel/filesystem/devfs/module.cpp b/kernel/kernel/filesystem/devfs/module.cpp new file mode 100644 index 00000000..a7a1aca9 --- /dev/null +++ b/kernel/kernel/filesystem/devfs/module.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +#include + +namespace +{ + + struct descriptor final : kernel::filesystem::driver_descriptor + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "devfs"; + } + + [[nodiscard]] auto make_instance() const -> kernel::filesystem::filesystem::filesystem_ptr override + { + return kstd::make_shared(); + } + }; + + [[gnu::used]] + constexpr auto registration = kernel::filesystem::driver_module{}; + +} // namespace \ No newline at end of file diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 579094e0..92945eb2 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -1,6 +1,5 @@ #include -#include #include #include #include @@ -35,24 +34,6 @@ using namespace kstd::units_literals; namespace kernel::filesystem::ext2 { - struct descriptor final : kernel::filesystem::driver_descriptor - { - [[nodiscard]] auto name() const noexcept -> std::string_view override - { - return "ext2"; - } - - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override - { - return kstd::make_shared(); - } - }; - - [[gnu::used]] - constexpr auto registration = driver_module{}; - - static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); - namespace { [[nodiscard]] auto bitmap_is_set(kstd::vector const & bitmap, size_t index) -> bool @@ -74,6 +55,8 @@ namespace kernel::filesystem::ext2 read_only_compatible_features::large_file_support; } // namespace + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + auto filesystem::indirect_levels(mount_state const & state) const -> std::array { return { diff --git a/kernel/kernel/filesystem/ext2/module.cpp b/kernel/kernel/filesystem/ext2/module.cpp new file mode 100644 index 00000000..e6b14307 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/module.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +#include + +namespace +{ + struct descriptor final : kernel::filesystem::driver_descriptor + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] auto make_instance() const -> kernel::filesystem::filesystem::filesystem_ptr override + { + return kstd::make_shared(); + } + }; + + [[gnu::used]] + constexpr auto registration = kernel::filesystem::driver_module{}; +} // namespace diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index a14addba..4618fd69 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -1,6 +1,5 @@ #include -#include #include #include #include @@ -17,22 +16,6 @@ namespace kernel::filesystem::rootfs { - struct descriptor final : kernel::filesystem::driver_descriptor - { - [[nodiscard]] auto name() const noexcept -> std::string_view override - { - return "rootfs"; - } - - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override - { - return kstd::make_shared(); - } - }; - - [[gnu::used]] - constexpr auto registration = driver_module{}; - static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(rootfs::filesystem)); auto filesystem::probe(inode_ptr const & inode) const -> kstd::result diff --git a/kernel/kernel/filesystem/rootfs/module.cpp b/kernel/kernel/filesystem/rootfs/module.cpp new file mode 100644 index 00000000..464120b2 --- /dev/null +++ b/kernel/kernel/filesystem/rootfs/module.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#include + +#include + +namespace +{ + + struct descriptor final : kernel::filesystem::driver_descriptor + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "rootfs"; + } + + [[nodiscard]] auto make_instance() const -> kernel::filesystem::filesystem::filesystem_ptr override + { + return kstd::make_shared(); + } + }; + + [[gnu::used]] + constexpr auto registration = kernel::filesystem::driver_module{}; + +} // namespace \ No newline at end of file -- cgit v1.2.3 From 2a09bbc8f813d28d69768ba9375b637e2ba8bd8d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 16:57:24 +0200 Subject: kernel/fs: ext2: cosmetic cleanup --- kernel/kernel/filesystem/ext2/error.cpp | 3 + kernel/kernel/filesystem/ext2/error.hpp | 3 +- kernel/kernel/filesystem/ext2/filesystem.cpp | 402 +++++++++++++-------- kernel/kernel/filesystem/ext2/filesystem.hpp | 93 ++++- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 6 - kernel/kernel/filesystem/ext2/inode.cpp | 4 +- kernel/kernel/filesystem/ext2/inode.tests.cpp | 9 +- .../filesystem/ext2/linked_directory_entry.hpp | 3 +- 8 files changed, 332 insertions(+), 191 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/error.cpp b/kernel/kernel/filesystem/ext2/error.cpp index ffe49460..73921379 100644 --- a/kernel/kernel/filesystem/ext2/error.cpp +++ b/kernel/kernel/filesystem/ext2/error.cpp @@ -42,6 +42,8 @@ namespace kernel::filesystem::ext2 return "not enough inodes"; case ext2_errc::unsupported_features_present: return "unsupported features present"; + case ext2_errc::name_too_long: + return "name too long"; default: return "unknown ext2 error"; }; @@ -54,6 +56,7 @@ namespace kernel::filesystem::ext2 { case ext2_errc::invalid_magic_number: case ext2_errc::invalid_root_inode: + case ext2_errc::name_too_long: if (condition.category() == kernel::filesystem::vfs_category()) { return condition.value() == static_cast(kernel::filesystem::vfs_errc::invalid_filesystem); diff --git a/kernel/kernel/filesystem/ext2/error.hpp b/kernel/kernel/filesystem/ext2/error.hpp index 59df1669..edd0d017 100644 --- a/kernel/kernel/filesystem/ext2/error.hpp +++ b/kernel/kernel/filesystem/ext2/error.hpp @@ -21,7 +21,8 @@ namespace kernel::filesystem::ext2 failed_to_read_block_group_descriptors, not_enough_free_blocks, not_enough_inodes, - unsupported_features_present + unsupported_features_present, + name_too_long, }; [[nodiscard]] auto ext2_category() noexcept -> kstd::error_category const &; diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 92945eb2..45d4efeb 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -34,43 +35,53 @@ using namespace kstd::units_literals; namespace kernel::filesystem::ext2 { + //! Check that this driver class is stateless. + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + namespace { - [[nodiscard]] auto bitmap_is_set(kstd::vector const & bitmap, size_t index) -> bool + //! Check if the given bit has the bit at the given index set. + //! + //! @warning This function will panic if the bit index is out-of-bounds for the given bitmap. + //! + //! @param bitmap The bitmap to check. + //! @param index The index of the bit to check. + [[nodiscard]] auto bitmap_is_set(kstd::vector const & bitmap, size_t index) -> bool { auto const byte_index = index / 8; auto const bit_index = index % 8; - return (bitmap.at(byte_index) & static_cast(1u << bit_index)) != 0; + return (bitmap.at(byte_index) & static_cast(1u << bit_index)) != std::byte{}; } - auto bitmap_set(kstd::vector & bitmap, size_t index) -> void + //! Set the bit at the given index in the given bitmap. + //! + //! @warning This function will panic if the bit index is out-of-bounds for the given bitmap. + //! + //! @param bitmap The bitmap to manipulate. + //! @param index The index of the bit to set. + auto bitmap_set(kstd::vector & bitmap, size_t index) -> void { auto const byte_index = index / 8; auto const bit_index = index % 8; - bitmap.at(byte_index) |= static_cast(1u << bit_index); + bitmap.at(byte_index) |= static_cast(1u << bit_index); } - auto supported_incompatible_features = incompatible_features::file_types_in_directory_entries; - auto supported_ro_compatible_features = read_only_compatible_features::sparse_superblock_copies | // - read_only_compatible_features::large_file_support; - } // namespace + //! The set of "incompatible" Extended Filesystem features supported by this driver. + constexpr auto supported_incompatible_features = incompatible_features::file_types_in_directory_entries; - static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + //! The set of "read-only" Extended Filesystem features supported by this driver. + constexpr auto supported_ro_compatible_features = read_only_compatible_features::sparse_superblock_copies | // + read_only_compatible_features::large_file_support; - auto filesystem::indirect_levels(mount_state const & state) const -> std::array - { - return { - {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, - {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, - {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} - }; - } + //! A set of permissions allowing all access to everyone. + constexpr auto no_access_restrictions = std::uint16_t{0x01FF}; + } // namespace auto filesystem::probe(inode_ptr const & backing_inode) const -> kstd::result { auto superblock = ext2::superblock{}; - auto bytes = std::as_writable_bytes(std::span{&superblock, 1}); - auto read_result = backing_inode->read(bytes, constants::superblock_offset); + auto const bytes = kstd::raw_bytes(superblock); + auto const read_result = backing_inode->read(bytes, constants::superblock_offset); if (!read_result) { @@ -93,12 +104,12 @@ namespace kernel::filesystem::ext2 auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result { - auto mount_state = kstd::make_shared(); + auto const mount_state = kstd::make_shared(); auto & [superblock, block_group_descriptors, backing] = *mount_state; backing = backing_inode; - auto superblock_bytes = std::as_writable_bytes(std::span{&superblock, 1}); + auto const superblock_bytes = kstd::raw_bytes(superblock); if (auto read_result = backing->read(superblock_bytes, constants::superblock_offset); !read_result) { return kstd::failure(read_result.error()); @@ -113,7 +124,7 @@ namespace kernel::filesystem::ext2 auto const num_block_groups = (superblock.blocks_count + blocks_per_group - 1) / blocks_per_group; block_group_descriptors = kstd::vector(num_block_groups); - auto block_group_descriptors_bytes = std::as_writable_bytes(std::span{block_group_descriptors}); + auto const block_group_descriptors_bytes = kstd::raw_bytes(block_group_descriptors); if (auto read_result = backing->read(block_group_descriptors_bytes, block_group_descriptor_table_offset(*mount_state)); !read_result) @@ -121,7 +132,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(read_result.error()); } - auto root = read_inode(constants::root_inode_number, *mount_state); + auto const root = read_inode(constants::root_inode_number, *mount_state); if (!root) { @@ -139,27 +150,27 @@ namespace kernel::filesystem::ext2 auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const -> kstd::result { - if (!parent) + auto const ext2_parent = static_pointer_cast(parent); + if (!ext2_parent) { return kstd::failure(vfs_errc::invalid_inode); } - if (!parent->is_directory()) + if (!ext2_parent->is_directory()) { return kstd::failure(vfs_errc::not_a_directory); } - auto mount_state = static_pointer_cast(driver_data); + auto const mount_state = static_pointer_cast(driver_data); if (!mount_state) { - return kstd::failure(vfs_errc::invalid_driver_data); + return kstd::failure(vfs_errc::not_mounted); } - auto * ext2_parent = static_cast(parent.get()); auto const & inode_data = ext2_parent->data(); - kstd::vector buffer(block_size(*mount_state).value); + auto buffer = kstd::vector{block_size(*mount_state).value}; - for (uint32_t i = 0; i < inode_block_count(inode_data, *mount_state); ++i) + for (auto i = 0u; i < block_count(inode_data, *mount_state); ++i) { auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data, *mount_state); if (!global_block_number) @@ -167,24 +178,24 @@ namespace kernel::filesystem::ext2 return kstd::failure(global_block_number.error()); } - if (auto read_result = read_block(*global_block_number, buffer.data(), *mount_state); !read_result) + if (auto result = read_block(*global_block_number, buffer.data(), *mount_state); !result) { - return kstd::failure(read_result.error()); + return kstd::failure(result.error()); } - auto const * entry = reinterpret_cast(buffer.data()); - auto bytes_read = 0_B; + auto entry = reinterpret_cast(buffer.data()); + auto read = 0_B; - while (bytes_read < block_size(*mount_state) && entry->inode != 0) + while (read < block_size(*mount_state) && entry->inode != 0) { - auto const entry_name = std::string_view{entry->name.data(), entry->name_len}; + auto const entry_name = std::string_view{&entry->name_start, entry->name_len}; if (entry_name == name) { return read_inode(entry->inode, *mount_state); } - bytes_read += kstd::bytes{entry->rec_len}; - entry = reinterpret_cast(buffer.data() + bytes_read); + read += kstd::bytes{entry->rec_len}; + entry = reinterpret_cast(buffer.data() + read); } } @@ -205,19 +216,19 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_a_directory); } - auto is_device = kapi::filesystem::is_device(type); + auto const is_device = kapi::filesystem::is_device(type); if (is_device && !raw_device) { return kstd::failure(vfs_errc::invalid_argument); } - auto * ext2_parent = static_cast(parent.get()); + auto const ext2_parent = static_pointer_cast(parent); if (!ext2_parent) { return kstd::failure(vfs_errc::invalid_argument); } - auto mount_state = static_pointer_cast(driver_data); + auto const mount_state = static_pointer_cast(driver_data); if (!mount_state) { return kstd::failure(vfs_errc::invalid_driver_data); @@ -231,65 +242,92 @@ namespace kernel::filesystem::ext2 auto inode_number = maybe_inode_number.value(); - inode_data new_inode_data{}; + auto data = inode_data{}; - uint16_t const full_access_mode = 0x01FF; // TODO use correct access rights - new_inode_data.mode = map_vfs_inode_type_into_inode_mode(type, full_access_mode); - new_inode_data.size = 0; - new_inode_data.dir_acl = 0; - new_inode_data.links_count = 1; - new_inode_data.blocks = 0; - new_inode_data.block.fill(0); + // TODO: use correct access rights + data.mode = map_vfs_inode_type_into_inode_mode(type, no_access_restrictions); + data.size = 0; + data.dir_acl = 0; + data.links_count = 1; + data.blocks = 0; + data.block.fill(0); if (is_device) { - new_inode_data.block[0] = static_cast(raw_device->minor) | // - (static_cast(raw_device->major) << 8); + data.block[0] = static_cast(raw_device->minor) | // + (static_cast(raw_device->major) << 8); } - // TODO preallocate blocks depending on type and m_superblock.prealloc_dir_blocks or m_superblock.prealloc_blocks; + auto created = kstd::make_shared(inode_number, data); + created->set_owning_mount(ext2_parent->owning_mount().lock()); - if (auto result = add_directory_entry(ext2_parent, name, inode_number, new_inode_data.mode, *mount_state); !result) + // 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, *created, data.mode, *mount_state); !result) { return kstd::failure(result.error()); } - 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()) + if (created->is_directory()) { // TODO increment used_dirs_count in block group descriptor - if (auto result = init_directory(new_inode, ext2_parent, *mount_state); !result) + if (auto result = init_directory(*created, *ext2_parent, *mount_state); !result) { return kstd::failure(result.error()); } } - if (auto write_result = write_inode(inode_number, new_inode->data(), *mount_state); !write_result) + if (auto result = write_inode(inode_number, created->data(), *mount_state); !result) { - return kstd::failure(write_result.error()); + return kstd::failure(result.error()); } - return new_inode; + return created; + } + + auto filesystem::block_size(mount_state const & state) const -> kstd::bytes + { + return kstd::bytes{constants::base_block_size.value << state.superblock.log_block_size}; + } + + auto filesystem::revision_level(mount_state const & state) const -> uint32_t + { + return state.superblock.rev_level; + } + + auto filesystem::inode_size(mount_state const & state) const -> kstd::bytes + { + return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size); + } + + auto filesystem::block_count(inode_data const & data, mount_state const & state) const -> uint32_t + { + return data.blocks / (2 << state.superblock.log_block_size); } - auto filesystem::add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, - [[maybe_unused]] uint16_t mode, mount_state & state) -> kstd::result + auto filesystem::indirect_levels(mount_state const & state) const -> std::array { - 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); + return { + {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, + {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, + {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} + }; + } + + auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, + mount_state & state) -> kstd::result + { + auto const last_block_index = block_count(directory.data(), state) - 1; + auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, directory.data(), state); if (!global_block) { return kstd::failure(global_block.error()); } - kstd::vector buffer(block_size(state).value); - if (auto read_result = read_block(*global_block, buffer.data(), state); !read_result) + auto buffer = kstd::vector{block_size(state).value}; + if (auto result = read_block(*global_block, buffer.data(), state); !result) { - return kstd::failure(read_result.error()); + return kstd::failure(result.error()); } // TODO handle "gaps" in directory entries (e.g., after deletions) in the current implementation, we only @@ -298,6 +336,11 @@ namespace kernel::filesystem::ext2 while (true) { auto const * entry = reinterpret_cast(buffer.data() + offset); + auto f = std::string_view{&entry->name_start, entry->name_len}; + if (f.length() == 255) + { + break; + } if (offset + kstd::bytes{entry->rec_len} >= block_size(state)) { break; @@ -315,84 +358,137 @@ namespace kernel::filesystem::ext2 if (kstd::bytes{last_entry->rec_len} - last_entry_actual_len >= needed_rec_len) { 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, state); + auto entry_offset = offset + last_entry_actual_len; + auto entry = write_directory_entry_to_buffer(buffer, entry_offset, child, name, file_type); + if (!entry) + { + return kstd::failure(entry.error()); + } + + auto remainder = block_size(state) - entry_offset; + (*entry)->rec_len = remainder.value; + return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data(), state); }) .transform([](auto) {}); } else { - if (!ext2_parent->append_blocks(1)) + if (!directory.append_blocks(1)) { return kstd::failure(ext2_errc::not_enough_free_blocks); } - auto const new_block_index = inode_block_count(ext2_parent->data(), state) - 1; + auto const new_block_index = block_count(directory.data(), state) - 1; auto const new_global_block = - map_inode_block_index_to_global_block_number(new_block_index, ext2_parent->data(), state); + map_inode_block_index_to_global_block_number(new_block_index, directory.data(), state); if (!new_global_block) { return kstd::failure(new_global_block.error()); } 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 entry = write_directory_entry_to_buffer(buffer, 0_B, child, name, file_type); + if (!entry) + { + return kstd::failure(entry.error()); + } + + auto remainder = block_size(state); + (*entry)->rec_len = remainder.value; + + if (auto result = new_global_block.and_then( [&](auto block_number) { return write_block(block_number, buffer.data(), state); }); - !update_result) + !result) { - return kstd::failure(update_result.error()); + return kstd::failure(result.error()); } } - 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 size = block_count(directory.data(), state) * block_size(state); + directory.data_mutable().size = size.value; + return write_inode(directory.number(), directory.data(), state); } - auto filesystem::init_directory(kstd::shared_ptr const & new_inode, - kernel::filesystem::ext2::inode * parent_inode, mount_state & state) - -> kstd::result + auto filesystem::init_directory(inode & directory, inode & parent, mount_state & state) -> kstd::result { - if (!new_inode->append_blocks(1)) + if (!directory.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(), state); + auto const global_block = map_inode_block_index_to_global_block_number(0, directory.data(), state); if (!global_block) { return kstd::failure(global_block.error()); } - kstd::vector 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((8u + 1 + 3u) & ~3u); - auto * entry = reinterpret_cast(buffer.data()); - entry->rec_len = dot_actual_len.value; + auto buffer = kstd::vector{block_size(state).value}; + auto dot = write_directory_entry_to_buffer(buffer, 0_B, directory, ".", kapi::filesystem::file_type::directory); - write_directory_entry_to_buffer(buffer.data(), dot_actual_len, parent_inode->number(), "..", 2, state); + if (!dot) + { + return kstd::failure(dot.error()); + } + + auto dot_dot_offset = kstd::bytes{(*dot)->rec_len}; + auto dot_dot = + write_directory_entry_to_buffer(buffer, dot_dot_offset, parent, "..", kapi::filesystem::file_type::directory); + if (!dot_dot) + { + return kstd::failure(dot_dot.error()); + } + auto remainder = block_size(state) - dot_dot_offset; + (*dot_dot)->rec_len = remainder.value; // '..' inside the new dir counts as an extra hard link to the parent - auto & parent_inode_data = parent_inode->data_mutable(); + auto & parent_inode_data = parent.data_mutable(); parent_inode_data.links_count++; - return write_inode(parent_inode->number(), parent_inode_data, state) + return write_inode(parent.number(), parent_inode_data, state) .and_then([&]() { return global_block; }) .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, mount_state & state) -> void + auto filesystem::write_directory_entry_to_buffer(std::span buffer, kstd::bytes offset, inode & target, + std::string_view name, kapi::filesystem::file_type type) + -> kstd::result { - auto const name_len = static_cast(name.size()); - auto * entry = reinterpret_cast(block_buffer + offset); - entry->inode = child_inode_number; - entry->rec_len = static_cast(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 const name_length = static_cast(name.size()); + auto const record_size = (sizeof(linked_directory_entry) - 1 + name_length + 3u) & ~3u; + if (buffer.size() - offset.value < record_size) + { + // TODO: improve error code. + return kstd::failure(vfs_errc::invalid_argument); + } + + auto * entry = reinterpret_cast(buffer.data() + offset); + entry->inode = target.number(); + entry->rec_len = record_size; + entry->name_len = name_length; + entry->file_type = [=] { + switch (type) + { + case kapi::filesystem::file_type::regular: + return 1; + case kapi::filesystem::file_type::directory: + return 2; + case kapi::filesystem::file_type::character_device: + return 3; + case kapi::filesystem::file_type::block_device: + return 4; + case kapi::filesystem::file_type::fifo: + return 5; + case kapi::filesystem::file_type::socket: + return 6; + case kapi::filesystem::file_type::symbolic_link: + return 7; + default: + return 0; + } + }(); + kstd::libc::memcpy(&entry->name_start, name.data(), name_length); + return kstd::success(entry); } auto filesystem::read_inode(uint32_t inode_number, mount_state const & state) const @@ -402,8 +498,7 @@ namespace kernel::filesystem::ext2 { auto new_inode_data = inode_data{}; - if (auto read_result = state.backing_inode->read(as_writable_bytes(std::span{&new_inode_data, 1}), *inode_offset); - !read_result) + if (auto read_result = state.backing_inode->read(kstd::raw_bytes(new_inode_data), *inode_offset); !read_result) { return kstd::failure(read_result.error()); } @@ -423,7 +518,7 @@ namespace kernel::filesystem::ext2 { if (auto inode_offset = calculate_inode_offset(inode_number, state)) { - return state.backing_inode->write(as_bytes(std::span{&data, 1}), *inode_offset).transform([](auto) {}); + return state.backing_inode->write(kstd::raw_bytes(data), *inode_offset).transform([](auto) {}); } else { @@ -471,7 +566,7 @@ namespace kernel::filesystem::ext2 continue; } - kstd::vector block_bitmap(block_size(state).value, 0); + auto block_bitmap = kstd::vector{block_size(state).value}; if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap.data(), state); !read_result) { return kstd::failure(read_result.error()); @@ -502,7 +597,7 @@ namespace kernel::filesystem::ext2 // TODO update all block group descriptors if (auto write_result = - backing_inode->write(as_bytes(std::span{&block_group_descriptor, 1}), + backing_inode->write(kstd::raw_bytes(block_group_descriptor), block_group_descriptor_table_offset(state) + block_group_descriptor_index * kstd::size_of(block_group_descriptor)); !write_result) @@ -513,7 +608,7 @@ namespace kernel::filesystem::ext2 } // TODO update all superblock copies - if (auto write_result = backing_inode->write(as_bytes(std::span{&superblock, 1}), constants::superblock_offset); + if (auto write_result = backing_inode->write(kstd::raw_bytes(superblock), constants::superblock_offset); !write_result) { return kstd::failure(write_result.error()); @@ -545,7 +640,7 @@ namespace kernel::filesystem::ext2 continue; } - kstd::vector inode_bitmap(block_size(state).value, 0); + auto inode_bitmap = kstd::vector{block_size(state).value}; if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap.data(), state); !read_result) { return kstd::failure(read_result.error()); @@ -649,8 +744,7 @@ namespace kernel::filesystem::ext2 auto const block_start_offset = block_number * block_size(state); auto const number_start_address = block_start_offset + index * kstd::size_of(); - if (auto read_result = - state.backing_inode->read(as_writable_bytes(std::span{&block_number_buffer, 1}), number_start_address); + if (auto read_result = state.backing_inode->read(kstd::raw_bytes(block_number_buffer), number_start_address); !read_result) { return kstd::failure(read_result.error()); @@ -704,7 +798,7 @@ namespace kernel::filesystem::ext2 } else { - if (auto write_result = backing_inode->write(as_bytes(std::span{&block_number, 1}), parent_byte_offset); + if (auto write_result = backing_inode->write(kstd::raw_bytes(block_number), parent_byte_offset); !write_result) { return kstd::failure(write_result.error()); @@ -716,7 +810,7 @@ namespace kernel::filesystem::ext2 if (stride == 1) { - if (auto write_result = backing_inode->write(as_bytes(std::span{&global_block_number, 1}), byte_offset); + if (auto write_result = backing_inode->write(kstd::raw_bytes(global_block_number), byte_offset); !write_result) { return kstd::failure(write_result.error()); @@ -740,7 +834,7 @@ namespace kernel::filesystem::ext2 return kstd::success(); } - auto filesystem::read_block(uint32_t block_number, void * buffer, mount_state & state) const + auto filesystem::read_block(uint32_t block_number, void * buffer, mount_state const & state) const -> kstd::result { auto const block_offset = static_cast(block_number) * block_size(state); @@ -762,7 +856,7 @@ namespace kernel::filesystem::ext2 { // TODO update all block group descriptors return state.backing_inode - ->write(as_bytes(std::span{&block_group_descriptor, 1}), + ->write(kstd::raw_bytes(block_group_descriptor), block_group_descriptor_table_offset(state) + block_group_descriptor_index * kstd::size_of(block_group_descriptor)) .transform([](auto) {}); @@ -771,42 +865,56 @@ namespace kernel::filesystem::ext2 auto filesystem::write_superblock(mount_state & state) const -> kstd::result { // TODO update all superblock copies - return state.backing_inode->write(as_bytes(std::span{&state.superblock, 1}), constants::superblock_offset) + return state.backing_inode->write(kstd::raw_bytes(state.superblock), constants::superblock_offset) .transform([](auto) {}); } - auto filesystem::map_inode_mode_to_file_type(uint16_t mode) -> uint8_t + auto filesystem::map_inode_mode_to_file_type(uint16_t mode) -> kapi::filesystem::file_type { switch (mode & constants::mode_mask) { case constants::mode_regular: - return 1; + return kapi::filesystem::file_type::regular; case constants::mode_directory: - return 2; + return kapi::filesystem::file_type::directory; + case constants::mode_block_device: + return kapi::filesystem::file_type::block_device; + case constants::mode_character_device: + return kapi::filesystem::file_type::character_device; case constants::mode_symbolic_link: - return 7; + return kapi::filesystem::file_type::symbolic_link; + case constants::mode_fifo: + return kapi::filesystem::file_type::fifo; + case constants::mode_socket: + return kapi::filesystem::file_type::socket; default: - return 0; + return kapi::filesystem::file_type{0}; } } auto filesystem::map_vfs_inode_type_into_inode_mode(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t { - switch (type) - { - case kapi::filesystem::file_type::directory: - return mode | constants::mode_directory; - case kapi::filesystem::file_type::regular: - return mode | constants::mode_regular; - case kapi::filesystem::file_type::block_device: - return mode | constants::mode_block_device; - case kapi::filesystem::file_type::character_device: - return mode | constants::mode_character_device; - case kapi::filesystem::file_type::symbolic_link: - // return mode | constants::mode_symbolic_link; // TODO implement - default: - kapi::system::panic("[EXT2] Not implemented."); - } + return mode | [=] { + switch (type) + { + case kapi::filesystem::file_type::directory: + return constants::mode_directory; + case kapi::filesystem::file_type::regular: + return constants::mode_regular; + case kapi::filesystem::file_type::block_device: + return constants::mode_block_device; + case kapi::filesystem::file_type::character_device: + return constants::mode_character_device; + case kapi::filesystem::file_type::symbolic_link: + return constants::mode_symbolic_link; // TODO implement + case kapi::filesystem::file_type::fifo: + return constants::mode_fifo; + case kapi::filesystem::file_type::socket: + return constants::mode_socket; + default: + kapi::system::panic("[EXT2] Not implemented."); + } + }(); } auto filesystem::block_numbers_per_block(mount_state const & state) const -> size_t @@ -829,26 +937,6 @@ namespace kernel::filesystem::ext2 return block_numbers_per_doubly_indirect_block(state) * block_numbers_per_block(state); } - auto filesystem::block_size(mount_state const & state) const -> kstd::bytes - { - return kstd::bytes{constants::base_block_size.value << state.superblock.log_block_size}; - } - - auto filesystem::revision_level(mount_state const & state) const -> uint32_t - { - return state.superblock.rev_level; - } - - auto filesystem::inode_size(mount_state const & state) const -> kstd::bytes - { - return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size); - } - - auto filesystem::inode_block_count(inode_data const & data, mount_state const & state) const -> uint32_t - { - return data.blocks / (2 << state.superblock.log_block_size); - } - auto filesystem::update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void { data.blocks += delta * (2 << state.superblock.log_block_size); diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 4b5604e5..fec4a283 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -49,6 +51,9 @@ namespace kernel::filesystem::ext2 constexpr uint16_t inline mode_symbolic_link = 0xA000; constexpr uint16_t inline mode_block_device = 0x6000; constexpr uint16_t inline mode_character_device = 0x2000; + constexpr uint16_t inline mode_fifo = 0x1000; + constexpr uint16_t inline mode_socket = 0xC000; + } // namespace constants //! Ext2 incompatibility features @@ -76,6 +81,9 @@ namespace kernel::filesystem::ext2 //! The Second Extended Filesystem (ext2) struct filesystem final : kernel::filesystem::filesystem { + //! @name Driver Interface Implementation + //! @{ + [[nodiscard]] auto probe(inode_ptr const & backing_inode) const -> kstd::result override; auto mount(inode_ptr const & backing_inode) -> kstd::result override; @@ -88,23 +96,48 @@ namespace kernel::filesystem::ext2 std::optional raw_device = std::nullopt) -> kstd::result override; + //! @} + + //! @name Filesystem Information Queries + //! @{ + //! Get the size of a block in the filesystem. //! + //! @param state The driver state to operate on. //! @return The size of a block in bytes. [[nodiscard]] auto block_size(mount_state const & state) const -> kstd::bytes; //! Get the revision level of the filesystem. //! + //! @param state The driver state to operate on. //! @return The revision level. [[nodiscard]] auto revision_level(mount_state const & state) const -> uint32_t; + //! Get the size of an inode in the filesystem. + //! + //! @param state The driver state to operate on. + //! @return The size of an inode in bytes. + [[nodiscard]] auto inode_size(mount_state const & state) const -> kstd::bytes; + + //! Get the number of blocks allocated to an inode. + //! + //! @param data The inode data. + //! @param state The driver state to operate on. + //! @return The number of blocks allocated to the inode. + [[nodiscard]] auto block_count(inode_data const & data, mount_state const & state) const -> uint32_t; + + //! @} + + //! @name Block I/O + //! @{ + //! Read a block from the backing inode into the provided buffer. //! //! @param block_number The number of the block to read. //! @param buffer The buffer to read the block data into. //! @param state The state to operate on. //! @return The number of bytes read. - auto read_block(uint32_t block_number, void * buffer, mount_state & state) const -> kstd::result; + auto read_block(uint32_t block_number, void * buffer, mount_state const & state) const -> kstd::result; //! Write a block of data from the provided buffer to the backing inode. //! @@ -114,6 +147,8 @@ namespace kernel::filesystem::ext2 //! @return The number of bytes written. auto write_block(uint32_t block_number, void const * buffer, mount_state & state) -> kstd::result; + //! @} + //! Allocate a specified number of blocks. //! //! @param count The number of blocks to allocate. @@ -121,18 +156,6 @@ namespace kernel::filesystem::ext2 //! @return A vector of the allocated block numbers. auto allocate_blocks(size_t count, mount_state & state) -> kstd::result>; - //! Get the size of an inode in the filesystem. - //! - //! @return The size of an inode in bytes. - [[nodiscard]] auto inode_size(mount_state const & state) const -> kstd::bytes; - - //! Get the number of blocks allocated to an inode. - //! - //! @param 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, mount_state const & state) const -> uint32_t; - //! Update the number of blocks allocated to an inode. //! //! @param data The inode data. @@ -176,13 +199,45 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto indirect_levels(mount_state const & state) const -> std::array; + //! Allocate a single inode in the file system. + //! + //! @param state The driver state to operate on. + //! @return An inode number on success, an error otherwise. auto allocate_inode(mount_state & state) -> kstd::result; - auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode, + + //! Add a new directory entry to a given directory. + //! + //! @param directory The directory to add the entry to. + //! @param name The name for the entry. + //! @param child The inode number of the child. + //! @param mode The file mode of the entry. + //! @param state The driver state to operate on. + //! @return Nothing on success, an error code otherwise. + auto add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, mount_state & state) -> kstd::result; - auto init_directory(kstd::shared_ptr const & new_inode, inode * parent_inode, mount_state & state) - -> kstd::result; - 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, mount_state & state) -> void; + + //! Initialize a new directory inode. + //! + //! This function initializes an inode to be an empty directory. On success, the inode will be a directory with only + //! two children, "." and "..". + //! + //! @param directory The inode to initialize. + //! @param parent The parent of this newly initialized directory. + //! @param state The driver state to operate on. + //! @return Nothing on success, an error otherwise. + auto init_directory(inode & directory, inode & parent, mount_state & state) -> kstd::result; + + //! Write a new directory entry into the given buffer. + //! + //! @param buffer The buffer to write to. + //! @param offset The offset inside to the buffer. + //! @param target The inode the entry targets. + //! @param name The name for the entry. + //! @param type The filet type of the entry. + //! @return A pointer to the written entry on success, an error otherwise. + auto write_directory_entry_to_buffer(std::span buffer, kstd::bytes offset, inode & target, + std::string_view name, kapi::filesystem::file_type type) + -> kstd::result; [[nodiscard]] auto calculate_inode_offset(uint32_t inode_number, mount_state const & state) const -> kstd::result; @@ -203,7 +258,7 @@ namespace kernel::filesystem::ext2 mount_state const & state) const -> kstd::result; [[nodiscard]] auto write_superblock(mount_state & state) const -> kstd::result; - auto map_inode_mode_to_file_type(uint16_t mode) -> uint8_t; + auto map_inode_mode_to_file_type(uint16_t mode) -> kapi::filesystem::file_type; auto map_vfs_inode_type_into_inode_mode(kapi::filesystem::file_type type, uint16_t mode) -> uint16_t; }; } // namespace kernel::filesystem::ext2 diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 752dd010..c0df4647 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -166,12 +166,6 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, std::string_view result{reinterpret_cast(read_buffer.data()), static_cast(*bytes_read)}; REQUIRE(result == "Hello"); } - - THEN("a symbolic link is not implemented yet") - { - REQUIRE_THROWS_AS(fs->create_inode(root, "blub", kapi::filesystem::file_type::symbolic_link, driver_data), - kernel::tests::cpu::halt); - } } } diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 8c7d0ec0..a12c65d8 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -136,7 +136,7 @@ namespace kernel::filesystem::ext2 auto block_size = (*filesystem)->block_size(*state); - auto const current_block_count = (*filesystem)->inode_block_count(m_data, *state); + auto const current_block_count = (*filesystem)->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) @@ -217,7 +217,7 @@ namespace kernel::filesystem::ext2 for (auto i = 0uz; i < new_blocks->size(); ++i) { - auto const block_index = (*filesystem)->inode_block_count(m_data, *state) + i; + auto const block_index = (*filesystem)->block_count(m_data, *state) + i; auto const global_block_number = new_blocks->at(i); if (auto write_result = diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index a6a88fc8..0152fd8b 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -355,7 +356,7 @@ 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(*mount_state); - auto const expected_allocated_blocks = 32 * fs->inode_block_count(inode_data, *mount_state); + auto const expected_allocated_blocks = 32 * fs->block_count(inode_data, *mount_state); auto write_buffer = kstd::vector(block_size.value * expected_allocated_blocks, std::byte{'A'}); @@ -369,7 +370,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, *mount_state) == expected_allocated_blocks); + REQUIRE(fs->block_count(new_inode_data, *mount_state) == expected_allocated_blocks); } THEN("writing to a an inode of type directory panics") @@ -433,7 +434,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" 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)); + REQUIRE(dev_inode->write(kstd::raw_bytes(inode), inode_data_offset)); auto const buffer = kstd::vector{std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, std::byte{'o'}, std::byte{' '}, @@ -443,7 +444,7 @@ 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)); + REQUIRE(dev_inode->read(kstd::raw_bytes(inode_data), inode_data_offset)); auto read_inode = kernel::filesystem::ext2::inode{inode_number, inode_data}; read_inode.set_owning_mount(*mount); return read_inode; diff --git a/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp b/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp index 9c9d162d..08999cb8 100644 --- a/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp +++ b/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp @@ -1,7 +1,6 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_LINKED_DIRECTORY_ENTRY_HPP #define TEACHOS_KERNEL_FILESYSTEM_EXT2_LINKED_DIRECTORY_ENTRY_HPP -#include #include namespace kernel::filesystem::ext2 @@ -13,7 +12,7 @@ namespace kernel::filesystem::ext2 uint16_t rec_len; uint8_t name_len; uint8_t file_type; - std::array name; // NOLINT(readability-magic-numbers) + char name_start; // NOLINT(readability-magic-numbers) }; } // namespace kernel::filesystem::ext2 -- cgit v1.2.3 From 17198a261acb892c62ad7278ac2e2266a8430d2f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 17:07:11 +0200 Subject: kernel/fs: ext2: make block_count take the inode --- kernel/kernel/filesystem/ext2/filesystem.cpp | 12 ++++++------ kernel/kernel/filesystem/ext2/filesystem.hpp | 4 ++-- kernel/kernel/filesystem/ext2/inode.cpp | 4 ++-- kernel/kernel/filesystem/ext2/inode.tests.cpp | 13 ++++++------- 4 files changed, 16 insertions(+), 17 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 45d4efeb..a9d75743 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -170,7 +170,7 @@ namespace kernel::filesystem::ext2 auto const & inode_data = ext2_parent->data(); auto buffer = kstd::vector{block_size(*mount_state).value}; - for (auto i = 0u; i < block_count(inode_data, *mount_state); ++i) + for (auto i = 0u; i < block_count(*ext2_parent, *mount_state); ++i) { auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data, *mount_state); if (!global_block_number) @@ -299,9 +299,9 @@ namespace kernel::filesystem::ext2 return kstd::bytes(revision_level(state) == constants::good_old_revision ? 128 : state.superblock.inode_size); } - auto filesystem::block_count(inode_data const & data, mount_state const & state) const -> uint32_t + auto filesystem::block_count(inode const & inode, mount_state const & state) const -> uint32_t { - return data.blocks / (2 << state.superblock.log_block_size); + return inode.data().blocks / (2 << state.superblock.log_block_size); } auto filesystem::indirect_levels(mount_state const & state) const -> std::array @@ -316,7 +316,7 @@ namespace kernel::filesystem::ext2 auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, mount_state & state) -> kstd::result { - auto const last_block_index = block_count(directory.data(), state) - 1; + auto const last_block_index = block_count(directory, state) - 1; auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, directory.data(), state); if (!global_block) @@ -378,7 +378,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(ext2_errc::not_enough_free_blocks); } - auto const new_block_index = block_count(directory.data(), state) - 1; + auto const new_block_index = block_count(directory, state) - 1; auto const new_global_block = map_inode_block_index_to_global_block_number(new_block_index, directory.data(), state); if (!new_global_block) @@ -404,7 +404,7 @@ namespace kernel::filesystem::ext2 } } - auto size = block_count(directory.data(), state) * block_size(state); + auto size = block_count(directory, state) * block_size(state); directory.data_mutable().size = size.value; return write_inode(directory.number(), directory.data(), state); } diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index fec4a283..bb1e8e84 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -121,10 +121,10 @@ namespace kernel::filesystem::ext2 //! Get the number of blocks allocated to an inode. //! - //! @param data The inode data. + //! @param inode The inode whose block count to query. //! @param state The driver state to operate on. //! @return The number of blocks allocated to the inode. - [[nodiscard]] auto block_count(inode_data const & data, mount_state const & state) const -> uint32_t; + [[nodiscard]] auto block_count(inode const & inode, mount_state const & state) const -> uint32_t; //! @} diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index a12c65d8..2d4091aa 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -136,7 +136,7 @@ namespace kernel::filesystem::ext2 auto block_size = (*filesystem)->block_size(*state); - auto const current_block_count = (*filesystem)->block_count(m_data, *state); + auto const current_block_count = (*filesystem)->block_count(*this, *state); auto const max_new_inode_size_without_new_blocks = current_block_count * block_size; if (new_inode_size > max_new_inode_size_without_new_blocks) @@ -217,7 +217,7 @@ namespace kernel::filesystem::ext2 for (auto i = 0uz; i < new_blocks->size(); ++i) { - auto const block_index = (*filesystem)->block_count(m_data, *state) + i; + auto const block_index = (*filesystem)->block_count(*this, *state) + i; auto const global_block_number = new_blocks->at(i); if (auto write_result = diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 0152fd8b..2d3a2ec2 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -353,24 +353,23 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in THEN("writing allocates new blocks and updates the inode size") { - auto inode_data = static_cast(file.value().get())->data(); + auto inode = static_pointer_cast(file.value()); auto const block_size = fs->block_size(*mount_state); - auto const expected_allocated_blocks = 32 * fs->block_count(inode_data, *mount_state); + auto const expected_allocated_blocks = 32 * fs->block_count(*inode, *mount_state); auto write_buffer = kstd::vector(block_size.value * expected_allocated_blocks, std::byte{'A'}); - auto const bytes_written = file.value()->write(write_buffer, 0_B); + auto const bytes_written = inode->write(write_buffer, 0_B); REQUIRE(bytes_written == block_size * expected_allocated_blocks); auto read_buffer = kstd::vector(block_size.value * expected_allocated_blocks, std::byte{0x00}); - auto const bytes_read = file.value()->read(read_buffer, 0_B); + auto const bytes_read = inode->read(read_buffer, 0_B); REQUIRE(bytes_read == block_size * expected_allocated_blocks); REQUIRE(std::ranges::all_of(read_buffer, [](std::byte c) { return c == std::byte{'A'}; })); - auto new_inode_data = static_cast(file.value().get())->data(); - REQUIRE(new_inode_data.size == write_buffer.size()); - REQUIRE(fs->block_count(new_inode_data, *mount_state) == expected_allocated_blocks); + REQUIRE(inode->size().value == write_buffer.size()); + REQUIRE(fs->block_count(*inode, *mount_state) == expected_allocated_blocks); } THEN("writing to a an inode of type directory panics") -- cgit v1.2.3 From 746f0bf813dd02cbcb5a580f69cfc892dd04cb8c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 17:15:04 +0200 Subject: kernel/fs: ext2: retype block I/O operations --- kernel/kernel/filesystem/ext2/filesystem.cpp | 62 +++++++++++++++------------- kernel/kernel/filesystem/ext2/filesystem.hpp | 6 ++- 2 files changed, 38 insertions(+), 30 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index a9d75743..bc935e0f 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -178,7 +178,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(global_block_number.error()); } - if (auto result = read_block(*global_block_number, buffer.data(), *mount_state); !result) + if (auto result = read_block(*global_block_number, buffer, *mount_state); !result) { return kstd::failure(result.error()); } @@ -304,6 +304,30 @@ namespace kernel::filesystem::ext2 return inode.data().blocks / (2 << state.superblock.log_block_size); } + auto filesystem::read_block(uint32_t block_number, std::span buffer, mount_state const & state) const + -> kstd::result + { + if (buffer.size() < block_size(state).value) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + auto const block_offset = static_cast(block_number) * block_size(state); + return state.backing_inode->read(buffer, block_offset); + } + + auto filesystem::write_block(uint32_t block_number, std::span buffer, mount_state & state) + -> kstd::result + { + if (buffer.size() < block_size(state).value) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + auto const block_offset = static_cast(block_number) * block_size(state); + return state.backing_inode->write(buffer, block_offset); + } + auto filesystem::indirect_levels(mount_state const & state) const -> std::array { return { @@ -325,7 +349,7 @@ namespace kernel::filesystem::ext2 } auto buffer = kstd::vector{block_size(state).value}; - if (auto result = read_block(*global_block, buffer.data(), state); !result) + if (auto result = read_block(*global_block, buffer, state); !result) { return kstd::failure(result.error()); } @@ -368,7 +392,7 @@ namespace kernel::filesystem::ext2 auto remainder = block_size(state) - entry_offset; (*entry)->rec_len = remainder.value; - return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data(), state); }) + return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); }) .transform([](auto) {}); } else @@ -396,8 +420,8 @@ namespace kernel::filesystem::ext2 auto remainder = block_size(state); (*entry)->rec_len = remainder.value; - if (auto result = new_global_block.and_then( - [&](auto block_number) { return write_block(block_number, buffer.data(), state); }); + if (auto result = + new_global_block.and_then([&](auto block_number) { return write_block(block_number, buffer, state); }); !result) { return kstd::failure(result.error()); @@ -446,7 +470,7 @@ namespace kernel::filesystem::ext2 return write_inode(parent.number(), parent_inode_data, state) .and_then([&]() { return global_block; }) - .and_then([&](auto block_number) { return write_block(block_number, buffer.data(), state); }) + .and_then([&](auto block_number) { return write_block(block_number, buffer, state); }) .transform([](auto) {}); } @@ -567,7 +591,7 @@ namespace kernel::filesystem::ext2 } auto block_bitmap = kstd::vector{block_size(state).value}; - if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap.data(), state); !read_result) + if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap, state); !read_result) { return kstd::failure(read_result.error()); } @@ -589,8 +613,7 @@ namespace kernel::filesystem::ext2 if (is_bitmap_dirty) { - if (auto write_result = write_block(block_group_descriptor.block_bitmap, block_bitmap.data(), state); - !write_result) + if (auto write_result = write_block(block_group_descriptor.block_bitmap, block_bitmap, state); !write_result) { return kstd::failure(write_result.error()); } @@ -641,7 +664,7 @@ namespace kernel::filesystem::ext2 } auto inode_bitmap = kstd::vector{block_size(state).value}; - if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap.data(), state); !read_result) + if (auto read_result = read_block(block_group_descriptor.inode_bitmap, inode_bitmap, state); !read_result) { return kstd::failure(read_result.error()); } @@ -654,8 +677,7 @@ namespace kernel::filesystem::ext2 block_group_descriptor.free_inodes_count--; superblock.free_inodes_count--; - if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap.data(), state); - !write_result) + if (auto write_result = write_block(block_group_descriptor.inode_bitmap, inode_bitmap, state); !write_result) { return kstd::failure(write_result.error()); } @@ -834,22 +856,6 @@ namespace kernel::filesystem::ext2 return kstd::success(); } - auto filesystem::read_block(uint32_t block_number, void * buffer, mount_state const & state) const - -> kstd::result - { - auto const block_offset = static_cast(block_number) * block_size(state); - return state.backing_inode->read(std::span{static_cast(buffer), block_size(state).value}, - block_offset); - } - - auto filesystem::write_block(uint32_t block_number, void const * buffer, mount_state & state) - -> kstd::result - { - auto const block_offset = static_cast(block_number) * block_size(state); - return state.backing_inode->write(std::span{static_cast(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, mount_state const & state) const -> kstd::result diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index bb1e8e84..e98dabde 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -137,7 +137,8 @@ namespace kernel::filesystem::ext2 //! @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, mount_state const & state) const -> kstd::result; + [[nodiscard]] auto read_block(uint32_t block_number, std::span buffer, mount_state const & state) const + -> kstd::result; //! Write a block of data from the provided buffer to the backing inode. //! @@ -145,7 +146,8 @@ namespace kernel::filesystem::ext2 //! @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, mount_state & state) -> kstd::result; + [[nodiscard]] auto write_block(uint32_t block_number, std::span buffer, mount_state & state) + -> kstd::result; //! @} -- cgit v1.2.3 From 1a437c02fa9f488f2d2ada23b13fc9f5b16699bf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 17:31:34 +0200 Subject: kernel/fs: ext2: cosmetic inode cleanup --- kernel/kernel/filesystem/ext2/filesystem.cpp | 4 +- kernel/kernel/filesystem/ext2/inode.cpp | 194 +++++++++++++-------------- kernel/kernel/filesystem/ext2/inode.hpp | 85 +++++++++--- 3 files changed, 160 insertions(+), 123 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index bc935e0f..5104e8cc 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -429,7 +429,7 @@ namespace kernel::filesystem::ext2 } auto size = block_count(directory, state) * block_size(state); - directory.data_mutable().size = size.value; + directory.data().size = size.value; return write_inode(directory.number(), directory.data(), state); } @@ -465,7 +465,7 @@ namespace kernel::filesystem::ext2 (*dot_dot)->rec_len = remainder.value; // '..' inside the new dir counts as an extra hard link to the parent - auto & parent_inode_data = parent.data_mutable(); + auto & parent_inode_data = parent.data(); parent_inode_data.links_count++; return write_inode(parent.number(), parent_inode_data, state) diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 2d4091aa..cfc22989 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -47,20 +47,19 @@ namespace kernel::filesystem::ext2 return kstd::failure(filesystem.error()); } - auto driver_data = get_driver_data(); - if (!driver_data) + auto state = get_driver_data(); + if (!state) { - return kstd::failure(driver_data.error()); + return kstd::failure(state.error()); } - auto state = static_pointer_cast(*driver_data); - auto backing_inode = state->backing_inode; - if (!state->backing_inode) + auto backing_inode = (*state)->backing_inode; + if (!(*state)->backing_inode) { return kstd::failure(vfs_errc::not_mounted); } - auto block_size = (*filesystem)->block_size(*state); + auto block_size = (*filesystem)->block_size(**state); auto block_index = offset / block_size; auto in_block_offset = offset % block_size; @@ -69,7 +68,7 @@ namespace kernel::filesystem::ext2 while (bytes_read < requested_size) { auto const block_number = - (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, *state); + (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, **state); if (!block_number) { break; @@ -121,22 +120,21 @@ namespace kernel::filesystem::ext2 return kstd::failure(filesystem.error()); } - auto driver_data = get_driver_data(); - if (!driver_data) + auto state = get_driver_data(); + if (!state) { - return kstd::failure(driver_data.error()); + return kstd::failure(state.error()); } - auto state = static_pointer_cast(*driver_data); - auto backing_inode = state->backing_inode; - if (!state->backing_inode) + auto backing_inode = (*state)->backing_inode; + if (!(*state)->backing_inode) { return kstd::failure(vfs_errc::not_mounted); } - auto block_size = (*filesystem)->block_size(*state); + auto block_size = (*filesystem)->block_size(**state); - auto const current_block_count = (*filesystem)->block_count(*this, *state); + auto const current_block_count = (*filesystem)->block_count(*this, **state); auto const max_new_inode_size_without_new_blocks = current_block_count * block_size; if (new_inode_size > max_new_inode_size_without_new_blocks) @@ -159,7 +157,7 @@ namespace kernel::filesystem::ext2 while (bytes_written < kstd::bytes{buffer.size()}) { auto const block_number = - (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, *state); + (*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) { @@ -185,7 +183,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, *state); !write_result) + if (auto write_result = (*filesystem)->write_inode(m_inode_number, m_data, **state); !write_result) { return kstd::failure(write_result.error()); } @@ -193,54 +191,19 @@ namespace kernel::filesystem::ext2 return bytes_written; } - auto inode::append_blocks(size_t count) -> bool + auto inode::is_block_device() const -> bool { - auto filesystem = get_filesystem(); - if (!filesystem) - { - return false; - } - - auto driver_data = get_driver_data(); - if (!driver_data) - { - return false; - } - - auto state = static_pointer_cast(*driver_data); - - auto new_blocks = (*filesystem)->allocate_blocks(count, *state); - if (!new_blocks) - { - return false; - } - - for (auto i = 0uz; i < new_blocks->size(); ++i) - { - auto const block_index = (*filesystem)->block_count(*this, *state) + i; - auto const global_block_number = new_blocks->at(i); - - if (auto write_result = - (*filesystem) - ->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number, *state); - !write_result) - { - return false; - } - } - - (*filesystem)->update_inode_block_count(m_data, count, *state); - return true; + return (m_data.mode & constants::mode_mask) == constants::mode_block_device; } - [[nodiscard]] auto inode::data() const -> inode_data const & + auto inode::is_character_device() const -> bool { - return m_data; + return (m_data.mode & constants::mode_mask) == constants::mode_character_device; } - [[nodiscard]] auto inode::data_mutable() -> inode_data & + auto inode::is_directory() const -> bool { - return m_data; + return (m_data.mode & constants::mode_mask) == constants::mode_directory; } auto inode::is_regular() const -> bool @@ -248,24 +211,24 @@ namespace kernel::filesystem::ext2 return (m_data.mode & constants::mode_mask) == constants::mode_regular; } - auto inode::is_directory() const -> bool - { - return (m_data.mode & constants::mode_mask) == constants::mode_directory; - } - auto inode::is_symbolic_link() const -> bool { return (m_data.mode & constants::mode_mask) == constants::mode_symbolic_link; } - auto inode::is_block_device() const -> bool + auto inode::raw_device() const -> std::optional { - return (m_data.mode & constants::mode_mask) == constants::mode_block_device; - } + if (!is_device()) + { + return std::nullopt; + } - auto inode::is_character_device() const -> bool - { - return (m_data.mode & constants::mode_mask) == constants::mode_character_device; + auto const raw_device_number = m_data.block[0]; + + return kapi::filesystem::device_number{ + .major = static_cast((raw_device_number >> 8) & 0xff), + .minor = static_cast(raw_device_number & 0xff), + }; } auto inode::status() const -> kstd::result @@ -284,45 +247,42 @@ namespace kernel::filesystem::ext2 return result; } - auto inode::raw_device() const -> std::optional - { - if (!is_device()) - { - return std::nullopt; - } - - auto const raw_device_number = m_data.block[0]; - - return kapi::filesystem::device_number{ - .major = static_cast((raw_device_number >> 8) & 0xff), - .minor = static_cast(raw_device_number & 0xff), - }; - } - - auto inode::size() const -> kstd::bytes + auto inode::append_blocks(size_t count) -> bool { - uint64_t size = m_data.size; - auto filesystem = get_filesystem(); if (!filesystem) { - return 0_B; + return false; } - auto driver_data = get_driver_data(); - if (!driver_data) + auto state = get_driver_data(); + if (!state) { - return 0_B; + return false; } - auto state = static_pointer_cast(*driver_data); + auto new_blocks = (*filesystem)->allocate_blocks(count, **state); + if (!new_blocks) + { + return false; + } - if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular()) + for (auto i = 0uz; i < new_blocks->size(); ++i) { - size |= static_cast(m_data.dir_acl) << 32; + auto const block_index = (*filesystem)->block_count(*this, **state) + i; + auto const global_block_number = new_blocks->at(i); + + if (auto write_result = + (*filesystem) + ->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number, **state); + !write_result) + { + return false; + } } - return kstd::bytes{size}; + (*filesystem)->update_inode_block_count(m_data, count, **state); + return true; } auto inode::set_size(kstd::bytes new_size) -> void @@ -348,6 +308,40 @@ namespace kernel::filesystem::ext2 m_data.size = static_cast(new_size.value); } + [[nodiscard]] auto inode::data() -> inode_data & + { + return m_data; + } + + [[nodiscard]] auto inode::data() const -> inode_data const & + { + return m_data; + } + + auto inode::size() const -> kstd::bytes + { + uint64_t size = m_data.size; + + auto filesystem = get_filesystem(); + if (!filesystem) + { + return 0_B; + } + + auto state = get_driver_data(); + if (!state) + { + return 0_B; + } + + if ((*filesystem)->revision_level(**state) > constants::good_old_revision && is_regular()) + { + size |= static_cast(m_data.dir_acl) << 32; + } + + return kstd::bytes{size}; + } + [[nodiscard]] auto inode::number() const -> uint32_t { return m_inode_number; @@ -373,21 +367,21 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - auto inode::get_driver_data() -> kstd::result> + auto inode::get_driver_data() -> kstd::result> { if (auto mount = owning_mount().lock()) { - return mount->driver_data(); + return static_pointer_cast(mount->driver_data()); } return kstd::failure(vfs_errc::not_mounted); } - auto inode::get_driver_data() const -> kstd::result> + auto inode::get_driver_data() const -> kstd::result> { if (auto mount = owning_mount().lock()) { - return mount->driver_data(); + return static_pointer_cast(mount->driver_data()); } return kstd::failure(vfs_errc::not_mounted); diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index 7f668833..735905e9 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_INODE_HPP #define TEACHOS_KERNEL_FILESYSTEM_EXT2_INODE_HPP +#include #include #include @@ -44,32 +45,33 @@ namespace kernel::filesystem::ext2 struct inode : kernel::filesystem::inode { + //! @name Construction/Destruction + //! @{ + //! Create an ext2 inode associated with the given filesystem. //! //! @param inode_number The inode number on disk. //! @param data The data associated with this inode, read from the disk. explicit inode(uint32_t inode_number, inode_data const & data); + //! @} + + //! @name I/O Operations + //! @{ + [[nodiscard]] auto read(std::span buffer, kstd::bytes offset) const -> kstd::result override; auto write(std::span buffer, kstd::bytes offset) -> kstd::result override; - //! Append the specified number of blocks to this inode. - //! - //! @param count The number of blocks to append. - //! @return true if the blocks were successfully appended, false otherwise. - auto append_blocks(size_t count) -> bool; + //! @} - //! Get the data associated with this inode. - //! - //! @return A const reference to the inode data. - [[nodiscard]] auto data() const -> inode_data const &; + //! @name Property Checking + //! @{ - //! Get the data associated with this inode. - //! - //! @return A reference to the inode data. - [[nodiscard]] auto data_mutable() -> inode_data &; + [[nodiscard]] auto is_block_device() const -> bool override; + + [[nodiscard]] auto is_character_device() const -> bool override; [[nodiscard]] auto is_directory() const -> bool override; @@ -77,37 +79,78 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto is_symbolic_link() const -> bool override; - [[nodiscard]] auto is_block_device() const -> bool override; + //! @} - [[nodiscard]] auto is_character_device() const -> bool override; + //! @name POSIX Information Access + //! @{ + + [[nodiscard]] auto raw_device() const -> std::optional override; [[nodiscard]] auto status() const -> kstd::result override; - [[nodiscard]] auto raw_device() const -> std::optional override; + //! @} - //! Get the size of the file represented by this inode. + //! @name Property Manipulation + //! @{ + + //! Append the specified number of blocks to this inode. //! - //! @return The size of the file in bytes. - [[nodiscard]] auto size() const -> kstd::bytes; + //! @param count The number of blocks to append. + //! @return true if the blocks were successfully appended, false otherwise. + auto append_blocks(size_t count) -> bool; //! Set the size of the file represented by this inode. //! //! @param new_size The new size of the file in bytes. auto set_size(kstd::bytes new_size) -> void; + //! @} + + //! @name Ext2 Information Queries + //! @{ + + //! Get the data associated with this inode. + //! + //! @return A reference to the inode data. + [[nodiscard]] auto data() -> inode_data &; + + //! Get the data associated with this inode. + //! + //! @return A const reference to the inode data. + [[nodiscard]] auto data() const -> inode_data const &; + + //! Get the size of the file represented by this inode. + //! + //! @return The size of the file in bytes. + [[nodiscard]] auto size() const -> kstd::bytes; + //! @brief Get the inode number of this inode. //! //! @return The inode number. [[nodiscard]] auto number() const -> uint32_t; + //! @} + private: + //! Get the filesystem driver associated with this inode. + //! + //! @return The filesystem driver on success, and error otherwise. [[nodiscard]] auto get_filesystem() -> kstd::result>; + //! Get the filesystem driver associated with this inode. + //! + //! @return The filesystem driver on success, and error otherwise. [[nodiscard]] auto get_filesystem() const -> kstd::result>; - [[nodiscard]] auto get_driver_data() -> kstd::result>; + //! Get the filesystem driver data associated with this inode. + //! + //! @return The filesystem driver data on success, and error otherwise. + [[nodiscard]] auto get_driver_data() -> kstd::result>; - [[nodiscard]] auto get_driver_data() const -> kstd::result>; + //! Get the filesystem driver data associated with this inode. + //! + //! @return The filesystem driver data on success, and error otherwise. + [[nodiscard]] auto get_driver_data() const -> kstd::result>; //! The inode number on disk. uint32_t m_inode_number{}; -- cgit v1.2.3 From cd92184749880817b5f495b1006365c8c88ebab6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 25 Aug 2026 17:08:15 +0200 Subject: kernel/fs: ext2: extract stateless functions --- kernel/kernel/filesystem/ext2/filesystem.cpp | 112 +++++++++++---------- kernel/kernel/filesystem/ext2/filesystem.hpp | 23 +---- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 27 ++--- kernel/kernel/filesystem/ext2/inode.cpp | 6 +- 4 files changed, 81 insertions(+), 87 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 5104e8cc..18af5a61 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -40,6 +40,12 @@ namespace kernel::filesystem::ext2 namespace { + struct indirect_level + { + uint32_t slot_index; + size_t capacity; + }; + //! Check if the given bit has the bit at the given index set. //! //! @warning This function will panic if the bit index is out-of-bounds for the given bitmap. @@ -66,6 +72,36 @@ namespace kernel::filesystem::ext2 bitmap.at(byte_index) |= static_cast(1u << bit_index); } + //! Get the number of block numbers storable on each level + //! + //! @param level The level to check. + //! @param block_size The size of a single block. + [[nodiscard]] constexpr auto block_numbers(std::size_t level, kstd::bytes block_size) noexcept -> std::size_t + { + if (level == 0) + { + return constants::direct_block_count; + } + + auto const numbers_per_block = block_size / kstd::size_of(); + auto result = numbers_per_block; + for (auto current_level = level; current_level > 1; --current_level) + { + result *= numbers_per_block; + } + + return result; + } + + [[nodiscard]] constexpr auto indirect_levels(kstd::bytes block_size) -> std::array + { + return { + {{constants::singly_indirect_block_index, block_numbers(1, block_size)}, + {constants::doubly_indirect_block_index, block_numbers(2, block_size)}, + {constants::triply_indirect_block_index, block_numbers(3, block_size)}} + }; + } + //! The set of "incompatible" Extended Filesystem features supported by this driver. constexpr auto supported_incompatible_features = incompatible_features::file_types_in_directory_entries; @@ -167,12 +203,11 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - auto const & inode_data = ext2_parent->data(); auto buffer = kstd::vector{block_size(*mount_state).value}; for (auto i = 0u; i < block_count(*ext2_parent, *mount_state); ++i) { - auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data, *mount_state); + auto const global_block_number = inode_block_number(i, *ext2_parent, *mount_state); if (!global_block_number) { return kstd::failure(global_block_number.error()); @@ -328,20 +363,11 @@ namespace kernel::filesystem::ext2 return state.backing_inode->write(buffer, block_offset); } - auto filesystem::indirect_levels(mount_state const & state) const -> std::array - { - return { - {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, - {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, - {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} - }; - } - auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, mount_state & state) -> kstd::result { auto const last_block_index = block_count(directory, state) - 1; - auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, directory.data(), state); + auto const global_block = inode_block_number(last_block_index, directory, state); if (!global_block) { @@ -403,8 +429,7 @@ namespace kernel::filesystem::ext2 } auto const new_block_index = block_count(directory, state) - 1; - auto const new_global_block = - map_inode_block_index_to_global_block_number(new_block_index, directory.data(), state); + auto const new_global_block = inode_block_number(new_block_index, directory, state); if (!new_global_block) { return kstd::failure(new_global_block.error()); @@ -440,7 +465,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(ext2_errc::not_enough_free_blocks); } - auto const global_block = map_inode_block_index_to_global_block_number(0, directory.data(), state); + auto const global_block = inode_block_number(0, directory, state); if (!global_block) { return kstd::failure(global_block.error()); @@ -703,35 +728,38 @@ namespace kernel::filesystem::ext2 return kstd::failure(ext2_errc::not_enough_inodes); } - auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data, - mount_state const & state) const + auto filesystem::inode_block_number(size_t index, inode const & inode, mount_state const & state) const -> kstd::result { - if (inode_block_index < constants::direct_block_count) + auto const & block_array = inode.data().block; + + if (index < constants::direct_block_count) { - return data.block.at(inode_block_index); + return block_array.at(index); } - inode_block_index -= constants::direct_block_count; - - for (auto const & level : indirect_levels(state)) + index -= constants::direct_block_count; + auto const block_size = this->block_size(state); + auto const numbers_per_block = block_numbers(1, block_size); + for (auto const & level : indirect_levels(block_size)) { - if (inode_block_index >= level.capacity) + auto const capacity = level.capacity; + if (index >= capacity) { - inode_block_index -= level.capacity; + index -= capacity; continue; } - auto block_number = data.block[level.slot_index]; + auto block_number = block_array[level.slot_index]; if (block_number == 0) { return 0; } - for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state)) + for (auto stride = capacity / numbers_per_block;; stride /= numbers_per_block) { - auto const idx = inode_block_index / stride; - inode_block_index %= stride; + auto const idx = index / stride; + index %= stride; if (auto read_result = read_block_number_at_index(block_number, idx, state); !read_result) { @@ -786,7 +814,9 @@ namespace kernel::filesystem::ext2 } inode_block_index -= constants::direct_block_count; - for (auto const & level : indirect_levels(state)) + auto const block_size = this->block_size(state); + auto const numbers_per_block = block_numbers(1, block_size); + for (auto const & level : indirect_levels(block_size)) { if (inode_block_index >= level.capacity) { @@ -799,7 +829,7 @@ namespace kernel::filesystem::ext2 auto parent_byte_offset = 0_B; bool is_root = true; - for (auto stride = level.capacity / block_numbers_per_block(state);; stride /= block_numbers_per_block(state)) + for (auto stride = level.capacity / numbers_per_block;; stride /= numbers_per_block) { auto const idx = inode_block_index / stride; inode_block_index %= stride; @@ -828,7 +858,7 @@ namespace kernel::filesystem::ext2 } } - auto const byte_offset = block_number * block_size(state) + idx * kstd::size_of(); + auto const byte_offset = block_number * block_size + idx * kstd::size_of(); if (stride == 1) { @@ -923,26 +953,6 @@ namespace kernel::filesystem::ext2 }(); } - auto filesystem::block_numbers_per_block(mount_state const & state) const -> size_t - { - return block_size(state) / kstd::size_of(); - } - - auto filesystem::block_numbers_per_singly_indirect_block(mount_state const & state) const -> size_t - { - return block_numbers_per_block(state); - } - - auto filesystem::block_numbers_per_doubly_indirect_block(mount_state const & state) const -> size_t - { - return block_numbers_per_singly_indirect_block(state) * block_numbers_per_block(state); - } - - auto filesystem::block_numbers_per_triply_indirect_block(mount_state const & state) const -> size_t - { - return block_numbers_per_doubly_indirect_block(state) * block_numbers_per_block(state); - } - auto filesystem::update_inode_block_count(inode_data & data, uint32_t delta, mount_state & state) -> void { data.blocks += delta * (2 << state.superblock.log_block_size); diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index e98dabde..93836b91 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -172,14 +171,13 @@ namespace kernel::filesystem::ext2 //! @param data The inode data to write. auto write_inode(uint32_t inode_number, inode_data const & data, mount_state & state) -> kstd::result; - //! Map an inode block index to a global block number. + //! Get the block number associated with the nth block of an inode. //! - //! @param inode_block_index The index of the block within the inode. + //! @param index The index of the block within the inode. + //! @param inode The inode. //! @param state The state to operate on. - //! @param data The inode data. //! @return The global block number on success, an error otherwise. - [[nodiscard]] auto map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data, - mount_state const & state) const + [[nodiscard]] auto inode_block_number(size_t index, inode const & inode, mount_state const & state) const -> kstd::result; //! Write a global block number to an inode block index. @@ -193,14 +191,6 @@ namespace kernel::filesystem::ext2 -> kstd::result; private: - struct indirect_level - { - uint32_t slot_index; - size_t capacity; - }; - - [[nodiscard]] auto indirect_levels(mount_state const & state) const -> std::array; - //! Allocate a single inode in the file system. //! //! @param state The driver state to operate on. @@ -250,11 +240,6 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto block_group_descriptor_table_offset(mount_state const & state) const -> kstd::bytes; - [[nodiscard]] auto block_numbers_per_block(mount_state const & state) const -> size_t; - [[nodiscard]] auto block_numbers_per_singly_indirect_block(mount_state const & state) const -> size_t; - [[nodiscard]] auto block_numbers_per_doubly_indirect_block(mount_state const & state) const -> size_t; - [[nodiscard]] auto block_numbers_per_triply_indirect_block(mount_state const & state) const -> size_t; - [[nodiscard]] auto write_block_group_descriptor(block_group_descriptor const & block_group_descriptor, size_t block_group_descriptor_index, mount_state const & state) const -> kstd::result; diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index c0df4647..6303959d 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -227,18 +228,20 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys auto const doubly_start = singly_start + numbers_per_block; auto const triply_start = doubly_start + numbers_per_block * numbers_per_block; + auto inode = kernel::filesystem::ext2::inode{42, inode_data}; + THEN("mapping resolves direct, singly, doubly and triply indirect indexes") { - REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data, *mount_state) == 7); - REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data, *mount_state) == 31); - REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data, *mount_state) == 42); - REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data, *mount_state) == 53); + REQUIRE(fs->inode_block_number(0, inode, *mount_state) == 7); + REQUIRE(fs->inode_block_number(singly_start, inode, *mount_state) == 31); + REQUIRE(fs->inode_block_number(doubly_start, inode, *mount_state) == 42); + REQUIRE(fs->inode_block_number(triply_start, inode, *mount_state) == 53); } THEN("mapping returns error for out-of-range indexes") { auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block; - REQUIRE(!fs->map_inode_block_index_to_global_block_number(beyond_triply, inode_data, *mount_state)); + REQUIRE(!fs->inode_block_number(beyond_triply, inode, *mount_state)); } } } @@ -333,14 +336,12 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys REQUIRE(triply_leaf_table == 21); REQUIRE(read_u32(static_cast(triply_leaf_table) * block_size) == triply_global_block_number); - REQUIRE(fs->map_inode_block_index_to_global_block_number(0, inode_data, *mount_state) == - direct_global_block_number); - REQUIRE(fs->map_inode_block_index_to_global_block_number(singly_start, inode_data, *mount_state) == - singly_global_block_number); - REQUIRE(fs->map_inode_block_index_to_global_block_number(doubly_start, inode_data, *mount_state) == - doubly_global_block_number); - REQUIRE(fs->map_inode_block_index_to_global_block_number(triply_start, inode_data, *mount_state) == - triply_global_block_number); + auto inode = kernel::filesystem::ext2::inode{42, inode_data}; + + REQUIRE(fs->inode_block_number(0, inode, *mount_state) == direct_global_block_number); + REQUIRE(fs->inode_block_number(singly_start, inode, *mount_state) == singly_global_block_number); + REQUIRE(fs->inode_block_number(doubly_start, inode, *mount_state) == doubly_global_block_number); + REQUIRE(fs->inode_block_number(triply_start, inode, *mount_state) == triply_global_block_number); } } } diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index cfc22989..34452ac8 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -67,8 +67,7 @@ namespace kernel::filesystem::ext2 while (bytes_read < requested_size) { - auto const block_number = - (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, **state); + auto const block_number = (*filesystem)->inode_block_number(block_index, *this, **state); if (!block_number) { break; @@ -156,8 +155,7 @@ namespace kernel::filesystem::ext2 while (bytes_written < kstd::bytes{buffer.size()}) { - auto const block_number = - (*filesystem)->map_inode_block_index_to_global_block_number(block_index, m_data, **state); + auto const block_number = (*filesystem)->inode_block_number(block_index, *this, **state); // TODO BA-FS26 if blocknumber == 0 --> handle sparse file if (!block_number) { -- cgit v1.2.3 From 94383569926c6566ed8c102addc709cb0429f398 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 25 Aug 2026 20:24:33 +0200 Subject: kernel/fs: ext2: simplify directory iteration --- kernel/CMakeLists.txt | 1 + .../kernel/filesystem/ext2/directory_iterator.cpp | 87 +++++++++++++++ .../kernel/filesystem/ext2/directory_iterator.hpp | 48 +++++++++ .../filesystem/ext2/directory_iterator.tests.cpp | 118 +++++++++++++++++++++ kernel/kernel/filesystem/ext2/filesystem.cpp | 36 ++----- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 8 ++ kernel/kernel/filesystem/ext2/inode.tests.cpp | 5 +- .../filesystem/ext2/linked_directory_entry.hpp | 6 ++ 8 files changed, 282 insertions(+), 27 deletions(-) create mode 100644 kernel/kernel/filesystem/ext2/directory_iterator.cpp create mode 100644 kernel/kernel/filesystem/ext2/directory_iterator.hpp create mode 100644 kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 6f998084..1a5e2421 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -75,6 +75,7 @@ target_sources("kernel_lib" PRIVATE "kernel/filesystem/devfs/module.cpp" # ext2 Filesystem + "kernel/filesystem/ext2/directory_iterator.cpp" "kernel/filesystem/ext2/error.cpp" "kernel/filesystem/ext2/filesystem.cpp" "kernel/filesystem/ext2/inode.cpp" diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.cpp new file mode 100644 index 00000000..f37c87b6 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/directory_iterator.cpp @@ -0,0 +1,87 @@ +#include + +#include + +#include +#include + +#include + +namespace kernel::filesystem::ext2 +{ + + directory_iterator::directory_iterator(inode const & inode) + : m_inode(&inode) + , m_buffer{sizeof(value_type)} + { + if (!inode.is_directory()) + { + kapi::system::panic("[FS:ext2] Tried perform directory iteration on non-directory inode {}", inode.number()); + } + read(); + } + + auto directory_iterator::operator*() const -> reference + { + return *reinterpret_cast(m_buffer.data()); + } + + auto directory_iterator::operator->() const -> pointer + { + return reinterpret_cast(m_buffer.data()); + } + + auto directory_iterator::operator++() -> directory_iterator & + { + if (!m_inode || m_file_offset >= m_inode->size()) + { + m_inode = nullptr; + return *this; + } + read(); + return *this; + } + + auto directory_iterator::operator++(int) -> directory_iterator + { + auto copy = *this; + ++(*this); + return copy; + } + + auto operator==(directory_iterator const & lhs, directory_iterator const & rhs) -> bool + { + if (lhs.m_inode == rhs.m_inode) + { + return lhs.m_inode == nullptr || lhs.m_file_offset == rhs.m_file_offset; + } + return false; + } + + auto directory_iterator::read() -> void + { + if (auto result = m_inode->read(m_buffer, m_file_offset); !result) + { + kapi::system::panic("[FS:ext2] failed to read directory entry", result.error()); + } + + auto entry = reinterpret_cast(m_buffer.data()); + + auto const remainder = entry->name_len - 1; + + if (remainder > 0) + { + m_buffer.resize(m_buffer.size() + remainder); + + if (auto result = m_inode->read(m_buffer, m_file_offset); !result) + { + kapi::system::panic("[FS:ext2] failed to read directory entry", result.error()); + } + + entry = reinterpret_cast(m_buffer.data()); + } + + m_file_offset = m_file_offset + static_cast(entry->rec_len); + } + +} // namespace kernel::filesystem::ext2 \ No newline at end of file diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.hpp b/kernel/kernel/filesystem/ext2/directory_iterator.hpp new file mode 100644 index 00000000..92dd2b51 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/directory_iterator.hpp @@ -0,0 +1,48 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_DIRECTORY_ITERATOR_HPP +#define TEACHOS_KERNEL_FILESYSTEM_EXT2_DIRECTORY_ITERATOR_HPP + +#include +#include + +#include +#include +#include + +#include +#include + +namespace kernel::filesystem::ext2 +{ + + struct directory_iterator + { + using iterator_category = std::forward_iterator_tag; + using iterator_concept = std::forward_iterator_tag; + using value_type = linked_directory_entry; + using pointer = linked_directory_entry const *; + using reference = linked_directory_entry const &; + + constexpr directory_iterator() = default; + explicit directory_iterator(inode const & inode); + + auto operator*() const -> reference; + + auto operator->() const -> pointer; + + auto operator++() -> directory_iterator &; + + auto operator++(int) -> directory_iterator; + + auto friend operator==(directory_iterator const & lhs, directory_iterator const & rhs) -> bool; + + private: + auto read() -> void; + + kstd::observer_ptr m_inode{}; + kstd::bytes m_file_offset{}; + kstd::vector m_buffer{}; + }; + +} // namespace kernel::filesystem::ext2 + +#endif \ No newline at end of file diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp new file mode 100644 index 00000000..20ef7009 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp @@ -0,0 +1,118 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, + "Ext2 directory_iterator walks a real directory and terminates", "[filesystem][ext2][readdir]") +{ + auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img"; + + GIVEN("a mounted ext2 filesystem and its root directory") + { + REQUIRE(std::filesystem::exists(image_path)); + REQUIRE_NOTHROW(setup_modules_from_img({"test_img_module"}, {image_path})); + + auto boot_device = kernel::devices::storage::determine_boot_device(); + REQUIRE(boot_device != nullptr); + + auto dev_inode = kstd::make_shared(boot_device); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + REQUIRE(mount); + + auto root = (*mount)->root_dentry()->inode(); + auto const & root_ext2_inode = static_cast(*root); + + WHEN("iterating from begin to the default-constructed end sentinel") + { + auto names = std::vector{}; + auto guard = 0; + + for (auto it = kernel::filesystem::ext2::directory_iterator{root_ext2_inode}; + it != kernel::filesystem::ext2::directory_iterator{}; ++it) + { + REQUIRE(guard++ < 64); // fails loudly on a non-terminating loop rather than hanging the suite + names.emplace_back(&it->name_start, it->name_len); + } + + THEN("iteration terminates on its own and finds the expected entries") + { + REQUIRE(guard < 64); + REQUIRE(std::ranges::find(names, ".") != names.end()); + REQUIRE(std::ranges::find(names, "..") != names.end()); + REQUIRE(std::ranges::find(names, "information") != names.end()); + } + } + } +} + +SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, + "Ext2 directory_iterator satisfies the forward-iterator multi-pass guarantee", + "[filesystem][ext2][readdir]") +{ + auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img"; + + GIVEN("an iterator positioned at the first entry of the root directory") + { + REQUIRE(std::filesystem::exists(image_path)); + REQUIRE_NOTHROW(setup_modules_from_img({"test_img_module"}, {image_path})); + + auto boot_device = kernel::devices::storage::determine_boot_device(); + REQUIRE(boot_device != nullptr); + + auto dev_inode = kstd::make_shared(boot_device); + auto fs = kstd::make_shared(); + auto mount = kernel::filesystem::mount::create(nullptr, fs, nullptr, nullptr, dev_inode); + REQUIRE(mount); + + auto root = (*mount)->root_dentry()->inode(); + auto const & root_ext2_inode = static_cast(*root); + + auto original = kernel::filesystem::ext2::directory_iterator{root_ext2_inode}; + auto const first_name = std::string{&original->name_start, original->name_len}; + + WHEN("the iterator is copied, then only the original is advanced") + { + auto copy = original; + ++original; + + THEN("the copy still refers to the first entry, unaffected by advancing the original") + { + auto const copy_name = std::string{©->name_start, copy->name_len}; + REQUIRE(copy_name == first_name); + + auto const advanced_name = std::string{&original->name_start, original->name_len}; + REQUIRE(advanced_name != first_name); + } + } + } +} + +SCENARIO("Ext2 directory_iterator's default-constructed value is a valid, comparable end sentinel", + "[filesystem][ext2][readdir]") +{ + GIVEN("two independently default-constructed iterators") + { + auto first = kernel::filesystem::ext2::directory_iterator{}; + auto second = kernel::filesystem::ext2::directory_iterator{}; + + THEN("they compare equal to each other") + { + REQUIRE(first == second); + } + } +} \ No newline at end of file diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 18af5a61..7031cf5f 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -186,13 +187,13 @@ namespace kernel::filesystem::ext2 auto filesystem::lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const -> kstd::result { - auto const ext2_parent = static_pointer_cast(parent); - if (!ext2_parent) + auto const directory = static_pointer_cast(parent); + if (!directory) { return kstd::failure(vfs_errc::invalid_inode); } - if (!ext2_parent->is_directory()) + if (!directory->is_directory()) { return kstd::failure(vfs_errc::not_a_directory); } @@ -203,34 +204,16 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - auto buffer = kstd::vector{block_size(*mount_state).value}; - - for (auto i = 0u; i < block_count(*ext2_parent, *mount_state); ++i) + for (auto it = directory_iterator{*directory}; it != directory_iterator{}; ++it) { - auto const global_block_number = inode_block_number(i, *ext2_parent, *mount_state); - if (!global_block_number) - { - return kstd::failure(global_block_number.error()); - } - - if (auto result = read_block(*global_block_number, buffer, *mount_state); !result) + if (it->inode == 0) { - return kstd::failure(result.error()); + continue; } - auto entry = reinterpret_cast(buffer.data()); - auto read = 0_B; - - while (read < block_size(*mount_state) && entry->inode != 0) + if (it->name() == name) { - auto const entry_name = std::string_view{&entry->name_start, entry->name_len}; - if (entry_name == name) - { - return read_inode(entry->inode, *mount_state); - } - - read += kstd::bytes{entry->rec_len}; - entry = reinterpret_cast(buffer.data() + read); + return read_inode(it->inode, *mount_state); } } @@ -309,6 +292,7 @@ namespace kernel::filesystem::ext2 { return kstd::failure(result.error()); } + created->set_size(block_size(*mount_state)); } if (auto result = write_inode(inode_number, created->data(), *mount_state); !result) diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 6303959d..8d1fc3d9 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -67,10 +67,12 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); REQUIRE(information.value()->is_directory()); + (*information)->set_owning_mount(*mount); auto info_1 = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(info_1); REQUIRE(info_1.value()->is_regular()); + (*info_1)->set_owning_mount(*mount); } THEN("lookup returns null for invalid inputs") @@ -79,8 +81,10 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); + (*information)->set_owning_mount(*mount); auto info_1 = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(info_1); + (*info_1)->set_owning_mount(*mount); REQUIRE(!fs->lookup(*info_1, "anything", driver_data)); REQUIRE(!fs->lookup(root, "does_not_exist", driver_data)); @@ -117,9 +121,11 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto new_inode = fs->create_inode(root, "blub", kapi::filesystem::file_type::regular, driver_data); REQUIRE(new_inode); REQUIRE(new_inode.value()->is_regular()); + (*new_inode)->set_owning_mount(*mount); lookup_result = fs->lookup(root, "blub", driver_data); REQUIRE(lookup_result); + (*lookup_result)->set_owning_mount(*mount); } THEN("a directory can be created") @@ -139,10 +145,12 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, { auto new_directory = fs->create_inode(root, "blub", kapi::filesystem::file_type::directory, driver_data); REQUIRE(new_directory); + (*new_directory)->set_owning_mount(*mount); auto new_file = fs->create_inode(new_directory.value(), "blub_file", kapi::filesystem::file_type::regular, driver_data); REQUIRE(new_file); + (*new_file)->set_owning_mount(*mount); auto lookup_result = fs->lookup(new_directory.value(), "blub_file", driver_data); REQUIRE(lookup_result); diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 2d3a2ec2..4d57768b 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -111,6 +111,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); + (*information)->set_owning_mount(*mount); + auto file = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(file); REQUIRE(file.value()->is_regular()); @@ -322,10 +324,11 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto information = fs->lookup(root, "information", driver_data); REQUIRE(information); + (*information)->set_owning_mount(*mount); + auto file = fs->lookup(*information, "info_1.txt", driver_data); REQUIRE(file); REQUIRE(file.value()->is_regular()); - (*file)->set_owning_mount(*mount); auto mount_state = static_pointer_cast(driver_data); diff --git a/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp b/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp index 08999cb8..2d364f05 100644 --- a/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp +++ b/kernel/kernel/filesystem/ext2/linked_directory_entry.hpp @@ -2,12 +2,18 @@ #define TEACHOS_KERNEL_FILESYSTEM_EXT2_LINKED_DIRECTORY_ENTRY_HPP #include +#include namespace kernel::filesystem::ext2 { //! A linked directory entry in the ext2 filesystem. struct [[gnu::packed]] linked_directory_entry { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view + { + return std::string_view{&name_start, name_len}; + } + uint32_t inode; uint16_t rec_len; uint8_t name_len; -- cgit v1.2.3 From 660c4548f2da83b938fba88e39020eae2796dc0e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 25 Aug 2026 22:49:44 +0200 Subject: kernel/fs: ext2: add a simple write batching type --- kernel/CMakeLists.txt | 1 + kernel/kernel/filesystem/ext2/filesystem.hpp | 2 + kernel/kernel/filesystem/ext2/write_batch.cpp | 67 +++++++++++++++++++++++++++ kernel/kernel/filesystem/ext2/write_batch.hpp | 53 +++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 kernel/kernel/filesystem/ext2/write_batch.cpp create mode 100644 kernel/kernel/filesystem/ext2/write_batch.hpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 1a5e2421..35c3a957 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -80,6 +80,7 @@ target_sources("kernel_lib" PRIVATE "kernel/filesystem/ext2/filesystem.cpp" "kernel/filesystem/ext2/inode.cpp" "kernel/filesystem/ext2/module.cpp" + "kernel/filesystem/ext2/write_batch.cpp" # Rootfs Filesystem "kernel/filesystem/rootfs/filesystem.cpp" diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 93836b91..f43e357c 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -191,6 +191,8 @@ namespace kernel::filesystem::ext2 -> kstd::result; private: + friend struct write_batch; + //! Allocate a single inode in the file system. //! //! @param state The driver state to operate on. diff --git a/kernel/kernel/filesystem/ext2/write_batch.cpp b/kernel/kernel/filesystem/ext2/write_batch.cpp new file mode 100644 index 00000000..e8663d21 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/write_batch.cpp @@ -0,0 +1,67 @@ +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace kernel::filesystem::ext2 +{ + + write_batch::write_batch(filesystem & filesystem, mount_state & state) + : m_filesystem{filesystem} + , m_state{state} + {} + + write_batch::~write_batch() + { + std::ranges::for_each(m_dirty_groups, [this](auto index) { + auto & descriptor = m_state.block_group_descriptors.at(index); + auto result = m_filesystem.write_block_group_descriptor(descriptor, index, m_state); + + if (!result) + { + kapi::system::panic("[FS:ext2] failed to write block groups descriptor", result.error()); + } + }); + + if (!m_dirty_groups.empty()) + { + auto result = m_filesystem.write_superblock(m_state); + if (!result) + { + kapi::system::panic("[FS:ext2] failed to write superblock", result.error()); + } + } + + std::ranges::for_each(m_dirty_inodes, [this](auto inode) { + auto result = m_filesystem.write_inode(inode->number(), inode->data(), m_state); + if (!result) + { + kapi::system::panic("[FS:ext2] failed to write inode", result.error()); + } + }); + } + + auto write_batch::mark_group(std::size_t index) -> void + { + if (std::ranges::find(m_dirty_groups, index) == std::ranges::end(m_dirty_groups)) + { + m_dirty_groups.push_back(index); + } + } + + auto write_batch::mark_inode(inode & inode) -> void + { + if (std::ranges::find(m_dirty_inodes, &inode) == std::ranges::end(m_dirty_inodes)) + { + m_dirty_inodes.push_back(&inode); + } + } + +} // namespace kernel::filesystem::ext2 diff --git a/kernel/kernel/filesystem/ext2/write_batch.hpp b/kernel/kernel/filesystem/ext2/write_batch.hpp new file mode 100644 index 00000000..103684ac --- /dev/null +++ b/kernel/kernel/filesystem/ext2/write_batch.hpp @@ -0,0 +1,53 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH +#define TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH + +#include + +#include + +namespace kernel::filesystem::ext2 +{ + + struct filesystem; + struct inode; + struct mount_state; + + //! A RAII write batching type. + //! + //! Any metadata writes are first appended to the batch. On destruction, the write is committed to the filesystem. + struct write_batch + { + //! Construct a new write batch for the given filesystem and mount state. + //! + //! @param filesystem The filesystem driver to use for writes. + //! @param state The driver state to operate on. + write_batch(filesystem & filesystem, mount_state & state); + + write_batch(write_batch const &) = delete; + write_batch(write_batch &&) = delete; + auto operator=(write_batch const &) = delete; + auto operator=(write_batch &&) = delete; + + //! Commit and destroy the batch. + ~write_batch(); + + //! Mark the group with the given index as dirty. + //! + //! @param index The index of the group to mark. + auto mark_group(std::size_t index) -> void; + + //! Mark the given inode as dirty. + //! + //! @param inode The inode to mark. + auto mark_inode(inode & inode) -> void; + + private: + filesystem & m_filesystem; + mount_state & m_state; + kstd::vector m_dirty_groups{}; + kstd::vector m_dirty_inodes{}; + }; + +} // namespace kernel::filesystem::ext2 + +#endif -- cgit v1.2.3 From 0af6ccea26ede3372d0ecf82c1e67c13145f20c1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Aug 2026 09:41:27 +0200 Subject: kernel/fs: ext2: introduce write batching --- kernel/kernel/filesystem/ext2/filesystem.cpp | 123 ++++++++++----------- kernel/kernel/filesystem/ext2/filesystem.hpp | 22 ++-- kernel/kernel/filesystem/ext2/filesystem.tests.cpp | 15 ++- kernel/kernel/filesystem/ext2/inode.cpp | 25 ++--- kernel/kernel/filesystem/ext2/inode.hpp | 4 +- kernel/kernel/filesystem/ext2/inode.tests.cpp | 2 +- 6 files changed, 96 insertions(+), 95 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 7031cf5f..3609f510 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -252,7 +253,9 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::invalid_driver_data); } - auto maybe_inode_number = allocate_inode(*mount_state); + auto batch = write_batch{*this, *mount_state}; + + auto maybe_inode_number = allocate_inode(*mount_state, batch); if (!maybe_inode_number) { return kstd::failure(maybe_inode_number.error()); @@ -280,7 +283,7 @@ namespace kernel::filesystem::ext2 created->set_owning_mount(ext2_parent->owning_mount().lock()); // 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, *created, data.mode, *mount_state); !result) + if (auto result = add_directory_entry(*ext2_parent, name, *created, data.mode, *mount_state, batch); !result) { return kstd::failure(result.error()); } @@ -288,17 +291,14 @@ namespace kernel::filesystem::ext2 if (created->is_directory()) { // TODO increment used_dirs_count in block group descriptor - if (auto result = init_directory(*created, *ext2_parent, *mount_state); !result) + if (auto result = init_directory(*created, *ext2_parent, *mount_state, batch); !result) { return kstd::failure(result.error()); } created->set_size(block_size(*mount_state)); } - if (auto result = write_inode(inode_number, created->data(), *mount_state); !result) - { - return kstd::failure(result.error()); - } + batch.mark_inode(*created); return created; } @@ -348,7 +348,7 @@ namespace kernel::filesystem::ext2 } auto filesystem::add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, - mount_state & state) -> kstd::result + mount_state & state, write_batch & batch) -> kstd::result { auto const last_block_index = block_count(directory, state) - 1; auto const global_block = inode_block_number(last_block_index, directory, state); @@ -407,7 +407,7 @@ namespace kernel::filesystem::ext2 } else { - if (!directory.append_blocks(1)) + if (!directory.append_blocks(1, batch)) { return kstd::failure(ext2_errc::not_enough_free_blocks); } @@ -439,12 +439,14 @@ namespace kernel::filesystem::ext2 auto size = block_count(directory, state) * block_size(state); directory.data().size = size.value; - return write_inode(directory.number(), directory.data(), state); + batch.mark_inode(directory); + return kstd::success(); } - auto filesystem::init_directory(inode & directory, inode & parent, mount_state & state) -> kstd::result + auto filesystem::init_directory(inode & directory, inode & parent, mount_state & state, write_batch & batch) + -> kstd::result { - if (!directory.append_blocks(1)) + if (!directory.append_blocks(1, batch)) { return kstd::failure(ext2_errc::not_enough_free_blocks); } @@ -477,10 +479,10 @@ namespace kernel::filesystem::ext2 auto & parent_inode_data = parent.data(); parent_inode_data.links_count++; - return write_inode(parent.number(), parent_inode_data, state) - .and_then([&]() { return global_block; }) - .and_then([&](auto block_number) { return write_block(block_number, buffer, state); }) - .transform([](auto) {}); + batch.mark_inode(parent); + + return global_block.and_then([&](auto number) { return write_block(number, buffer, state); }).transform([](auto) { + }); } auto filesystem::write_directory_entry_to_buffer(std::span buffer, kstd::bytes offset, inode & target, @@ -579,7 +581,8 @@ namespace kernel::filesystem::ext2 return inode_offset; } - auto filesystem::allocate_blocks(size_t count, mount_state & state) -> kstd::result> + auto filesystem::allocate_blocks(size_t count, mount_state & state, write_batch & batch) + -> kstd::result> { auto & [superblock, block_group_descriptors, backing_inode] = state; @@ -588,73 +591,70 @@ namespace kernel::filesystem::ext2 return kstd::failure(ext2_errc::not_enough_free_blocks); } - kstd::vector allocated_blocks{}; + struct pending_group + { + std::size_t index; + std::size_t claimed; + kstd::vector bitmap; + }; + + auto pending = kstd::vector{}; + auto allocated_blocks = kstd::vector{}; - for (auto block_group_descriptor_index = 0uz; block_group_descriptor_index < block_group_descriptors.size(); - ++block_group_descriptor_index) + for (auto group_index = 0uz; group_index < block_group_descriptors.size() && allocated_blocks.size() < count; + ++group_index) { - auto & block_group_descriptor = block_group_descriptors.at(block_group_descriptor_index); - if (block_group_descriptor.free_blocks_count == 0) + auto & descriptor = block_group_descriptors.at(group_index); + if (descriptor.free_blocks_count == 0) { continue; } auto block_bitmap = kstd::vector{block_size(state).value}; - if (auto read_result = read_block(block_group_descriptor.block_bitmap, block_bitmap, state); !read_result) + if (auto read_result = read_block(descriptor.block_bitmap, block_bitmap, state); !read_result) { return kstd::failure(read_result.error()); } - bool is_bitmap_dirty = false; + auto claimed = 0uz; for (auto i = 0uz; i < static_cast(superblock.blocks_per_group) && allocated_blocks.size() < count; ++i) { if (!bitmap_is_set(block_bitmap, i)) { - is_bitmap_dirty = true; - bitmap_set(block_bitmap, i); - block_group_descriptor.free_blocks_count--; - superblock.free_blocks_count--; - - allocated_blocks.push_back(i + block_group_descriptor_index * superblock.blocks_per_group); + ++claimed; + allocated_blocks.push_back(i + group_index * superblock.blocks_per_group); } } - if (is_bitmap_dirty) + if (claimed > 0) { - if (auto write_result = write_block(block_group_descriptor.block_bitmap, block_bitmap, state); !write_result) - { - return kstd::failure(write_result.error()); - } - - // TODO update all block group descriptors - if (auto write_result = - backing_inode->write(kstd::raw_bytes(block_group_descriptor), - block_group_descriptor_table_offset(state) + - block_group_descriptor_index * kstd::size_of(block_group_descriptor)); - !write_result) - { - return kstd::failure(write_result.error()); - } + pending.push_back({group_index, claimed, std::move(block_bitmap)}); } } - // TODO update all superblock copies - if (auto write_result = backing_inode->write(kstd::raw_bytes(superblock), constants::superblock_offset); - !write_result) + if (allocated_blocks.size() != count) { - return kstd::failure(write_result.error()); + return kstd::failure(ext2_errc::not_enough_free_blocks); } - if (allocated_blocks.size() != count) + for (auto & group : pending) { - return kstd::failure(ext2_errc::not_enough_free_blocks); + auto & descriptor = block_group_descriptors.at(group.index); + descriptor.free_blocks_count -= group.claimed; + superblock.free_blocks_count -= group.claimed; + + if (auto result = write_block(descriptor.block_bitmap, group.bitmap, state); !result) + { + return kstd::failure(result.error()); + } + batch.mark_group(group.index); } return allocated_blocks; } - auto filesystem::allocate_inode(mount_state & state) -> kstd::result + auto filesystem::allocate_inode(mount_state & state, write_batch & batch) -> kstd::result { auto & [superblock, block_group_descriptors, _] = state; @@ -691,18 +691,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(write_result.error()); } - 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(state); !write_result) - { - return kstd::failure(write_result.error()); - } + batch.mark_group(block_group_descriptor_index); return block_group_descriptor_index * superblock.inodes_per_group + i + 1; } @@ -788,8 +777,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, mount_state & state) - -> kstd::result + uint32_t global_block_number, mount_state & state, + write_batch & batch) -> kstd::result { if (inode_block_index < constants::direct_block_count) { @@ -820,7 +809,7 @@ namespace kernel::filesystem::ext2 if (idx == 0 && inode_block_index == 0) { - auto allocated = allocate_blocks(1, state); + auto allocated = allocate_blocks(1, state, batch); if (!allocated) { return kstd::failure(allocated.error()); diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index f43e357c..1bce8d71 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -154,8 +155,10 @@ namespace kernel::filesystem::ext2 //! //! @param count The number of blocks to allocate. //! @param state The state to operate on. + //! @param batch The active write batch. //! @return A vector of the allocated block numbers. - auto allocate_blocks(size_t count, mount_state & state) -> kstd::result>; + auto allocate_blocks(size_t count, mount_state & state, write_batch & batch) + -> kstd::result>; //! Update the number of blocks allocated to an inode. //! @@ -183,12 +186,13 @@ namespace kernel::filesystem::ext2 //! 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. + //! @param state The state to operate on. + //! @param batch The active write batch. auto write_global_block_number_to_inode_block_index(size_t block_index, inode_data & data, - uint32_t global_block_number, mount_state & state) - -> kstd::result; + uint32_t global_block_number, mount_state & state, + write_batch & batch) -> kstd::result; private: friend struct write_batch; @@ -196,8 +200,9 @@ namespace kernel::filesystem::ext2 //! Allocate a single inode in the file system. //! //! @param state The driver state to operate on. + //! @param batch The active write batch. //! @return An inode number on success, an error otherwise. - auto allocate_inode(mount_state & state) -> kstd::result; + auto allocate_inode(mount_state & state, write_batch & batch) -> kstd::result; //! Add a new directory entry to a given directory. //! @@ -206,9 +211,10 @@ namespace kernel::filesystem::ext2 //! @param child The inode number of the child. //! @param mode The file mode of the entry. //! @param state The driver state to operate on. + //! @param batch The active write batch. //! @return Nothing on success, an error code otherwise. auto add_directory_entry(inode & directory, std::string_view name, inode & child, std::uint16_t mode, - mount_state & state) -> kstd::result; + mount_state & state, write_batch & batch) -> kstd::result; //! Initialize a new directory inode. //! @@ -218,8 +224,10 @@ namespace kernel::filesystem::ext2 //! @param directory The inode to initialize. //! @param parent The parent of this newly initialized directory. //! @param state The driver state to operate on. + //! @param batch The active write batch. //! @return Nothing on success, an error otherwise. - auto init_directory(inode & directory, inode & parent, mount_state & state) -> kstd::result; + auto init_directory(inode & directory, inode & parent, mount_state & state, write_batch & batch) + -> kstd::result; //! Write a new directory entry into the given buffer. //! diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 8d1fc3d9..28aabed7 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 @@ -313,30 +314,32 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys constexpr auto doubly_global_block_number = 303; constexpr auto triply_global_block_number = 404; - REQUIRE( - fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number, *mount_state)); + auto batch = kernel::filesystem::ext2::write_batch{*fs, *mount_state}; + + REQUIRE(fs->write_global_block_number_to_inode_block_index(0, inode_data, direct_global_block_number, + *mount_state, batch)); REQUIRE(inode_data.block[0] == direct_global_block_number); REQUIRE(fs->write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number, - *mount_state)); + *mount_state, batch)); 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, *mount_state)); + singly_global_block_number + 1, *mount_state, batch)); 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, - *mount_state)); + *mount_state, batch)); 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, - *mount_state)); + *mount_state, batch)); 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); diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 34452ac8..56174638 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include @@ -136,15 +138,16 @@ namespace kernel::filesystem::ext2 auto const current_block_count = (*filesystem)->block_count(*this, **state); auto const max_new_inode_size_without_new_blocks = current_block_count * block_size; + auto batch = write_batch{**filesystem, **state}; + 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 + block_size - 1_B) / block_size; - if (!append_blocks(additional_blocks_needed)) + if (!append_blocks(additional_blocks_needed, batch)) { - // TODO handle out of space - kapi::system::panic("[EXT2] Failed to allocate blocks for inode write"); + return kstd::failure(ext2_errc::not_enough_free_blocks); } } @@ -181,11 +184,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, **state); !write_result) - { - return kstd::failure(write_result.error()); - } - + batch.mark_inode(*this); return bytes_written; } @@ -245,7 +244,7 @@ namespace kernel::filesystem::ext2 return result; } - auto inode::append_blocks(size_t count) -> bool + auto inode::append_blocks(size_t count, write_batch & batch) -> bool { auto filesystem = get_filesystem(); if (!filesystem) @@ -259,7 +258,7 @@ namespace kernel::filesystem::ext2 return false; } - auto new_blocks = (*filesystem)->allocate_blocks(count, **state); + auto new_blocks = (*filesystem)->allocate_blocks(count, **state, batch); if (!new_blocks) { return false; @@ -270,9 +269,9 @@ namespace kernel::filesystem::ext2 auto const block_index = (*filesystem)->block_count(*this, **state) + i; auto const global_block_number = new_blocks->at(i); - if (auto write_result = - (*filesystem) - ->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number, **state); + if (auto write_result = (*filesystem) + ->write_global_block_number_to_inode_block_index(block_index, m_data, + global_block_number, **state, batch); !write_result) { return false; diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index 735905e9..5393a853 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -2,6 +2,7 @@ #define TEACHOS_KERNEL_FILESYSTEM_EXT2_INODE_HPP #include +#include #include #include @@ -96,8 +97,9 @@ namespace kernel::filesystem::ext2 //! Append the specified number of blocks to this inode. //! //! @param count The number of blocks to append. + //! @param batch The active write batch. //! @return true if the blocks were successfully appended, false otherwise. - auto append_blocks(size_t count) -> bool; + auto append_blocks(size_t count, write_batch & batch) -> bool; //! Set the size of the file represented by this inode. //! diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 4d57768b..eab0aabd 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -529,7 +529,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" THEN("writing over the current size and over the number of free blocks") { auto const offset = 65 * block_size; - REQUIRE_THROWS_AS(inode.write(buffer, offset), kernel::tests::cpu::halt); + REQUIRE_FALSE(inode.write(buffer, offset)); } } } -- cgit v1.2.3 From e5f207d52676a78b85c0eabc003cfd355fcec715 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Aug 2026 10:04:27 +0200 Subject: fixup! kernel/fs: ext2: add a simple write batching type --- kernel/kernel/filesystem/ext2/write_batch.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/write_batch.hpp b/kernel/kernel/filesystem/ext2/write_batch.hpp index 103684ac..f4000391 100644 --- a/kernel/kernel/filesystem/ext2/write_batch.hpp +++ b/kernel/kernel/filesystem/ext2/write_batch.hpp @@ -1,5 +1,5 @@ -#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH -#define TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH +#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH_HPP +#define TEACHOS_KERNEL_FILESYSTEM_EXT2_WRITE_BATCH_HPP #include -- cgit v1.2.3 From c5a03077d137c4eaae471a84a459799f0372b5c7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Aug 2026 10:06:05 +0200 Subject: kernel/fs: ext: remove debug code --- kernel/kernel/filesystem/ext2/filesystem.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 3609f510..49b78d0c 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -370,11 +370,6 @@ namespace kernel::filesystem::ext2 while (true) { auto const * entry = reinterpret_cast(buffer.data() + offset); - auto f = std::string_view{&entry->name_start, entry->name_len}; - if (f.length() == 255) - { - break; - } if (offset + kstd::bytes{entry->rec_len} >= block_size(state)) { break; -- cgit v1.2.3 From 17c40c8579e36bcc842d29db4288f248aacafe7a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Aug 2026 11:17:39 +0200 Subject: fixup! kernel/fs: ext2: simplify directory iteration --- kernel/kernel/filesystem/ext2/directory_iterator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.cpp index f37c87b6..8475cdd9 100644 --- a/kernel/kernel/filesystem/ext2/directory_iterator.cpp +++ b/kernel/kernel/filesystem/ext2/directory_iterator.cpp @@ -2,11 +2,11 @@ #include +#include + #include #include -#include - namespace kernel::filesystem::ext2 { -- cgit v1.2.3 From 8f027bb373673374641c93d443bdce829ea1ca75 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 26 Aug 2026 13:29:18 +0200 Subject: kernel/fs: ext2: apply strict locking discipline --- .../kernel/filesystem/ext2/directory_iterator.cpp | 14 ++-- .../kernel/filesystem/ext2/directory_iterator.hpp | 5 +- .../filesystem/ext2/directory_iterator.tests.cpp | 9 ++- kernel/kernel/filesystem/ext2/filesystem.cpp | 84 ++++++++++++++++++++-- kernel/kernel/filesystem/ext2/filesystem.hpp | 29 +++++++- kernel/kernel/filesystem/ext2/inode.cpp | 79 +++++--------------- kernel/kernel/filesystem/ext2/mount_state.hpp | 3 + 7 files changed, 146 insertions(+), 77 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.cpp index 8475cdd9..3e614f26 100644 --- a/kernel/kernel/filesystem/ext2/directory_iterator.cpp +++ b/kernel/kernel/filesystem/ext2/directory_iterator.cpp @@ -1,6 +1,8 @@ #include +#include #include +#include #include @@ -10,8 +12,10 @@ namespace kernel::filesystem::ext2 { - directory_iterator::directory_iterator(inode const & inode) - : m_inode(&inode) + directory_iterator::directory_iterator(inode const & inode, filesystem const & filesystem, mount_state & state) + : m_inode{&inode} + , m_filesystem{&filesystem} + , m_state{&state} , m_buffer{sizeof(value_type)} { if (!inode.is_directory()) @@ -33,7 +37,7 @@ namespace kernel::filesystem::ext2 auto directory_iterator::operator++() -> directory_iterator & { - if (!m_inode || m_file_offset >= m_inode->size()) + if (!m_inode || m_file_offset >= m_filesystem->data_size(*m_inode, *m_state)) { m_inode = nullptr; return *this; @@ -60,7 +64,7 @@ namespace kernel::filesystem::ext2 auto directory_iterator::read() -> void { - if (auto result = m_inode->read(m_buffer, m_file_offset); !result) + if (auto result = m_filesystem->do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result) { kapi::system::panic("[FS:ext2] failed to read directory entry", result.error()); } @@ -73,7 +77,7 @@ namespace kernel::filesystem::ext2 { m_buffer.resize(m_buffer.size() + remainder); - if (auto result = m_inode->read(m_buffer, m_file_offset); !result) + if (auto result = m_filesystem->do_read(*m_inode, m_buffer, m_file_offset, *m_state); !result) { kapi::system::panic("[FS:ext2] failed to read directory entry", result.error()); } diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.hpp b/kernel/kernel/filesystem/ext2/directory_iterator.hpp index 92dd2b51..4e2fd9d8 100644 --- a/kernel/kernel/filesystem/ext2/directory_iterator.hpp +++ b/kernel/kernel/filesystem/ext2/directory_iterator.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -23,7 +24,7 @@ namespace kernel::filesystem::ext2 using reference = linked_directory_entry const &; constexpr directory_iterator() = default; - explicit directory_iterator(inode const & inode); + directory_iterator(inode const & inode, filesystem const & filesystem, mount_state & state); auto operator*() const -> reference; @@ -39,6 +40,8 @@ namespace kernel::filesystem::ext2 auto read() -> void; kstd::observer_ptr m_inode{}; + kstd::observer_ptr m_filesystem{}; + kstd::observer_ptr m_state{}; kstd::bytes m_file_offset{}; kstd::vector m_buffer{}; }; diff --git a/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp b/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp index 20ef7009..2d817e0b 100644 --- a/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp +++ b/kernel/kernel/filesystem/ext2/directory_iterator.tests.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -37,12 +38,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto root = (*mount)->root_dentry()->inode(); auto const & root_ext2_inode = static_cast(*root); + auto mount_state = static_pointer_cast((*mount)->driver_data()); + WHEN("iterating from begin to the default-constructed end sentinel") { auto names = std::vector{}; auto guard = 0; - for (auto it = kernel::filesystem::ext2::directory_iterator{root_ext2_inode}; + for (auto it = kernel::filesystem::ext2::directory_iterator{root_ext2_inode, *fs, *mount_state}; it != kernel::filesystem::ext2::directory_iterator{}; ++it) { REQUIRE(guard++ < 64); // fails loudly on a non-terminating loop rather than hanging the suite @@ -82,7 +85,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto root = (*mount)->root_dentry()->inode(); auto const & root_ext2_inode = static_cast(*root); - auto original = kernel::filesystem::ext2::directory_iterator{root_ext2_inode}; + auto mount_state = static_pointer_cast((*mount)->driver_data()); + + auto original = kernel::filesystem::ext2::directory_iterator{root_ext2_inode, *fs, *mount_state}; auto const first_name = std::string{&original->name_start, original->name_len}; WHEN("the iterator is copied, then only the original is advanced") diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 49b78d0c..bf977c46 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -17,12 +17,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -143,7 +145,7 @@ namespace kernel::filesystem::ext2 auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result { auto const mount_state = kstd::make_shared(); - auto & [superblock, block_group_descriptors, backing] = *mount_state; + auto & [superblock, block_group_descriptors, backing, _] = *mount_state; backing = backing_inode; @@ -205,7 +207,9 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - for (auto it = directory_iterator{*directory}; it != directory_iterator{}; ++it) + auto guard = kstd::lock_guard{mount_state->lock}; + + for (auto it = directory_iterator{*directory, *this, *mount_state}; it != directory_iterator{}; ++it) { if (it->inode == 0) { @@ -253,6 +257,7 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::invalid_driver_data); } + auto guard = kstd::lock_guard{mount_state->lock}; auto batch = write_batch{*this, *mount_state}; auto maybe_inode_number = allocate_inode(*mount_state, batch); @@ -295,7 +300,7 @@ namespace kernel::filesystem::ext2 { return kstd::failure(result.error()); } - created->set_size(block_size(*mount_state)); + set_data_size(*created, block_size(*mount_state), *mount_state); } batch.mark_inode(*created); @@ -579,7 +584,7 @@ namespace kernel::filesystem::ext2 auto filesystem::allocate_blocks(size_t count, mount_state & state, write_batch & batch) -> kstd::result> { - auto & [superblock, block_group_descriptors, backing_inode] = state; + auto & [superblock, block_group_descriptors, backing_inode, _] = state; if (block_group_descriptors.empty() || count > superblock.free_blocks_count) { @@ -649,9 +654,78 @@ namespace kernel::filesystem::ext2 return allocated_blocks; } + auto filesystem::data_size(inode const & inode, mount_state const & state) const -> kstd::bytes + { + uint64_t size = inode.data().size; + + if (revision_level(state) > constants::good_old_revision && inode.is_regular()) + { + size |= static_cast(inode.data().dir_acl) << 32; + } + + return kstd::bytes{size}; + } + + auto filesystem::set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) const -> void + { + if (revision_level(state) > constants::good_old_revision && inode.is_regular()) + { + inode.data().dir_acl = static_cast(new_size.value >> 32); + } + inode.data().size = static_cast(new_size.value); + } + + auto filesystem::do_read(inode const & inode, std::span buffer, kstd::bytes offset, + mount_state const & state) const -> kstd::result + { + auto const max_readable = data_size(inode, state) - offset; + auto const requested_size = std::min(kstd::bytes{buffer.size()}, max_readable); + + auto const block_size = this->block_size(state); + auto block_index = offset / block_size; + auto in_block_offset = offset % block_size; + + auto bytes_read = 0_B; + + while (bytes_read < requested_size) + { + auto const block_number = inode_block_number(block_index, inode, state); + if (!block_number) + { + break; + } + + auto const bytes_to_read = std::min(requested_size - bytes_read, block_size - in_block_offset); + if (block_number == 0) + { + kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value); + bytes_read += bytes_to_read; + } + else + { + auto const block_start_offset = block_number.value() * block_size; + auto const read_offset = block_start_offset + in_block_offset; + + auto const read_result = + state.backing_inode->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); + if (!read_result) + { + return kstd::failure(read_result.error()); + } + + bytes_read += read_result.value(); + } + + block_index++; + in_block_offset = 0_B; + } + + return bytes_read; + } + auto filesystem::allocate_inode(mount_state & state, write_batch & batch) -> kstd::result { - auto & [superblock, block_group_descriptors, _] = state; + auto & [superblock, block_group_descriptors, _, __] = state; if (block_group_descriptors.empty() || superblock.free_inodes_count == 0) { diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 1bce8d71..6d5720a2 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -2,6 +2,7 @@ #define TEACHOS_KERNEL_FILESYSTEM_EXT2_FILESYSTEM_HPP #include +#include #include #include #include @@ -195,7 +196,33 @@ namespace kernel::filesystem::ext2 write_batch & batch) -> kstd::result; private: - friend struct write_batch; + friend write_batch; + friend inode; + friend directory_iterator; + + //! Perform the actual read of the requested data. + //! + //! @param inode The inode whose data to read. + //! @param buffer The buffer to read into. + //! @param offset The offset inside the inode's data to start at. + //! @param state The driver state to operate on. + //! @return The number of bytes read on success, an error otherwise. + [[nodiscard]] auto do_read(inode const & inode, std::span buffer, kstd::bytes offset, + mount_state const & state) const -> kstd::result; + + //! Determine the size of an inode's data on disk. + //! + //! @param inode The inode whose data size to determine. + //! @param state The driver state to operate on. + //! @return The size of the data referenced by the inode. + [[nodiscard]] auto data_size(inode const & inode, mount_state const & state) const -> kstd::bytes; + + //! Set the size of an inode's data on disk. + //! + //! @param inode The inode whose data size to set. + //! @param new_size The size to set. + //! @param state The driver state to operate on. + auto set_data_size(inode & inode, kstd::bytes new_size, mount_state const & state) const -> void; //! Allocate a single inode in the file system. //! diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 56174638..075d6c5f 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -33,11 +34,10 @@ namespace kernel::filesystem::ext2 auto inode::read(std::span buffer, kstd::bytes offset) const -> kstd::result { - auto const max_readable = this->size() - offset; - auto const requested_size = std::min(kstd::bytes{buffer.size()}, max_readable); - if (is_symbolic_link() && this->size() <= kstd::bytes{sizeof(m_data.block)}) { + auto const max_readable = this->size() - offset; + auto const requested_size = std::min(kstd::bytes{buffer.size()}, max_readable); auto inline_target = reinterpret_cast(m_data.block.data()); kstd::libc::memcpy(buffer.data(), inline_target + offset, requested_size.value); return requested_size; @@ -61,46 +61,8 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - 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)->inode_block_number(block_index, *this, **state); - if (!block_number) - { - break; - } - - auto const bytes_to_read = std::min(requested_size - bytes_read, block_size - in_block_offset); - if (block_number == 0) - { - kstd::libc::memset(buffer.data() + bytes_read, 0, bytes_to_read.value); - bytes_read += bytes_to_read; - } - else - { - auto const block_start_offset = block_number.value() * block_size; - auto const read_offset = block_start_offset + in_block_offset; - - auto const read_result = - backing_inode->read(buffer.subspan(bytes_read.value, bytes_to_read.value), read_offset); - if (!read_result) - { - return kstd::failure(read_result.error()); - } - - bytes_read += read_result.value(); - } - - block_index++; - in_block_offset = 0_B; // After the first block, we always start at the beginning of the block - } - - return bytes_read; + auto guard = kstd::lock_guard{(*state)->lock}; + return (*filesystem)->do_read(*this, buffer, offset, **state); } auto inode::write(std::span buffer, kstd::bytes offset) -> kstd::result @@ -113,8 +75,6 @@ namespace kernel::filesystem::ext2 // TODO check maximum file size of filesystem // TODO handle sparse files - auto const new_inode_size = std::max(this->size(), offset + kstd::bytes{buffer.size()}); - auto filesystem = get_filesystem(); if (!filesystem) { @@ -133,13 +93,15 @@ namespace kernel::filesystem::ext2 return kstd::failure(vfs_errc::not_mounted); } - auto block_size = (*filesystem)->block_size(**state); + auto guard = kstd::lock_guard{(*state)->lock}; + auto batch = write_batch{**filesystem, **state}; + auto const new_inode_size = std::max((*filesystem)->data_size(*this, **state), offset + kstd::bytes{buffer.size()}); + + auto block_size = (*filesystem)->block_size(**state); auto const current_block_count = (*filesystem)->block_count(*this, **state); auto const max_new_inode_size_without_new_blocks = current_block_count * block_size; - auto batch = write_batch{**filesystem, **state}; - if (new_inode_size > max_new_inode_size_without_new_blocks) { auto const additional_blocks_needed = @@ -183,7 +145,8 @@ namespace kernel::filesystem::ext2 in_block_offset = 0_B; } - set_size(std::max(this->size(), offset + bytes_written)); + (*filesystem) + ->set_data_size(*this, std::max((*filesystem)->data_size(*this, **state), offset + bytes_written), **state); batch.mark_inode(*this); return bytes_written; } @@ -297,12 +260,8 @@ namespace kernel::filesystem::ext2 } auto state = static_pointer_cast(*driver_data); - - if ((*filesystem)->revision_level(*state) > constants::good_old_revision && is_regular()) - { - m_data.dir_acl = static_cast(new_size.value >> 32); - } - m_data.size = static_cast(new_size.value); + auto guard = kstd::lock_guard{state->lock}; + return (*filesystem)->set_data_size(*this, new_size, *state); } [[nodiscard]] auto inode::data() -> inode_data & @@ -317,8 +276,6 @@ namespace kernel::filesystem::ext2 auto inode::size() const -> kstd::bytes { - uint64_t size = m_data.size; - auto filesystem = get_filesystem(); if (!filesystem) { @@ -331,12 +288,8 @@ namespace kernel::filesystem::ext2 return 0_B; } - if ((*filesystem)->revision_level(**state) > constants::good_old_revision && is_regular()) - { - size |= static_cast(m_data.dir_acl) << 32; - } - - return kstd::bytes{size}; + auto guard = kstd::lock_guard{(*state)->lock}; + return (*filesystem)->data_size(*this, **state); } [[nodiscard]] auto inode::number() const -> uint32_t diff --git a/kernel/kernel/filesystem/ext2/mount_state.hpp b/kernel/kernel/filesystem/ext2/mount_state.hpp index e8ae8fd7..ba705382 100644 --- a/kernel/kernel/filesystem/ext2/mount_state.hpp +++ b/kernel/kernel/filesystem/ext2/mount_state.hpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -16,6 +18,7 @@ namespace kernel::filesystem::ext2 struct superblock superblock{}; kstd::vector block_group_descriptors{}; kstd::shared_ptr backing_inode{}; + mutable kapi::tracked_mutex lock{}; }; } // namespace kernel::filesystem::ext2 -- cgit v1.2.3