diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-08-28 22:29:08 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-08-28 22:42:08 +0200 |
| commit | 0319e4970ed8b1410643f4387615daba5d97b4a1 (patch) | |
| tree | 72c7c17ba791c1c6035fd94acb2ff112b34f3523 | |
| parent | aca4af4a324af6b7aa64d72677e621c759575de5 (diff) | |
| download | kernel-0319e4970ed8b1410643f4387615daba5d97b4a1.tar.xz kernel-0319e4970ed8b1410643f4387615daba5d97b4a1.zip | |
kernel/vfs: implement read_directory fixups.
POSIX requires that the data returned by the readdir() function shows
the inode number of the root of a mounted filesystem for its mount
point. Additionally, the inode number of the '..' reference in the
mounted filesystem must show the inode number of the mount point.
We perform this fixup when computing the entries during read_directory
on the fly. The implementation of the upward fixup will need to be
revised once the kernel supports bind mounts.
| -rw-r--r-- | kernel/kernel/main.cpp | 2 | ||||
| -rw-r--r-- | kernel/kernel/vfs.cpp | 10 | ||||
| -rw-r--r-- | kernel/kernel/vfs.hpp | 14 | ||||
| -rw-r--r-- | kernel/kernel/vfs/directory_file_descriptor.cpp | 80 | ||||
| -rw-r--r-- | kernel/kernel/vfs/mount_table.cpp | 17 | ||||
| -rw-r--r-- | kernel/kernel/vfs/mount_table.hpp | 13 |
6 files changed, 134 insertions, 2 deletions
diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp index 52562ad7..7083d517 100644 --- a/kernel/kernel/main.cpp +++ b/kernel/kernel/main.cpp @@ -227,7 +227,7 @@ auto run_demo() -> void auto stat = kapi::filesystem::status(kstd::format("{}/{}", path, entry.name)); if (stat) { - kstd::println("\t{:<8} {:<#8o} {:>#8} {:>3}:{<3} {}", stat->inode_number, stat->mode, stat->size, + kstd::println("\t{:<8} {:<#8o} {:>#8} {:>3}:{<3} {}", entry.inode_number, stat->mode, stat->size, stat->raw_device.major, stat->raw_device.minor, entry.name); } else diff --git a/kernel/kernel/vfs.cpp b/kernel/kernel/vfs.cpp index 742af328..42e98219 100644 --- a/kernel/kernel/vfs.cpp +++ b/kernel/kernel/vfs.cpp @@ -279,6 +279,16 @@ namespace kernel::vfs return kstd::failure(errc::invalid_argument); } + auto vfs::houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool + { + return m_mount_table.houses_mounts(parent); + } + + auto vfs::find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<struct mount> + { + return m_mount_table.find_mount_at(parent, name); + } + auto vfs::create_inode(std::string_view path, kapi::filesystem::file_type type, std::optional<kapi::filesystem::device_number> raw_device) -> kstd::result<void> { diff --git a/kernel/kernel/vfs.hpp b/kernel/kernel/vfs.hpp index 4528ab2e..a722a48d 100644 --- a/kernel/kernel/vfs.hpp +++ b/kernel/kernel/vfs.hpp @@ -109,6 +109,20 @@ namespace kernel::vfs auto create_device_node(std::string_view path, std::uint32_t mode, kapi::filesystem::device_number device) -> kstd::result<void>; + //! Check if a given given dentry houses any mounts. + //! + //! @param parent The suspected mount parent. + //! @return @c true iff. there is directory below the dentry that is a mount point, @c false otherwise. + [[nodiscard]] auto houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool; + + //! Find the mount associated with a given directory in a given parent. + //! + //! @param parent The suspected parent of the suspected mount point. + //! @param name The name of the mount point. + //! @return The mount if it exists, nullptr otherwise. + [[nodiscard]] auto find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) + -> kstd::shared_ptr<struct mount>; + private: // Note: Resolving a dentry requires traversing mount points; since the associated 'mount' object is discovered as a // byproduct of this traversal, we return it alongside the dentry to avoid redundant lookups in callers that require diff --git a/kernel/kernel/vfs/directory_file_descriptor.cpp b/kernel/kernel/vfs/directory_file_descriptor.cpp index c1fb2a55..54785f81 100644 --- a/kernel/kernel/vfs/directory_file_descriptor.cpp +++ b/kernel/kernel/vfs/directory_file_descriptor.cpp @@ -1,18 +1,89 @@ #include <kernel/vfs/directory_file_descriptor.hpp> -#include <kernel/vfs/dentry.hpp> +#include <kernel/vfs.hpp> #include <kapi/filesystem.hpp> #include <kstd/memory.hpp> #include <kstd/result.hpp> +#include <algorithm> #include <cstddef> +#include <ranges> #include <span> namespace kernel::vfs { + namespace + { + + auto fixup_dot_dot(std::span<kapi::filesystem::directory_entry> entries, + kstd::shared_ptr<dentry> const & current_directory) -> void + { + auto state = current_directory->inode()->driver_state().lock(); + if (!state) + { + return; + } + + auto mount = state->owner().lock(); + if (!mount || mount->root_dentry() != current_directory || mount->mount_path() == "/") + { + return; + } + + auto parent = mount->mount_dentry()->parent(); + if (!parent) + { + return; + } + + auto parent_status = parent->inode()->status(); + if (!parent_status) + { + return; + } + + auto found = std::ranges::find(entries, "..", &kapi::filesystem::directory_entry::name); + if (found != std::ranges::end(entries)) + { + found->inode_number = parent_status->inode_number; + } + } + + auto fixup_mounts(std::span<kapi::filesystem::directory_entry> entries, + kstd::shared_ptr<dentry> const & current_directory) -> void + { + auto directories = std::views::filter( + entries, [](auto const & entry) { return entry.type == kapi::filesystem::file_type::directory; }); + + auto & vfs_instance = vfs::vfs::get(); + + if (!vfs_instance.houses_mounts(current_directory)) + { + return; + } + + std::ranges::for_each(directories, [&](auto & entry) { + auto mounted = vfs_instance.find_mount_at(current_directory, entry.name); + if (!mounted) + { + return; + } + + auto mount_root_status = mounted->root_dentry()->inode()->status(); + if (!mount_root_status) + { + return; + } + + entry.inode_number = mount_root_status->inode_number; + }); + } + + } // namespace + auto directory_file_descriptor::read_directory(std::span<kapi::filesystem::directory_entry> entries) -> kstd::result<std::size_t> { @@ -23,6 +94,13 @@ namespace kernel::vfs } m_position = result->second; + auto const count = result->first; + + auto valid_entries = entries.first(count); + + fixup_dot_dot(valid_entries, get_dentry()); + fixup_mounts(valid_entries, get_dentry()); + return result->first; } diff --git a/kernel/kernel/vfs/mount_table.cpp b/kernel/kernel/vfs/mount_table.cpp index 43dff516..c7198396 100644 --- a/kernel/kernel/vfs/mount_table.cpp +++ b/kernel/kernel/vfs/mount_table.cpp @@ -83,6 +83,23 @@ namespace kernel::vfs return (mount_it != m_mounts.end()) ? *mount_it : nullptr; } + auto mount_table::houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool + { + return std::ranges::any_of(m_mounts, [&](auto const & mount) { + auto const dentry = mount->mount_dentry(); + return dentry && dentry->parent() == parent; + }); + } + + auto mount_table::find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<mount> + { + auto found = std::ranges::find_last_if(m_mounts, [&](auto const & mount) { + auto const & dentry = mount->mount_dentry(); + return dentry && dentry->parent() == parent && dentry->name() == name; + }); + return found.begin() != std::ranges::end(m_mounts) ? *found.begin() : 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 { diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp index d2bb2f94..afeaf5eb 100644 --- a/kernel/kernel/vfs/mount_table.hpp +++ b/kernel/kernel/vfs/mount_table.hpp @@ -38,6 +38,19 @@ 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>; + //! Check if a given given dentry houses any mounts. + //! + //! @param parent The suspected mount parent. + //! @return @c true iff. there is directory below the dentry that is a mount point, @c false otherwise. + [[nodiscard]] auto houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool; + + //! Find the mount associated with a given directory in a given parent. + //! + //! @param parent The suspected parent of the suspected mount point. + //! @param name The name of the mount point. + //! @return The mount if it exists, nullptr otherwise. + [[nodiscard]] auto find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<mount>; + //! Move the mount attachment of an existing mount //! //! @param mount The mount to modify. |
