aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-08-28 22:29:08 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-08-28 22:42:08 +0200
commit0319e4970ed8b1410643f4387615daba5d97b4a1 (patch)
tree72c7c17ba791c1c6035fd94acb2ff112b34f3523 /kernel
parentaca4af4a324af6b7aa64d72677e621c759575de5 (diff)
downloadkernel-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.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/main.cpp2
-rw-r--r--kernel/kernel/vfs.cpp10
-rw-r--r--kernel/kernel/vfs.hpp14
-rw-r--r--kernel/kernel/vfs/directory_file_descriptor.cpp80
-rw-r--r--kernel/kernel/vfs/mount_table.cpp17
-rw-r--r--kernel/kernel/vfs/mount_table.hpp13
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.