aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Braun <marcel.braun@ost.ch>2026-05-25 11:13:18 +0200
committerMarcel Braun <marcel.braun@ost.ch>2026-05-25 11:13:18 +0200
commit61d29a288334960cd9f43df91e4fd632a7f6ad66 (patch)
tree8ca81c4589ef2a2ca55a4a33527a6f12c34bd224
parent093074d5209f2d0062be79059f5881ee051c07d0 (diff)
downloadkernel-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.hpp13
-rw-r--r--kernel/include/kernel/filesystem/vfs.hpp7
-rw-r--r--kernel/src/filesystem/mount.cpp14
-rw-r--r--kernel/src/filesystem/mount.tests.cpp16
-rw-r--r--kernel/src/filesystem/mount_table.cpp16
-rw-r--r--kernel/src/filesystem/mount_table.tests.cpp14
-rw-r--r--kernel/src/filesystem/vfs.cpp26
-rw-r--r--kernel/src/filesystem/vfs.tests.cpp5
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")