aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-08-28 20:21:37 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-08-28 20:21:37 +0200
commit4eab5620f49a8ef31d0c620671718c5307276ec6 (patch)
treebc3432237f64591c4b62de6b3a09dbfb6c2b0f78 /kernel
parent92e04cd721b497a6483a121f58ac15aa53325910 (diff)
downloadkernel-4eab5620f49a8ef31d0c620671718c5307276ec6.tar.xz
kernel-4eab5620f49a8ef31d0c620671718c5307276ec6.zip
kernel/vfs: implement root swivel and mount move
Previously, the device filesystem (devfs) was simply grafted on each root filesystem during boot. This caused the existence of an unreachable, dead devfs mount after the VFS instance had been initialized. This changeset implements the ability to relocate an active mount from one mount point to another. That way, no second devfs mount needs to be created. Instead, the existing devfs mount is relocated to a mount point in the persistent root filesystem that get mounted during initialization. Secondly, this changeset also alters the VFS initialization flow, so that only one root mount exists after initialization finishes.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/vfs.cpp90
-rw-r--r--kernel/kernel/vfs.hpp4
-rw-r--r--kernel/kernel/vfs.tests.cpp22
-rw-r--r--kernel/kernel/vfs/dentry.cpp5
-rw-r--r--kernel/kernel/vfs/dentry.hpp4
-rw-r--r--kernel/kernel/vfs/mount.cpp11
-rw-r--r--kernel/kernel/vfs/mount.hpp8
-rw-r--r--kernel/kernel/vfs/mount_table.cpp10
-rw-r--r--kernel/kernel/vfs/mount_table.hpp9
9 files changed, 92 insertions, 71 deletions
diff --git a/kernel/kernel/vfs.cpp b/kernel/kernel/vfs.cpp
index 5f729406..742af328 100644
--- a/kernel/kernel/vfs.cpp
+++ b/kernel/kernel/vfs.cpp
@@ -84,36 +84,56 @@ namespace kernel::vfs
}
auto [device_fs_root, device_fs_data] = *device_fs_mount_result;
- graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data);
+ auto root_devfs_mount = resolve_path_internal("/").transform([&](auto res) {
+ auto [root_dentry, root_mount] = res;
+ auto dev_dentry = kstd::make_shared<dentry>(root_dentry, device_fs_root, "dev");
+ root_dentry->add_child(dev_dentry);
+ auto mount = mount::attach(dev_dentry, *devfs, device_fs_root, device_fs_data, root_mount, nullptr);
+ m_mount_table.add_mount(mount);
+ return mount;
+ });
+
+ if (!root_devfs_mount)
+ {
+ kapi::system::panic("[OS:FS] failed to mount initial devfs!", root_devfs_mount.error());
+ }
- // 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)
+ auto resolved = resolve_path_internal("/dev/ram0");
+ if (!resolved)
{
- auto driver = driver_registry::get().match(boot_device_dentry->inode());
- if (!driver)
- {
- kstd::println(kstd::print_sink::stderr, "[OS:FS] Missing driver for root disk!");
- return;
- }
+ kapi::system::panic("[OS:FS] Failed to resolve boot disk!", resolved.error());
+ }
- auto root_dentry = resolve_path("/");
- if (!root_dentry)
- {
- kapi::system::panic("[OS:FS] No root directory found!");
- }
+ auto [boot_device_dentry, boot_device_mount_context] = *resolved;
- auto mount =
- mount::create(*root_dentry, *driver, root_mount, boot_device_mount_context, boot_device_dentry->inode());
+ auto driver = driver_registry::get().match(boot_device_dentry->inode());
+ if (!driver)
+ {
+ kstd::println(kstd::print_sink::stderr, "[OS:FS] Missing driver for root disk!");
+ return;
+ }
- if (!mount)
+ auto mount = mount::create(nullptr, *driver, nullptr, 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);
+
+ auto real_dev_dentry = resolve_path("/dev");
+ if (!real_dev_dentry)
+ {
+ if (auto result = mkdir("/dev"); !result)
{
- kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error());
+ kapi::system::panic("[OS:FS] Failed to create devfs mount point!", result.error());
}
- m_mount_table.add_mount(*mount);
+ real_dev_dentry = resolve_path("/dev");
+ }
- graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data);
+ m_mount_table.move_mount(*root_devfs_mount, *real_dev_dentry, *mount);
+ if (auto result = m_mount_table.remove_mount(root_mount); !result)
+ {
+ kapi::system::panic("[OS:FS] Failed to unmount early rootfs!", result.error());
}
}
@@ -303,25 +323,6 @@ namespace kernel::vfs
return kstd::failure(errc::no_such_file_or_directory);
}
- auto vfs::graft_persistent_device_fs(kstd::shared_ptr<filesystem> const & device_fs,
- kstd::shared_ptr<inode> const & root_inode,
- kstd::shared_ptr<driver_state> 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)
- {
- auto dev_dentry = root_mount_point_dentry->find_child("dev");
- if (!dev_dentry)
- {
- dev_dentry = kstd::make_shared<dentry>(root_mount_point_dentry, root_inode, "dev");
- root_mount_point_dentry->add_child(dev_dentry);
- }
-
- auto new_mount = mount::attach(dev_dentry, device_fs, root_inode, driver_data, root_mount, nullptr);
- m_mount_table.add_mount(new_mount);
- }
- }
-
auto vfs::resolve_path_internal(std::string_view path) const -> kstd::result<std::pair<dentry_ptr, mount_ptr>>
{
if (!path::is_valid_absolute_path(path))
@@ -360,8 +361,6 @@ namespace kernel::vfs
if (part == "..")
{
- auto parent_dentry = current_dentry->parent();
-
if (current_dentry == current_mount->root_dentry())
{
if (current_mount->mount_path() == "/")
@@ -371,12 +370,13 @@ namespace kernel::vfs
if (auto parent_mount = current_mount->parent_mount())
{
+ current_dentry = current_mount->mount_dentry()->parent();
current_mount = parent_mount;
- current_dentry = parent_dentry;
+ continue;
}
}
- current_dentry = parent_dentry;
+ current_dentry = current_dentry->parent();
continue;
}
diff --git a/kernel/kernel/vfs.hpp b/kernel/kernel/vfs.hpp
index 8688536a..4528ab2e 100644
--- a/kernel/kernel/vfs.hpp
+++ b/kernel/kernel/vfs.hpp
@@ -124,10 +124,6 @@ namespace kernel::vfs
[[nodiscard]] auto find_mount(std::string_view path) const -> kstd::result<mount_ptr>;
- auto graft_persistent_device_fs(kstd::shared_ptr<filesystem> const & device_fs,
- kstd::shared_ptr<inode> const & root_inode,
- kstd::shared_ptr<driver_state> driver_data) -> void;
-
auto create_inode(std::string_view path, kapi::filesystem::file_type type,
std::optional<kapi::filesystem::device_number> raw_device = std::nullopt) -> kstd::result<void>;
diff --git a/kernel/kernel/vfs.tests.cpp b/kernel/kernel/vfs.tests.cpp
index 0c807082..f766a992 100644
--- a/kernel/kernel/vfs.tests.cpp
+++ b/kernel/kernel/vfs.tests.cpp
@@ -238,28 +238,6 @@ SCENARIO_METHOD(kernel::tests::vfs::storage_boot_module_vfs_fixture, "VFS with f
REQUIRE(dev_ram_32 != nullptr);
}
- THEN("boot root can be unmounted and remounted again but /dev is not re-grafted")
- {
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(vfs.close(info_1.value()->absolute_path()));
-
- REQUIRE(vfs.unmount("/dev"));
- REQUIRE(vfs.unmount("/"));
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1.error() == kstd::errc::no_such_file_or_directory);
-
- REQUIRE(vfs.mount("/dev/ram0", "/"));
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- auto dev_ram_0 = vfs.open("/dev/ram0");
- REQUIRE(dev_ram_0.error() == kstd::errc::no_such_file_or_directory);
- }
-
THEN("mount with null file system fails")
{
REQUIRE(vfs.mount("/closed.txt", "/information").error() == kstd::errc::not_supported);
diff --git a/kernel/kernel/vfs/dentry.cpp b/kernel/kernel/vfs/dentry.cpp
index a7bfc3cb..c22dc0e2 100644
--- a/kernel/kernel/vfs/dentry.cpp
+++ b/kernel/kernel/vfs/dentry.cpp
@@ -93,4 +93,9 @@ namespace kernel::vfs
{
return (m_flags & static_cast<uint32_t>(flag)) != 0;
}
+
+ auto dentry::set_parent(dentry_ptr const & parent) -> void
+ {
+ m_parent = parent;
+ }
} // namespace kernel::vfs \ No newline at end of file
diff --git a/kernel/kernel/vfs/dentry.hpp b/kernel/kernel/vfs/dentry.hpp
index b15a6f6c..13dea2a3 100644
--- a/kernel/kernel/vfs/dentry.hpp
+++ b/kernel/kernel/vfs/dentry.hpp
@@ -87,6 +87,10 @@ namespace kernel::vfs
[[nodiscard]] auto has_flag(dentry_flags flag) const -> bool;
private:
+ friend struct mount_table;
+
+ auto set_parent(dentry_ptr const & parent) -> void;
+
kstd::string m_name;
kstd::weak_ptr<dentry> m_parent;
kstd::vector<dentry_ptr> m_children;
diff --git a/kernel/kernel/vfs/mount.cpp b/kernel/kernel/vfs/mount.cpp
index b5fdfa39..76f72e22 100644
--- a/kernel/kernel/vfs/mount.cpp
+++ b/kernel/kernel/vfs/mount.cpp
@@ -138,4 +138,15 @@ namespace kernel::vfs
{
return m_ref_count;
}
+
+ auto mount::set_mount_dentry(dentry_ptr const & mount_dentry) -> void
+ {
+ m_mount_dentry = mount_dentry;
+ }
+
+ auto mount::set_parent_mount(mount_ptr const & parent_mount) -> void
+ {
+ m_parent_mount = parent_mount;
+ }
+
} // namespace kernel::vfs \ No newline at end of file
diff --git a/kernel/kernel/vfs/mount.hpp b/kernel/kernel/vfs/mount.hpp
index beecb759..b0993dd3 100644
--- a/kernel/kernel/vfs/mount.hpp
+++ b/kernel/kernel/vfs/mount.hpp
@@ -86,6 +86,8 @@ namespace kernel::vfs
[[nodiscard]] auto ref_count() const -> size_t;
private:
+ friend struct mount_table;
+
//! Create a new mount with the given parameters.
//!
//! @param mount_dentry The directory entry where the filesystem is mounted.
@@ -98,6 +100,12 @@ namespace kernel::vfs
mount_ptr const & parent_mount, mount_ptr const & source_mount,
kstd::shared_ptr<vfs::driver_state> driver_state);
+ //! Set the directory entry where the filesystem is mounted.
+ auto set_mount_dentry(dentry_ptr const & mount_dentry) -> void;
+
+ //! Set the parent mount this this mount was attached beneath.
+ auto set_parent_mount(mount_ptr const & parent_mount) -> void;
+
dentry_ptr m_mount_dentry{};
dentry_ptr m_root_dentry{};
filesystem_ptr m_filesystem{};
diff --git a/kernel/kernel/vfs/mount_table.cpp b/kernel/kernel/vfs/mount_table.cpp
index 01127697..43dff516 100644
--- a/kernel/kernel/vfs/mount_table.cpp
+++ b/kernel/kernel/vfs/mount_table.cpp
@@ -83,6 +83,16 @@ namespace kernel::vfs
return (mount_it != m_mounts.end()) ? *mount_it : nullptr;
}
+ auto mount_table::move_mount(kstd::shared_ptr<mount> const & mount, kstd::shared_ptr<dentry> const & mount_point,
+ kstd::shared_ptr<struct mount> const & parent) -> void
+ {
+ mount->mount_dentry()->unset_flag(dentry::dentry_flags::is_mount_point);
+ mount->root_dentry()->set_parent(mount_point->parent());
+ mount->set_mount_dentry(mount_point);
+ mount->set_parent_mount(parent);
+ mount_point->set_flag(dentry::dentry_flags::is_mount_point);
+ }
+
auto mount_table::find_mount_iterator(std::string_view path) const
-> kstd::vector<kstd::shared_ptr<mount>>::const_iterator
{
diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp
index 140aebac..731b0ad8 100644
--- a/kernel/kernel/vfs/mount_table.hpp
+++ b/kernel/kernel/vfs/mount_table.hpp
@@ -1,6 +1,7 @@
#ifndef TEACHOS_KERNEL_VFS_MOUNT_TABLE_HPP
#define TEACHOS_KERNEL_VFS_MOUNT_TABLE_HPP
+#include <kernel/vfs/dentry.hpp>
#include <kernel/vfs/mount.hpp>
#include <kstd/memory.hpp>
@@ -37,6 +38,14 @@ namespace kernel::vfs
//! @return A pointer to the mount with the exact matching path on success, nullpointer otherwise.
[[nodiscard]] auto find_mount(std::string_view path) const -> kstd::shared_ptr<mount>;
+ //! Move the mount attachment of an existing mount
+ //!
+ //! @param mount The mount to modify.
+ //! @param mount_point The new location the mount is mounted on.
+ //! @param parent The new parent mount of the mount.
+ auto move_mount(kstd::shared_ptr<mount> const & mount, kstd::shared_ptr<dentry> const & mount_point,
+ kstd::shared_ptr<struct mount> const & parent) -> void;
+
private:
[[nodiscard]] auto has_child_mounts(kstd::shared_ptr<mount> const & parent_mount) const -> bool;
[[nodiscard]] auto find_mount_iterator(std::string_view path) const