From b93a61ce7aca1831a2e81b7bd8d5870d86554f71 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 16:36:40 +0200 Subject: kernel/vfs: mount: resolve return type todo --- kernel/kernel/vfs.cpp | 20 +------------------- kernel/kernel/vfs/mount_table.cpp | 12 +++++++----- kernel/kernel/vfs/mount_table.hpp | 15 +++------------ kernel/kernel/vfs/mount_table.tests.cpp | 21 ++++++++++----------- 4 files changed, 21 insertions(+), 47 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/vfs.cpp b/kernel/kernel/vfs.cpp index 1f996fb4..5f729406 100644 --- a/kernel/kernel/vfs.cpp +++ b/kernel/kernel/vfs.cpp @@ -220,25 +220,7 @@ namespace kernel::vfs return kstd::failure(errc::invalid_path); } - auto remove_result = m_mount_table.remove_mount(path); - if (remove_result == mount_table::operation_result::removed) - { - return kstd::success(); - } - else if (remove_result == mount_table::operation_result::mount_not_found) - { - return kstd::failure(errc::mount_point_not_found); - } - else if (remove_result == mount_table::operation_result::cannot_be_unmounted) - { - return kstd::failure(errc::mount_busy); - } - else if (remove_result == mount_table::operation_result::has_child_mounts) - { - return kstd::failure(errc::has_child_mounts); - } - - return kstd::failure(errc::unmount_failed); + return m_mount_table.remove_mount(path); } auto vfs::mkdir(std::string_view path) -> kstd::result diff --git a/kernel/kernel/vfs/mount_table.cpp b/kernel/kernel/vfs/mount_table.cpp index 2b494040..1609bc36 100644 --- a/kernel/kernel/vfs/mount_table.cpp +++ b/kernel/kernel/vfs/mount_table.cpp @@ -1,9 +1,11 @@ #include #include +#include #include #include +#include #include #include @@ -33,22 +35,22 @@ namespace kernel::vfs } } - auto mount_table::remove_mount(std::string_view path) -> operation_result + auto mount_table::remove_mount(std::string_view path) -> kstd::result { auto mount_it = find_mount_iterator(path); if (mount_it == m_mounts.end()) { - return operation_result::mount_not_found; + return kstd::failure(errc::not_mounted); } auto const & mount = *mount_it; if (!mount->is_ready_to_unmount()) { - return operation_result::cannot_be_unmounted; + return kstd::failure(errc::mount_busy); } if (has_child_mounts(mount)) { - return operation_result::has_child_mounts; + return kstd::failure(errc::has_child_mounts); } if (auto source_mount = mount->source_mount()) @@ -62,7 +64,7 @@ namespace kernel::vfs } m_mounts.erase(mount_it); - return operation_result::removed; + return kstd::success(); } auto mount_table::find_mount(std::string_view path) const -> kstd::shared_ptr diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp index 86810a16..cb44c533 100644 --- a/kernel/kernel/vfs/mount_table.hpp +++ b/kernel/kernel/vfs/mount_table.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -13,15 +14,6 @@ namespace kernel::vfs //! A table managing all mounted filesystems. struct mount_table { - //! Results for mount table operations. - enum class operation_result : int - { - removed = 0, - has_child_mounts = -1, - mount_not_found = -2, - cannot_be_unmounted = -3 - }; - //! Add a mount to the table. //! //! @param mount The mount to add. @@ -30,9 +22,8 @@ namespace kernel::vfs //! Remove the topmost mount at the given @p path. //! //! @param path The mount path to remove. - //! @return The result of the removal operation. - [[nodiscard]] auto remove_mount(std::string_view path) - -> operation_result; // TODO: replace return type with kstd::result + //! @return Nothing on success, an error otherwise. + [[nodiscard]] auto remove_mount(std::string_view path) -> kstd::result; //! Find the mount with the exact mount path matching the given path. //! diff --git a/kernel/kernel/vfs/mount_table.tests.cpp b/kernel/kernel/vfs/mount_table.tests.cpp index e8f3ec4a..52ca9313 100644 --- a/kernel/kernel/vfs/mount_table.tests.cpp +++ b/kernel/kernel/vfs/mount_table.tests.cpp @@ -2,8 +2,7 @@ #include #include -#include -#include +#include #include #include @@ -21,8 +20,8 @@ SCENARIO("Mount table construction", "[filesystem][mount_table]") THEN("removing any mount returns mount_not_found") { - REQUIRE(table.remove_mount("/") == kernel::vfs::mount_table::operation_result::mount_not_found); - REQUIRE(table.remove_mount("/any/path") == kernel::vfs::mount_table::operation_result::mount_not_found); + REQUIRE(table.remove_mount("/").error() == kernel::vfs::errc::not_mounted); + REQUIRE(table.remove_mount("/any/path").error() == kernel::vfs::errc::not_mounted); } } } @@ -70,13 +69,13 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] THEN("removing a mount that has no child mounts succeeds") { - REQUIRE(table.remove_mount("/mnt") == kernel::vfs::mount_table::operation_result::removed); + REQUIRE(table.remove_mount("/mnt")); REQUIRE_FALSE(root_dentry2->has_flag(kernel::vfs::dentry::dentry_flags::is_mount_point)); } THEN("removing a mount that does not exist returns mount_not_found") { - REQUIRE(table.remove_mount("/nonexistent") == kernel::vfs::mount_table::operation_result::mount_not_found); + REQUIRE(table.remove_mount("/nonexistent").error() == kernel::vfs::errc::not_mounted); } } @@ -108,7 +107,7 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] THEN("removing the topmost mount with the same path succeeds") { - REQUIRE(table.remove_mount("/") == kernel::vfs::mount_table::operation_result::removed); + REQUIRE(table.remove_mount("/")); REQUIRE_FALSE(root_dentry2->has_flag(kernel::vfs::dentry::dentry_flags::is_mount_point)); } } @@ -144,13 +143,13 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem] THEN("removing a mount with child mounts returns has_child_mounts") { - REQUIRE(table.remove_mount("/") == kernel::vfs::mount_table::operation_result::has_child_mounts); - REQUIRE(table.remove_mount("/mnt") == kernel::vfs::mount_table::operation_result::has_child_mounts); + REQUIRE(table.remove_mount("/").error() == kernel::vfs::errc::has_child_mounts); + REQUIRE(table.remove_mount("/mnt").error() == kernel::vfs::errc::has_child_mounts); } THEN("removing a leaf mount succeeds") { - REQUIRE(table.remove_mount("/mnt/submnt") == kernel::vfs::mount_table::operation_result::removed); + REQUIRE(table.remove_mount("/mnt/submnt")); REQUIRE_FALSE(root_dentry3->has_flag(kernel::vfs::dentry::dentry_flags::is_mount_point)); } } @@ -177,7 +176,7 @@ SCENARIO("Mount reference counting", "[filesystem][mount_table]") table.add_mount(*mount); REQUIRE((*source_mount)->ref_count() == 1); - REQUIRE(table.remove_mount("/") == kernel::vfs::mount_table::operation_result::removed); + REQUIRE(table.remove_mount("/")); REQUIRE((*source_mount)->ref_count() == 0); } } -- cgit v1.2.3 From d3125dee241cd68ace6069537d36d32fc709b945 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 16:40:11 +0200 Subject: kernel/vfs: add identity based mount removal --- kernel/kernel/vfs/mount_table.cpp | 12 +++++++++++- kernel/kernel/vfs/mount_table.hpp | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/kernel/vfs/mount_table.cpp b/kernel/kernel/vfs/mount_table.cpp index 1609bc36..01127697 100644 --- a/kernel/kernel/vfs/mount_table.cpp +++ b/kernel/kernel/vfs/mount_table.cpp @@ -44,6 +44,16 @@ namespace kernel::vfs } auto const & mount = *mount_it; + return remove_mount(mount); + } + + auto mount_table::remove_mount(kstd::shared_ptr const & mount) -> kstd::result + { + if (!mount) + { + return kstd::failure(errc::invalid_argument); + } + if (!mount->is_ready_to_unmount()) { return kstd::failure(errc::mount_busy); @@ -63,7 +73,7 @@ namespace kernel::vfs mount_dentry->unset_flag(dentry::dentry_flags::is_mount_point); } - m_mounts.erase(mount_it); + kstd::erase(m_mounts, mount); return kstd::success(); } diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp index cb44c533..140aebac 100644 --- a/kernel/kernel/vfs/mount_table.hpp +++ b/kernel/kernel/vfs/mount_table.hpp @@ -25,6 +25,12 @@ namespace kernel::vfs //! @return Nothing on success, an error otherwise. [[nodiscard]] auto remove_mount(std::string_view path) -> kstd::result; + //! Remove the given mount. + //! + //! @param path The mount path to remove. + //! @return Nothing on success, an error otherwise. + [[nodiscard]] auto remove_mount(kstd::shared_ptr const & mount) -> kstd::result; + //! Find the mount with the exact mount path matching the given path. //! //! @param path The path to match against the mount paths in the table. -- cgit v1.2.3 From 662f5870a878ed29821fd82751629a8a0dd9041f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 20:05:24 +0200 Subject: kernel/fs: ext2: fix block allocation on 1 KiB fs When computing the actual block numbers for a filesystem, care must be taken to account for which block is the actual first data block. For 1 KiB block size filesystems, that block is actually block 1, not 0. This is because the first 1 KiB on any ext2 volume is reserved for bootloader data. Complicating matters, the bitmaps don't take this into account. They essentially reflect a logical view, describing which data blocks are already allocated. On a 1 KiB filesystem, this effectively means that bit 0 of the allocation bitmap references physical block 1. Luckily, we don't need to make that determination based on the block size at all. The superblock already carries the number of the first data block. That means one can simply add that number, which is 1 in the 1 KiB block size case and 0 otherwise, to the found block index. Interestingly, this was already caught by accident when locating the authoritative block group descriptor (BGD) table. A factor of two was multiplied into the calculation in the case of a 1 KiB block size. This factor arises because the primary BGD table follows the primary superblock. Since the superblock is located in physical block 0 in all cases except for a 1 KiB block size, the BGD table generally lands in block 1. This implies an offset of 1 block size from the volume start. In the 1 KiB case, the BGD table lands in block number 2, effectively at an offset of 2 blocks from the start of the volume. This changeset makes that calculation explicit in the BGD table locator code as well. This clarifies the previously obscure factor of 2. --- kernel/kernel/filesystems/ext2/filesystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystems/ext2/filesystem.cpp b/kernel/kernel/filesystems/ext2/filesystem.cpp index 384dfc77..7eaeeba2 100644 --- a/kernel/kernel/filesystems/ext2/filesystem.cpp +++ b/kernel/kernel/filesystems/ext2/filesystem.cpp @@ -568,7 +568,7 @@ namespace kernel::filesystems::ext2 //! @return The filesystem offset of the block group descriptor table. [[nodiscard]] auto block_group_descriptor_table_offset(driver_state const & state) -> kstd::bytes { - return block_size(state) == 1024_B ? 2 * block_size(state) : block_size(state); + return (state.superblock.first_data_block + 1) * block_size(state); } //! The set of "incompatible" Extended Filesystem features supported by this driver. @@ -894,7 +894,7 @@ namespace kernel::filesystems::ext2 { bitmap_set(block_bitmap, i); ++claimed; - allocated_blocks.push_back(i + group_index * superblock.blocks_per_group); + allocated_blocks.push_back(i + group_index * superblock.blocks_per_group + superblock.first_data_block); } } -- cgit v1.2.3 From 92e04cd721b497a6483a121f58ac15aa53325910 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 20:21:18 +0200 Subject: fixup! kernel/vfs: mount: resolve return type todo --- kernel/kernel/vfs.tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/vfs.tests.cpp b/kernel/kernel/vfs.tests.cpp index 475daf2d..0c807082 100644 --- a/kernel/kernel/vfs.tests.cpp +++ b/kernel/kernel/vfs.tests.cpp @@ -284,12 +284,12 @@ SCENARIO_METHOD(kernel::tests::vfs::storage_boot_module_vfs_fixture, "VFS with f THEN("unmount with invalid path fails") { REQUIRE(vfs.unmount("").error() == kstd::errc::invalid_argument); - REQUIRE(vfs.unmount("information").error() == kstd::errc::no_such_file_or_directory); + REQUIRE(vfs.unmount("information").error() == kstd::errc::not_connected); } THEN("unmounting non-existent mount point returns expected error code") { - REQUIRE(vfs.unmount("/information/nonexistent").error() == kstd::errc::no_such_file_or_directory); + REQUIRE(vfs.unmount("/information/nonexistent").error() == kstd::errc::not_connected); } THEN("a file can be access if . in the path") -- cgit v1.2.3 From 4eab5620f49a8ef31d0c620671718c5307276ec6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 20:21:37 +0200 Subject: 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. --- kernel/kernel/vfs.cpp | 90 +++++++++++++++++++-------------------- kernel/kernel/vfs.hpp | 4 -- kernel/kernel/vfs.tests.cpp | 22 ---------- kernel/kernel/vfs/dentry.cpp | 5 +++ kernel/kernel/vfs/dentry.hpp | 4 ++ kernel/kernel/vfs/mount.cpp | 11 +++++ kernel/kernel/vfs/mount.hpp | 8 ++++ kernel/kernel/vfs/mount_table.cpp | 10 +++++ kernel/kernel/vfs/mount_table.hpp | 9 ++++ 9 files changed, 92 insertions(+), 71 deletions(-) (limited to 'kernel') 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(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 const & device_fs, - 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) - { - auto dev_dentry = root_mount_point_dentry->find_child("dev"); - if (!dev_dentry) - { - dev_dentry = kstd::make_shared(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> { 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; - auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs, - 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; 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(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 m_parent; kstd::vector 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 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 const & mount, kstd::shared_ptr const & mount_point, + kstd::shared_ptr 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>::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 #include #include @@ -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; + //! 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 const & mount, kstd::shared_ptr const & mount_point, + kstd::shared_ptr const & parent) -> void; + private: [[nodiscard]] auto has_child_mounts(kstd::shared_ptr const & parent_mount) const -> bool; [[nodiscard]] auto find_mount_iterator(std::string_view path) const -- cgit v1.2.3 From 5613771ef93a462795fa3bec0aaa436c59a9a331 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 20:27:44 +0200 Subject: fixup! kernel/vfs: add identity based mount removal --- kernel/kernel/vfs/mount_table.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp index 731b0ad8..d2bb2f94 100644 --- a/kernel/kernel/vfs/mount_table.hpp +++ b/kernel/kernel/vfs/mount_table.hpp @@ -28,7 +28,7 @@ namespace kernel::vfs //! Remove the given mount. //! - //! @param path The mount path to remove. + //! @param mount The mount to remove. //! @return Nothing on success, an error otherwise. [[nodiscard]] auto remove_mount(kstd::shared_ptr const & mount) -> kstd::result; -- cgit v1.2.3 From a24af4a33c403e9aafd079e0a91a6e184fc85c46 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Aug 2026 20:35:42 +0200 Subject: fixup! kernel/fs: ext2: fix block allocation on 1 KiB fs --- kernel/kernel/filesystems/ext2/filesystem.tests.cpp | 13 +++++++------ kernel/kernel/filesystems/ext2/inode.tests.cpp | 5 ++++- kernel/kernel/test_support/filesystems/ext2.cpp | 1 + 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/kernel/kernel/filesystems/ext2/filesystem.tests.cpp b/kernel/kernel/filesystems/ext2/filesystem.tests.cpp index c7130e99..7477a51b 100644 --- a/kernel/kernel/filesystems/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystems/ext2/filesystem.tests.cpp @@ -273,6 +273,7 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys superblock.inodes_per_group = 32; superblock.rev_level = kernel::filesystems::ext2::constants::dynamic_revision; superblock.inode_size = 128; + superblock.first_data_block = 1; auto block_group_descriptor = kernel::filesystems::ext2::block_group_descriptor{}; block_group_descriptor.block_bitmap = 255; @@ -322,7 +323,7 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys REQUIRE(write_global_block_number_to_inode_block_index(singly_start, inode_data, singly_global_block_number, *driver_state, batch)); - REQUIRE(inode_data.block[12] == 16); + REQUIRE(inode_data.block[12] == 17); REQUIRE(read_u32(static_cast(inode_data.block[12]) * block_size.value) == singly_global_block_number); @@ -333,18 +334,18 @@ SCENARIO("Ext2 block writing includes direct and all indirect levels", "[filesys REQUIRE(write_global_block_number_to_inode_block_index(doubly_start, inode_data, doubly_global_block_number, *driver_state, batch)); - REQUIRE(inode_data.block[13] == 17); + REQUIRE(inode_data.block[13] == 18); auto const doubly_leaf_table = read_u32(static_cast(inode_data.block[13]) * block_size); - REQUIRE(doubly_leaf_table == 18); + REQUIRE(doubly_leaf_table == 19); REQUIRE(read_u32(static_cast(doubly_leaf_table) * block_size) == doubly_global_block_number); REQUIRE(write_global_block_number_to_inode_block_index(triply_start, inode_data, triply_global_block_number, *driver_state, batch)); - REQUIRE(inode_data.block[14] == 19); + REQUIRE(inode_data.block[14] == 20); auto const triply_middle_table = read_u32(static_cast(inode_data.block[14]) * block_size); - REQUIRE(triply_middle_table == 20); + REQUIRE(triply_middle_table == 21); auto const triply_leaf_table = read_u32(static_cast(triply_middle_table) * block_size); - REQUIRE(triply_leaf_table == 21); + REQUIRE(triply_leaf_table == 22); REQUIRE(read_u32(static_cast(triply_leaf_table) * block_size) == triply_global_block_number); auto inode = kernel::filesystems::ext2::inode{42, inode_data}; diff --git a/kernel/kernel/filesystems/ext2/inode.tests.cpp b/kernel/kernel/filesystems/ext2/inode.tests.cpp index d7d27553..bdfb661d 100644 --- a/kernel/kernel/filesystems/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystems/ext2/inode.tests.cpp @@ -422,6 +422,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" superblock.inode_size = 128; superblock.rev_level = 1; superblock.free_blocks_count = 64 - 15; + superblock.first_data_block = 1; auto block_group_descriptor = kernel::filesystems::ext2::block_group_descriptor{}; block_group_descriptor.inode_table = 5; @@ -544,7 +545,7 @@ SCENARIO("Ext2 inode write across block boundaries", "[filesystem][ext2][inode]" REQUIRE(inode_data.blocks + 2 == read_inode.data().blocks); auto expected_blocks = inode_data.block; - expected_blocks[2] = 16; + expected_blocks[2] = 17; auto const read_blocks = read_inode.data().block; REQUIRE(expected_blocks == read_blocks); } @@ -569,6 +570,7 @@ SCENARIO("Ext2 inode get_size() and set_size() handles size correctly depending superblock.blocks_per_group = 64; superblock.inodes_per_group = 32; superblock.inode_size = 128; + superblock.first_data_block = 1; GIVEN("an ext2 inode with good old revision and inode_data.size = 256, inode_data.dir_acl = 32") { @@ -788,6 +790,7 @@ SCENARIO("Ext2 inode read_directory skips deleted entries and paginates correctl superblock.inodes_per_group = 32; superblock.inode_size = 128; superblock.rev_level = 1; + superblock.first_data_block = 1; auto block_group_descriptor = kernel::filesystems::ext2::block_group_descriptor{}; block_group_descriptor.inode_table = 5; diff --git a/kernel/kernel/test_support/filesystems/ext2.cpp b/kernel/kernel/test_support/filesystems/ext2.cpp index d9008ade..92f56aef 100644 --- a/kernel/kernel/test_support/filesystems/ext2.cpp +++ b/kernel/kernel/test_support/filesystems/ext2.cpp @@ -47,6 +47,7 @@ namespace kernel::tests::filesystems::ext2 superblock.inodes_per_group = 32; superblock.rev_level = 1; superblock.inode_size = 128; + superblock.first_data_block = 1; setup_mock_ext2_layout(device, superblock); } -- cgit v1.2.3