diff options
| author | Marcel Braun <marcel.braun@ost.ch> | 2026-05-25 11:13:18 +0200 |
|---|---|---|
| committer | Marcel Braun <marcel.braun@ost.ch> | 2026-05-25 11:13:18 +0200 |
| commit | 61d29a288334960cd9f43df91e4fd632a7f6ad66 (patch) | |
| tree | 8ca81c4589ef2a2ca55a4a33527a6f12c34bd224 | |
| parent | 093074d5209f2d0062be79059f5881ee051c07d0 (diff) | |
| download | kernel-61d29a288334960cd9f43df91e4fd632a7f6ad66.tar.xz kernel-61d29a288334960cd9f43df91e4fd632a7f6ad66.zip | |
Increase reference count of source_mount when one of its files is mounted somewhere
| -rw-r--r-- | kernel/include/kernel/filesystem/mount.hpp | 13 | ||||
| -rw-r--r-- | kernel/include/kernel/filesystem/vfs.hpp | 7 | ||||
| -rw-r--r-- | kernel/src/filesystem/mount.cpp | 14 | ||||
| -rw-r--r-- | kernel/src/filesystem/mount.tests.cpp | 16 | ||||
| -rw-r--r-- | kernel/src/filesystem/mount_table.cpp | 16 | ||||
| -rw-r--r-- | kernel/src/filesystem/mount_table.tests.cpp | 14 | ||||
| -rw-r--r-- | kernel/src/filesystem/vfs.cpp | 26 | ||||
| -rw-r--r-- | kernel/src/filesystem/vfs.tests.cpp | 5 |
8 files changed, 69 insertions, 42 deletions
diff --git a/kernel/include/kernel/filesystem/mount.hpp b/kernel/include/kernel/filesystem/mount.hpp index 4ce374f..6c0c5b9 100644 --- a/kernel/include/kernel/filesystem/mount.hpp +++ b/kernel/include/kernel/filesystem/mount.hpp @@ -28,7 +28,8 @@ namespace kernel::filesystem @param parent_mount The parent mount that this mount is attached beneath. */ mount(kstd::shared_ptr<dentry> const & mount_dentry, kstd::shared_ptr<dentry> const & root_dentry, - kstd::shared_ptr<filesystem> const & fs, kstd::shared_ptr<mount> const & parent_mount); + kstd::shared_ptr<filesystem> const & fs, kstd::shared_ptr<mount> const & parent_mount, + kstd::shared_ptr<mount> const & source_mount); /** @brief Get the dentry where the filesystem is mounted. @@ -56,15 +57,20 @@ namespace kernel::filesystem [[nodiscard]] auto parent_mount() const -> kstd::shared_ptr<mount> const &; /** + @brief Get the source mount where this mount originates from. + */ + [[nodiscard]] auto source_mount() const -> kstd::shared_ptr<mount>; + + /** @brief Increment the reference count for this mount. */ auto increment_ref_count() -> void; /** @brief Decrement the reference count for this mount. - @return True if the reference count reached zero, false otherwise. + @warning Throws if ref_count is zero. */ - [[nodiscard]] auto decrement_ref_count() -> bool; + auto decrement_ref_count() -> void; /** @brief Check if the mount is ready to be unmounted. @@ -83,6 +89,7 @@ namespace kernel::filesystem kstd::shared_ptr<dentry> m_root_dentry; kstd::shared_ptr<filesystem> m_filesystem{}; kstd::shared_ptr<mount> m_parent_mount{}; + kstd::weak_ptr<mount> m_source_mount{}; std::atomic_size_t m_ref_count; }; } // namespace kernel::filesystem diff --git a/kernel/include/kernel/filesystem/vfs.hpp b/kernel/include/kernel/filesystem/vfs.hpp index aec8bfe..e6f2327 100644 --- a/kernel/include/kernel/filesystem/vfs.hpp +++ b/kernel/include/kernel/filesystem/vfs.hpp @@ -32,8 +32,7 @@ namespace kernel::filesystem non_existent_path = -2, mount_point_not_found = -3, unmount_failed = -4, - invalid_filesystem = -5, - close_failed = -6 + invalid_filesystem = -5 }; /** @@ -103,8 +102,8 @@ namespace kernel::filesystem [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::shared_ptr<mount>; auto do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, - kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs) - -> void; + kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs, + kstd::shared_ptr<mount> const & source_mount = nullptr) -> void; auto graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void; diff --git a/kernel/src/filesystem/mount.cpp b/kernel/src/filesystem/mount.cpp index b64c370..ead7479 100644 --- a/kernel/src/filesystem/mount.cpp +++ b/kernel/src/filesystem/mount.cpp @@ -14,11 +14,13 @@ namespace kernel::filesystem { mount::mount(kstd::shared_ptr<dentry> const & mount_dentry, kstd::shared_ptr<dentry> const & root_dentry, - kstd::shared_ptr<filesystem> const & fs, kstd::shared_ptr<mount> const & parent_mount) + kstd::shared_ptr<filesystem> const & fs, kstd::shared_ptr<mount> const & parent_mount, + kstd::shared_ptr<mount> const & source_mount) : m_mount_dentry(mount_dentry) , m_root_dentry(root_dentry) , m_filesystem(fs) , m_parent_mount(parent_mount) + , m_source_mount(source_mount) , m_ref_count(0) { if (!m_filesystem) @@ -56,20 +58,24 @@ namespace kernel::filesystem return m_parent_mount; } + auto mount::source_mount() const -> kstd::shared_ptr<mount> + { + return m_source_mount.lock(); + } + auto mount::increment_ref_count() -> void { m_ref_count += 1; } - auto mount::decrement_ref_count() -> bool + auto mount::decrement_ref_count() -> void { if (m_ref_count == 0) { - return false; + kapi::system::panic("[FILESYSTEM] decrement_ref_count() was called but ref_count is 0"); } m_ref_count -= 1; - return true; } auto mount::is_ready_to_unmount() const -> bool diff --git a/kernel/src/filesystem/mount.tests.cpp b/kernel/src/filesystem/mount.tests.cpp index 6b66571..40b7cbb 100644 --- a/kernel/src/filesystem/mount.tests.cpp +++ b/kernel/src/filesystem/mount.tests.cpp @@ -11,6 +11,8 @@ #include <catch2/catch_test_macros.hpp> +#include <stdexcept> + SCENARIO("Mount construction", "[filesystem][mount]") { GIVEN("a filesystem and a root dentry") @@ -21,7 +23,7 @@ SCENARIO("Mount construction", "[filesystem][mount]") WHEN("constructing a mount with the filesystem and root dentry") { - auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr}; + auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; THEN("the mount has the correct filesystem, root dentry, mount dentry, and mount path") { @@ -42,7 +44,7 @@ SCENARIO("Mount construction", "[filesystem][mount]") { THEN("the constructor panics") { - REQUIRE_THROWS_AS((kernel::filesystem::mount{root_dentry, root_dentry, nullptr, nullptr}), + REQUIRE_THROWS_AS((kernel::filesystem::mount{root_dentry, root_dentry, nullptr, nullptr, nullptr}), kernel::tests::cpu::halt); } } @@ -60,7 +62,7 @@ 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}; + auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; mount.increment_ref_count(); REQUIRE(mount.ref_count() == 1); @@ -70,20 +72,20 @@ SCENARIO("Mount reference counting", "[filesystem][mount]") REQUIRE(mount.ref_count() == 2); REQUIRE_FALSE(mount.is_ready_to_unmount()); - REQUIRE(mount.decrement_ref_count()); + mount.decrement_ref_count(); REQUIRE(mount.ref_count() == 1); REQUIRE_FALSE(mount.is_ready_to_unmount()); - REQUIRE(mount.decrement_ref_count()); + 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}; + auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr}; - REQUIRE_FALSE(mount.decrement_ref_count()); + REQUIRE_THROWS_AS(mount.decrement_ref_count(), std::runtime_error); REQUIRE(mount.ref_count() == 0); REQUIRE(mount.is_ready_to_unmount()); } diff --git a/kernel/src/filesystem/mount_table.cpp b/kernel/src/filesystem/mount_table.cpp index 26828b4..af8434b 100644 --- a/kernel/src/filesystem/mount_table.cpp +++ b/kernel/src/filesystem/mount_table.cpp @@ -22,6 +22,11 @@ namespace kernel::filesystem { m_mounts.push_back(mount); + if (auto source_mount = mount->source_mount()) + { + source_mount->increment_ref_count(); + } + if (auto mount_dentry = mount->mount_dentry()) { mount_dentry->set_flag(dentry::dentry_flags::is_mount_point); @@ -46,7 +51,16 @@ namespace kernel::filesystem return operation_result::has_child_mounts; } - mount->mount_dentry()->unset_flag(dentry::dentry_flags::is_mount_point); + if (auto source_mount = mount->source_mount()) + { + source_mount->decrement_ref_count(); + } + + if (auto mount_dentry = mount->mount_dentry()) + { + mount_dentry->unset_flag(dentry::dentry_flags::is_mount_point); + } + m_mounts.erase(mount_it); return operation_result::removed; } diff --git a/kernel/src/filesystem/mount_table.tests.cpp b/kernel/src/filesystem/mount_table.tests.cpp index f22b25e..8118e19 100644 --- a/kernel/src/filesystem/mount_table.tests.cpp +++ b/kernel/src/filesystem/mount_table.tests.cpp @@ -38,14 +38,14 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); - auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr); + auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>(); auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/mnt"); - auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr); + auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr, nullptr); table.add_mount(mount1); table.add_mount(mount2); @@ -89,14 +89,14 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); - auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr); + auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>(); auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); - auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr); + auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr, nullptr); table.add_mount(mount1); table.add_mount(mount2); @@ -122,21 +122,21 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); - auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr); + auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr); auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>(); auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>( mount_dentry1, kstd::make_shared<kernel::tests::filesystem::inode>(), "mnt"); - auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, mount1); + auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, mount1, nullptr); auto fs3 = kstd::make_shared<kernel::tests::filesystem::filesystem>(); auto root_dentry3 = kstd::make_shared<kernel::filesystem::dentry>( nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/"); auto mount_dentry3 = kstd::make_shared<kernel::filesystem::dentry>( mount_dentry2, kstd::make_shared<kernel::tests::filesystem::inode>(), "submnt"); - auto mount3 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry3, root_dentry3, fs3, mount2); + auto mount3 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry3, root_dentry3, fs3, mount2, nullptr); table.add_mount(mount1); table.add_mount(mount2); diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp index bf9a77d..ae85291 100644 --- a/kernel/src/filesystem/vfs.cpp +++ b/kernel/src/filesystem/vfs.cpp @@ -47,7 +47,7 @@ namespace kernel::filesystem root_fs->mount(nullptr); auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/"); - auto root_mount = kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, nullptr); + auto root_mount = kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) @@ -56,13 +56,14 @@ namespace kernel::filesystem graft_persistent_device_fs(device_fs); // mount boot fs at / (shadows rootfs), re-graft devfs - if (auto boot_device_dentry = resolve_path("/dev/ram0")) + auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0"); + 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 root_dentry = resolve_path("/")) { - do_mount_internal(root_dentry, root_mount, boot_root_fs); + do_mount_internal(root_dentry, root_mount, boot_root_fs, boot_device_mount_context); graft_persistent_device_fs(device_fs); } } @@ -94,11 +95,8 @@ namespace kernel::filesystem { if (auto mount = find_mount(path)) { - if (mount->decrement_ref_count()) - { - return operation_result::success; - } - return operation_result::close_failed; + mount->decrement_ref_count(); + return operation_result::success; } return operation_result::invalid_path; } @@ -111,14 +109,14 @@ namespace kernel::filesystem } auto [mount_point_dentry, mount_context] = resolve_path_internal(target); - if (mount_point_dentry && mount_context) { - if (auto source_dentry = resolve_path(source)) + auto [source_dentry, source_mount_context] = resolve_path_internal(source); + if (source_dentry && source_mount_context) { if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode())) { - do_mount_internal(mount_point_dentry, mount_context, fs); + do_mount_internal(mount_point_dentry, mount_context, fs, source_mount_context); return operation_result::success; } return operation_result::invalid_filesystem; @@ -149,12 +147,12 @@ namespace kernel::filesystem } auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, - kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs) - -> void + kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs, + kstd::shared_ptr<mount> const & source_mount) -> void { auto new_fs_root = kstd::make_shared<dentry>(mount_point_dentry->parent(), fs->root_inode(), mount_point_dentry->name()); - auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, parent_mount); + auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount); m_mount_table.add_mount(new_mount); } diff --git a/kernel/src/filesystem/vfs.tests.cpp b/kernel/src/filesystem/vfs.tests.cpp index 6fcc84e..8ae206a 100644 --- a/kernel/src/filesystem/vfs.tests.cpp +++ b/kernel/src/filesystem/vfs.tests.cpp @@ -10,6 +10,7 @@ #include <cstddef> #include <filesystem> +#include <stdexcept> #include <string_view> SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS with dummy modules", @@ -156,7 +157,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("file with invalid path or not opened file cannot be closed") { REQUIRE(vfs.close("invalid_path") == kernel::filesystem::vfs::operation_result::invalid_path); - REQUIRE(vfs.close("/information/info_1.txt") == kernel::filesystem::vfs::operation_result::close_failed); + REQUIRE_THROWS_AS(vfs.close("/information/info_1.txt"), std::runtime_error); } THEN("file cannot be closed twice") @@ -165,7 +166,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS REQUIRE(info_1 != nullptr); REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::close_failed); + REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path().view()), std::runtime_error); } THEN("images can be stacked mounted and correct file system is unmounted again") |
