aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Braun <marcel.braun@ost.ch>2026-05-16 14:20:38 +0200
committerMarcel Braun <marcel.braun@ost.ch>2026-05-16 14:20:38 +0200
commit106e9731aaf856f940592c02953e49a496555822 (patch)
treef3916a9865d03ebb574bac7d5496f6ec85d638ed
parentd22812dbf54a9fd8ecd558a94bf4ee789caf8011 (diff)
parent5b40e4a28307eed814adb46188c3f6783651d286 (diff)
downloadkernel-106e9731aaf856f940592c02953e49a496555822.tar.xz
kernel-106e9731aaf856f940592c02953e49a496555822.zip
Merge branch 'mount-reference-count' into 'develop-BA-FS26'
Mount reference count See merge request teachos/kernel!37
-rw-r--r--kernel/include/kernel/filesystem/dentry.hpp11
-rw-r--r--kernel/include/kernel/filesystem/mount.hpp26
-rw-r--r--kernel/include/kernel/filesystem/mount_table.hpp7
-rw-r--r--kernel/include/kernel/filesystem/open_file_descriptor.hpp20
-rw-r--r--kernel/include/kernel/filesystem/rootfs/filesystem.hpp2
-rw-r--r--kernel/include/kernel/filesystem/rootfs/inode.hpp26
-rw-r--r--kernel/include/kernel/filesystem/vfs.hpp29
-rw-r--r--kernel/kapi/filesystem.cpp12
-rw-r--r--kernel/kapi/filesystem.tests.cpp22
-rw-r--r--kernel/src/filesystem/dentry.cpp11
-rw-r--r--kernel/src/filesystem/ext2/inode.tests.cpp2
-rw-r--r--kernel/src/filesystem/mount.cpp28
-rw-r--r--kernel/src/filesystem/mount.tests.cpp42
-rw-r--r--kernel/src/filesystem/mount_table.cpp27
-rw-r--r--kernel/src/filesystem/mount_table.tests.cpp10
-rw-r--r--kernel/src/filesystem/open_file_descriptor.cpp22
-rw-r--r--kernel/src/filesystem/open_file_descriptor.tests.cpp38
-rw-r--r--kernel/src/filesystem/open_file_table.tests.cpp10
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.cpp9
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.tests.cpp7
-rw-r--r--kernel/src/filesystem/rootfs/inode.cpp14
-rw-r--r--kernel/src/filesystem/rootfs/inode.tests.cpp47
-rw-r--r--kernel/src/filesystem/vfs.cpp97
-rw-r--r--kernel/src/filesystem/vfs.tests.cpp60
24 files changed, 357 insertions, 222 deletions
diff --git a/kernel/include/kernel/filesystem/dentry.hpp b/kernel/include/kernel/filesystem/dentry.hpp
index 7eef693..925768a 100644
--- a/kernel/include/kernel/filesystem/dentry.hpp
+++ b/kernel/include/kernel/filesystem/dentry.hpp
@@ -24,8 +24,7 @@ namespace kernel::filesystem
*/
enum class dentry_flags : uint32_t
{
- is_mount_point = 1 << 0,
- is_mount_root = 1 << 1,
+ is_mount_point = 1 << 0
};
/**
@@ -62,12 +61,6 @@ namespace kernel::filesystem
[[nodiscard]] auto get_absolute_path() const -> kstd::string;
/**
- @brief traverse parent dentries until dentry with is_mount_root flag is found.
- @return The found dentry.
- */
- [[nodiscard]] auto find_mount_root_dentry() const -> kstd::shared_ptr<dentry>;
-
- /**
@brief Add a @p child dentry.
@param child The child dentry to add.
*/
@@ -104,7 +97,7 @@ namespace kernel::filesystem
kstd::shared_ptr<dentry> m_parent;
kstd::vector<kstd::shared_ptr<dentry>> m_children;
kstd::shared_ptr<inode> m_inode;
- uint32_t m_flags{0};
+ uint32_t m_flags;
};
} // namespace kernel::filesystem
diff --git a/kernel/include/kernel/filesystem/mount.hpp b/kernel/include/kernel/filesystem/mount.hpp
index f920891..5d8ea69 100644
--- a/kernel/include/kernel/filesystem/mount.hpp
+++ b/kernel/include/kernel/filesystem/mount.hpp
@@ -8,6 +8,7 @@
#include <kstd/string>
#include <atomic>
+#include <cstddef>
namespace kernel::filesystem
{
@@ -54,12 +55,35 @@ namespace kernel::filesystem
*/
[[nodiscard]] auto get_parent_mount() const -> kstd::shared_ptr<mount> const &;
+ /**
+ @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.
+ */
+ auto decrement_ref_count() -> bool;
+
+ /**
+ @brief Check if the mount is ready to be unmounted.
+ @return True if the mount is ready to be unmounted, false otherwise.
+ */
+ [[nodiscard]] auto is_ready_to_unmount() const -> bool;
+
+ /**
+ @brief Get the current reference count for this mount.
+ @return The current reference count.
+ */
+ [[nodiscard]] auto get_ref_count() const -> size_t;
+
private:
kstd::shared_ptr<dentry> m_mount_dentry;
kstd::shared_ptr<dentry> m_root_dentry;
kstd::shared_ptr<filesystem> m_filesystem{};
kstd::shared_ptr<mount> m_parent_mount{};
- std::atomic_uint32_t m_ref_count{0}; // TODO BA-FS26
+ std::atomic_size_t m_ref_count;
};
} // namespace kernel::filesystem
diff --git a/kernel/include/kernel/filesystem/mount_table.hpp b/kernel/include/kernel/filesystem/mount_table.hpp
index 59b9503..4f2d1b7 100644
--- a/kernel/include/kernel/filesystem/mount_table.hpp
+++ b/kernel/include/kernel/filesystem/mount_table.hpp
@@ -22,7 +22,8 @@ namespace kernel::filesystem
{
removed = 0,
has_child_mounts = -1,
- mount_not_found = -2
+ mount_not_found = -2,
+ cannot_be_unmounted = -3
};
/**
@@ -43,10 +44,12 @@ namespace kernel::filesystem
@param path The path to match against the mount paths in the table.
@return A pointer to the mount with the exact matching path, or a null pointer if no mount matches the path.
*/
- [[nodiscard]] auto find_exact_mount(std::string_view path) const -> kstd::shared_ptr<mount>;
+ [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::shared_ptr<mount>;
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
+ -> kstd::vector<kstd::shared_ptr<mount>>::const_iterator;
kstd::vector<kstd::shared_ptr<mount>> m_mounts;
};
diff --git a/kernel/include/kernel/filesystem/open_file_descriptor.hpp b/kernel/include/kernel/filesystem/open_file_descriptor.hpp
index 036dcf0..7ca7350 100644
--- a/kernel/include/kernel/filesystem/open_file_descriptor.hpp
+++ b/kernel/include/kernel/filesystem/open_file_descriptor.hpp
@@ -1,7 +1,7 @@
#ifndef TEACH_OS_KERNEL_FILESYSTEM_OPEN_FILE_DESCRIPTOR_HPP
#define TEACH_OS_KERNEL_FILESYSTEM_OPEN_FILE_DESCRIPTOR_HPP
-#include <kernel/filesystem/inode.hpp>
+#include <kernel/filesystem/dentry.hpp>
#include <kstd/memory>
@@ -11,15 +11,15 @@ namespace kernel::filesystem
{
/**
@brief Represents an open file descriptor in the filesystem. This class encapsulates the state of an open file,
- including a reference to the associated inode and the current file offset.
+ including a reference to the associated dentry and the current file offset.
*/
struct open_file_descriptor
{
/**
- @brief Constructs an open file descriptor for the given @p inode.
- @param inode The inode to associate with the open file descriptor.
+ @brief Constructs an open file descriptor for the given @p dentry.
+ @param dentry The dentry to associate with the open file descriptor.
*/
- explicit open_file_descriptor(kstd::shared_ptr<inode> const & inode);
+ explicit open_file_descriptor(kstd::shared_ptr<dentry> const & dentry);
/**
@brief Destructor for the open file descriptor.
@@ -50,10 +50,16 @@ namespace kernel::filesystem
@brief Returns the current file offset for this open file descriptor.
@return The current file offset in bytes.
*/
- [[nodiscard]] auto offset() const -> size_t;
+ [[nodiscard]] auto get_offset() const -> size_t;
+
+ /**
+ @brief Return a reference to the dentry associated with this open file descriptor.
+ @return A reference to the associated dentry.
+ */
+ [[nodiscard]] auto get_dentry() const -> kstd::shared_ptr<dentry> const &;
private:
- kstd::shared_ptr<inode> m_inode;
+ kstd::shared_ptr<dentry> m_dentry;
size_t m_offset;
};
diff --git a/kernel/include/kernel/filesystem/rootfs/filesystem.hpp b/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
index cc778d8..f99440b 100644
--- a/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
+++ b/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
@@ -31,7 +31,7 @@ namespace kernel::filesystem::rootfs
@brief Looks up an inode by @p name within a @p parent directory.
@param parent The parent directory inode.
@param name The name of the inode to look up.
- @return A pointer to the found inode, or a null pointer if not found.
+ @return Always returns nullptr.
*/
auto lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name)
-> kstd::shared_ptr<kernel::filesystem::inode> override;
diff --git a/kernel/include/kernel/filesystem/rootfs/inode.hpp b/kernel/include/kernel/filesystem/rootfs/inode.hpp
index 58035ea..2671207 100644
--- a/kernel/include/kernel/filesystem/rootfs/inode.hpp
+++ b/kernel/include/kernel/filesystem/rootfs/inode.hpp
@@ -8,16 +8,10 @@
#include <kstd/vector>
#include <cstddef>
-#include <string_view>
-#include <utility>
-
namespace kernel::filesystem::rootfs
{
/**
- @brief Represents an inode in the rootfs filesystem. This inode represents a directory in the root filesystem and
- maintains a list of child inodes corresponding to files and subdirectories within the root directory. The rootfs inode
- provides methods for reading and writing data (which are no-ops for the root directory), as well as adding and looking
- up child inodes by name.
+ @brief Represents an inode in the rootfs filesystem.
*/
struct inode : kernel::filesystem::inode
{
@@ -40,26 +34,10 @@ namespace kernel::filesystem::rootfs
auto write(void const * buffer, size_t offset, size_t size) -> size_t override;
/**
- @brief Adds a child inode to the rootfs directory inode with the specified @p name.
- @param name The name of the child inode.
- */
- auto add_child(std::string_view name) -> void;
-
- /**
- @brief Looks up a child inode by @p name.
- @param name The name of the child inode to look up.
- @return A pointer to the found child inode, or a null pointer if not found.
- */
- auto lookup_child(std::string_view name) -> kstd::shared_ptr<inode>;
-
- /**
@brief Check if this inode represents a directory.
- @return returns true, since this inode represents the root directory in the rootfs filesystem.
+ @return returns true, since this inode represents the / directory in the rootfs filesystem.
*/
[[nodiscard]] auto is_directory() const -> bool override;
-
- private:
- kstd::vector<std::pair<kstd::string, kstd::shared_ptr<inode>>> m_children;
};
} // namespace kernel::filesystem::rootfs
diff --git a/kernel/include/kernel/filesystem/vfs.hpp b/kernel/include/kernel/filesystem/vfs.hpp
index b5053a2..0058d04 100644
--- a/kernel/include/kernel/filesystem/vfs.hpp
+++ b/kernel/include/kernel/filesystem/vfs.hpp
@@ -1,14 +1,16 @@
#ifndef TEACH_OS_KERNEL_FILESYSTEM_VFS_HPP
#define TEACH_OS_KERNEL_FILESYSTEM_VFS_HPP
-#include "kernel/filesystem/devfs/filesystem.hpp"
#include <kernel/filesystem/dentry.hpp>
+#include <kernel/filesystem/devfs/filesystem.hpp>
#include <kernel/filesystem/filesystem.hpp>
+#include <kernel/filesystem/mount.hpp>
#include <kernel/filesystem/mount_table.hpp>
#include <kstd/memory>
#include <string_view>
+#include <utility>
namespace kernel::filesystem
{
@@ -31,6 +33,7 @@ namespace kernel::filesystem
mount_point_not_found = -3,
unmount_failed = -4,
invalid_filesystem = -5,
+ close_failed = -6
};
/**
@@ -59,6 +62,13 @@ namespace kernel::filesystem
auto open(std::string_view path) -> kstd::shared_ptr<dentry>;
/**
+ @brief Close a file by its associated @p path.
+ @param path The path to the file to close.
+ @return The result of the close operation.
+ */
+ auto close(std::string_view path) -> operation_result;
+
+ /**
@brief Mount a @p source path to a specific @p target path.
@param source The source of the filesystem to mount.
@param target The path where the filesystem should be mounted.
@@ -77,8 +87,23 @@ namespace kernel::filesystem
vfs() = default;
auto init_internal() -> void;
+ /**
+ * 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 mount context.
+ *
+ * If only one component is needed, the convenience wrappers can be used:
+ * - resolve_path() for the dentry only.
+ * - find_mount() for the mount context only.
+ */
+ [[nodiscard]] auto resolve_path_internal(std::string_view path)
+ -> std::pair<kstd::shared_ptr<dentry>, kstd::shared_ptr<mount>>;
[[nodiscard]] auto resolve_path(std::string_view path) -> kstd::shared_ptr<dentry>;
- auto do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, kstd::shared_ptr<filesystem> const & fs)
+ [[nodiscard]] auto find_mount(std::string_view path) -> 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;
auto graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void;
diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp
index 4c68f28..53a71be 100644
--- a/kernel/kapi/filesystem.cpp
+++ b/kernel/kapi/filesystem.cpp
@@ -35,7 +35,7 @@ namespace kapi::filesystem
{
if (auto dentry = kernel::filesystem::vfs::get().open(path))
{
- auto open_file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry->get_inode());
+ auto open_file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
return kernel::filesystem::open_file_table::get().add_file(open_file_descriptor);
}
@@ -44,7 +44,15 @@ namespace kapi::filesystem
auto close(int file_descriptor) -> int
{
- return kernel::filesystem::open_file_table::get().remove_file(file_descriptor);
+ if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().get_file(file_descriptor))
+ {
+ if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success)
+ {
+ return kernel::filesystem::open_file_table::get().remove_file(file_descriptor);
+ }
+ }
+ return -1;
}
auto read(int file_descriptor, void * buffer, size_t size) -> ssize_t
diff --git a/kernel/kapi/filesystem.tests.cpp b/kernel/kapi/filesystem.tests.cpp
index 1d1f8ee..d241afa 100644
--- a/kernel/kapi/filesystem.tests.cpp
+++ b/kernel/kapi/filesystem.tests.cpp
@@ -103,6 +103,19 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap
REQUIRE(kapi::filesystem::umount("/information") == 0);
}
+ THEN("a filesystem cannot be unmounted if files are still open and can be unmounted after files are closed")
+ {
+ REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information") == 0);
+
+ auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt");
+ REQUIRE(fd >= 0);
+
+ REQUIRE(kapi::filesystem::umount("/information") < 0);
+
+ REQUIRE(kapi::filesystem::close(fd) == 0);
+ REQUIRE(kapi::filesystem::umount("/information") == 0);
+ }
+
THEN("device can be opened as file and read from")
{
auto fd = kapi::filesystem::open("/dev/ram0");
@@ -158,6 +171,15 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap
REQUIRE(kapi::filesystem::close(999) < 0);
}
+ THEN("same file cannot be closed twice")
+ {
+ auto fd = kapi::filesystem::open("/information/info_1.txt");
+ REQUIRE(fd >= 0);
+
+ REQUIRE(kapi::filesystem::close(fd) == 0);
+ REQUIRE(kapi::filesystem::close(fd) < 0);
+ }
+
THEN("not opened files cannot be read from")
{
std::vector<std::byte> buffer(10);
diff --git a/kernel/src/filesystem/dentry.cpp b/kernel/src/filesystem/dentry.cpp
index c21771b..d963ed7 100644
--- a/kernel/src/filesystem/dentry.cpp
+++ b/kernel/src/filesystem/dentry.cpp
@@ -17,6 +17,7 @@ namespace kernel::filesystem
: m_name(name)
, m_parent(parent)
, m_inode(inode)
+ , m_flags(0)
{
if (!m_inode)
{
@@ -66,16 +67,6 @@ namespace kernel::filesystem
return path;
}
- auto dentry::find_mount_root_dentry() const -> kstd::shared_ptr<dentry>
- {
- auto parent = m_parent;
- while (parent && !parent->has_flag(dentry_flags::is_mount_root))
- {
- parent = parent->get_parent();
- }
- return parent;
- }
-
auto dentry::add_child(kstd::shared_ptr<dentry> const & child) -> void
{
m_children.push_back(child);
diff --git a/kernel/src/filesystem/ext2/inode.tests.cpp b/kernel/src/filesystem/ext2/inode.tests.cpp
index 45bea51..efc0660 100644
--- a/kernel/src/filesystem/ext2/inode.tests.cpp
+++ b/kernel/src/filesystem/ext2/inode.tests.cpp
@@ -1,9 +1,9 @@
#include <kernel/filesystem/ext2/inode.hpp>
-#include "kernel/filesystem/ext2/superblock.hpp"
#include <kernel/devices/storage/management.hpp>
#include <kernel/filesystem/device_inode.hpp>
#include <kernel/filesystem/ext2/filesystem.hpp>
+#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/test_support/cpu.hpp>
#include <kernel/test_support/devices/block_device.hpp>
diff --git a/kernel/src/filesystem/mount.cpp b/kernel/src/filesystem/mount.cpp
index 749c86a..1e04083 100644
--- a/kernel/src/filesystem/mount.cpp
+++ b/kernel/src/filesystem/mount.cpp
@@ -8,6 +8,7 @@
#include <kstd/memory>
#include <kstd/string>
+#include <cstddef>
#include <string_view>
namespace kernel::filesystem
@@ -18,6 +19,7 @@ namespace kernel::filesystem
, m_root_dentry(root_dentry)
, m_filesystem(fs)
, m_parent_mount(parent_mount)
+ , m_ref_count(0)
{
if (!m_filesystem)
{
@@ -53,4 +55,30 @@ namespace kernel::filesystem
{
return m_parent_mount;
}
+
+ auto mount::increment_ref_count() -> void
+ {
+ m_ref_count += 1;
+ }
+
+ auto mount::decrement_ref_count() -> bool
+ {
+ if (m_ref_count == 0)
+ {
+ return false;
+ }
+
+ m_ref_count -= 1;
+ return true;
+ }
+
+ auto mount::is_ready_to_unmount() const -> bool
+ {
+ return m_ref_count == 0;
+ }
+
+ auto mount::get_ref_count() const -> size_t
+ {
+ return m_ref_count;
+ }
} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount.tests.cpp b/kernel/src/filesystem/mount.tests.cpp
index 58e9bab..e7dd709 100644
--- a/kernel/src/filesystem/mount.tests.cpp
+++ b/kernel/src/filesystem/mount.tests.cpp
@@ -29,6 +29,7 @@ SCENARIO("Mount construction", "[filesystem][mount]")
REQUIRE(mount.get_root_dentry() == root_dentry);
REQUIRE(mount.get_mount_dentry() == root_dentry);
REQUIRE(mount.get_mount_path() == "/");
+ REQUIRE(mount.is_ready_to_unmount());
}
THEN("the mount has no parent mount")
@@ -47,3 +48,44 @@ SCENARIO("Mount construction", "[filesystem][mount]")
}
}
}
+
+SCENARIO("Mount reference counting", "[filesystem][mount]")
+{
+ GIVEN("a filesystem and a root dentry")
+ {
+ auto fs = kstd::make_shared<kernel::tests::filesystem::filesystem>();
+ auto root_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
+ auto root_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, root_inode, "/");
+
+ 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};
+
+ mount.increment_ref_count();
+ REQUIRE(mount.get_ref_count() == 1);
+ REQUIRE_FALSE(mount.is_ready_to_unmount());
+
+ mount.increment_ref_count();
+ REQUIRE(mount.get_ref_count() == 2);
+ REQUIRE_FALSE(mount.is_ready_to_unmount());
+
+ REQUIRE(mount.decrement_ref_count());
+ REQUIRE(mount.get_ref_count() == 1);
+ REQUIRE_FALSE(mount.is_ready_to_unmount());
+
+ REQUIRE(mount.decrement_ref_count());
+ REQUIRE(mount.get_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};
+
+ REQUIRE_FALSE(mount.decrement_ref_count());
+ REQUIRE(mount.get_ref_count() == 0);
+ REQUIRE(mount.is_ready_to_unmount());
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/src/filesystem/mount_table.cpp b/kernel/src/filesystem/mount_table.cpp
index 5a49e7a..9951590 100644
--- a/kernel/src/filesystem/mount_table.cpp
+++ b/kernel/src/filesystem/mount_table.cpp
@@ -26,25 +26,21 @@ namespace kernel::filesystem
{
mount_dentry->set_flag(dentry::dentry_flags::is_mount_point);
}
- if (auto root_dentry = mount->get_root_dentry())
- {
- root_dentry->set_flag(dentry::dentry_flags::is_mount_root);
- }
}
auto mount_table::remove_mount(std::string_view path) -> operation_result
{
- // TODO BA-FS26 check wheter something is open in this mount
- auto mount_range =
- std::ranges::find_last_if(m_mounts, [&](auto const & mount) { return mount->get_mount_path() == path; });
- auto mount_it = mount_range.begin();
-
+ auto mount_it = find_mount_iterator(path);
if (mount_it == m_mounts.end())
{
return operation_result::mount_not_found;
}
auto const & mount = *mount_it;
+ if (!mount->is_ready_to_unmount())
+ {
+ return operation_result::cannot_be_unmounted;
+ }
if (has_child_mounts(mount))
{
return operation_result::has_child_mounts;
@@ -55,11 +51,16 @@ namespace kernel::filesystem
return operation_result::removed;
}
- auto mount_table::find_exact_mount(std::string_view path) const -> kstd::shared_ptr<mount>
+ auto mount_table::find_mount(std::string_view path) const -> kstd::shared_ptr<mount>
{
- auto mount_range =
- std::ranges::find_last_if(m_mounts, [&](auto const & mount) { return mount->get_mount_path() == path; });
- auto mount_it = mount_range.begin();
+ auto mount_it = find_mount_iterator(path);
return (mount_it != m_mounts.end()) ? *mount_it : nullptr;
}
+
+ auto mount_table::find_mount_iterator(std::string_view path) const
+ -> kstd::vector<kstd::shared_ptr<mount>>::const_iterator
+ {
+ return std::ranges::find_last_if(m_mounts, [&](auto const & mount) { return mount->get_mount_path() == path; })
+ .begin();
+ }
} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount_table.tests.cpp b/kernel/src/filesystem/mount_table.tests.cpp
index 4ae8711..f22b25e 100644
--- a/kernel/src/filesystem/mount_table.tests.cpp
+++ b/kernel/src/filesystem/mount_table.tests.cpp
@@ -58,14 +58,14 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem]
THEN("finding mounts by exact valid path returns the correct mount")
{
- REQUIRE(table.find_exact_mount("/") == mount1);
- REQUIRE(table.find_exact_mount("/mnt") == mount2);
+ REQUIRE(table.find_mount("/") == mount1);
+ REQUIRE(table.find_mount("/mnt") == mount2);
}
THEN("finding mounts by exact invalid path returns null")
{
- REQUIRE(table.find_exact_mount("/nonexistent") == nullptr);
- REQUIRE(table.find_exact_mount("/mnt/file") == nullptr);
+ REQUIRE(table.find_mount("/nonexistent") == nullptr);
+ REQUIRE(table.find_mount("/mnt/file") == nullptr);
}
THEN("removing a mount that has no child mounts succeeds")
@@ -103,7 +103,7 @@ SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem]
THEN("finding mounts by exact valid path returns the correct mount")
{
- REQUIRE(table.find_exact_mount("/") == mount2);
+ REQUIRE(table.find_mount("/") == mount2);
}
THEN("removing the topmost mount with the same path succeeds")
diff --git a/kernel/src/filesystem/open_file_descriptor.cpp b/kernel/src/filesystem/open_file_descriptor.cpp
index 25bffbd..ebaabef 100644
--- a/kernel/src/filesystem/open_file_descriptor.cpp
+++ b/kernel/src/filesystem/open_file_descriptor.cpp
@@ -1,6 +1,7 @@
-#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/open_file_descriptor.hpp>
+#include <kernel/filesystem/dentry.hpp>
+
#include <kstd/memory>
#include <kstd/os/error.hpp>
@@ -8,33 +9,38 @@
namespace kernel::filesystem
{
- open_file_descriptor::open_file_descriptor(kstd::shared_ptr<inode> const & inode)
- : m_inode(inode)
+ open_file_descriptor::open_file_descriptor(kstd::shared_ptr<dentry> const & dentry)
+ : m_dentry(dentry)
, m_offset(0)
{
- if (!inode)
+ if (!dentry)
{
- kstd::os::panic("[FILESYSTEM] open_file_descriptor constructed with null inode.");
+ kstd::os::panic("[FILESYSTEM] open_file_descriptor constructed with null dentry.");
}
}
auto open_file_descriptor::read(void * buffer, size_t size) -> size_t
{
- auto read_bytes = m_inode->read(buffer, m_offset, size);
+ auto read_bytes = m_dentry->get_inode()->read(buffer, m_offset, size);
m_offset += read_bytes;
return read_bytes;
}
auto open_file_descriptor::write(void const * buffer, size_t size) -> size_t
{
- auto written_bytes = m_inode->write(buffer, m_offset, size);
+ auto written_bytes = m_dentry->get_inode()->write(buffer, m_offset, size);
m_offset += written_bytes;
return written_bytes;
}
- auto open_file_descriptor::offset() const -> size_t
+ auto open_file_descriptor::get_offset() const -> size_t
{
return m_offset;
}
+ auto open_file_descriptor::get_dentry() const -> kstd::shared_ptr<dentry> const &
+ {
+ return m_dentry;
+ }
+
} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/open_file_descriptor.tests.cpp b/kernel/src/filesystem/open_file_descriptor.tests.cpp
index 53835ba..1910b8b 100644
--- a/kernel/src/filesystem/open_file_descriptor.tests.cpp
+++ b/kernel/src/filesystem/open_file_descriptor.tests.cpp
@@ -1,5 +1,7 @@
#include <kernel/filesystem/open_file_descriptor.hpp>
+#include <kernel/filesystem/dentry.hpp>
+#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/vfs.hpp>
#include <kernel/test_support/filesystem/inode.hpp>
#include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp>
@@ -16,51 +18,53 @@
SCENARIO("Open file descriptor construction", "[filesystem][open_file_descriptor]")
{
- GIVEN("an inode and an open file descriptor for that inode")
+ GIVEN("a dentry and an open file descriptor for that dentry")
{
auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto file_descriptor = kernel::filesystem::open_file_descriptor{inode};
+ auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
+ auto file_descriptor = kernel::filesystem::open_file_descriptor{dentry};
THEN("the initial offset is zero")
{
- REQUIRE(file_descriptor.offset() == 0);
+ REQUIRE(file_descriptor.get_offset() == 0);
}
}
}
SCENARIO("Open file descriptor read/write offset management", "[filesystem][open_file_descriptor]")
{
- GIVEN("an inode that tracks read/write calls and an open file descriptor for that inode")
+ GIVEN("a dentry that tracks read/write calls and an open file descriptor for that dentry")
{
auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto file_descriptor = kernel::filesystem::open_file_descriptor{inode};
+ auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
+ auto file_descriptor = kernel::filesystem::open_file_descriptor{dentry};
THEN("the offset is updated correctly after reads")
{
REQUIRE(file_descriptor.read(nullptr, 100) == 100);
- REQUIRE(file_descriptor.offset() == 100);
+ REQUIRE(file_descriptor.get_offset() == 100);
REQUIRE(file_descriptor.read(nullptr, 50) == 50);
- REQUIRE(file_descriptor.offset() == 150);
+ REQUIRE(file_descriptor.get_offset() == 150);
}
THEN("the offset is updated correctly after writes")
{
REQUIRE(file_descriptor.write(nullptr, 200) == 200);
- REQUIRE(file_descriptor.offset() == 200);
+ REQUIRE(file_descriptor.get_offset() == 200);
REQUIRE(file_descriptor.write(nullptr, 25) == 25);
- REQUIRE(file_descriptor.offset() == 225);
+ REQUIRE(file_descriptor.get_offset() == 225);
}
THEN("reads and writes both update the same offset")
{
REQUIRE(file_descriptor.read(nullptr, 10) == 10);
- REQUIRE(file_descriptor.offset() == 10);
+ REQUIRE(file_descriptor.get_offset() == 10);
REQUIRE(file_descriptor.write(nullptr, 20) == 20);
- REQUIRE(file_descriptor.offset() == 30);
+ REQUIRE(file_descriptor.get_offset() == 30);
REQUIRE(file_descriptor.read(nullptr, 5) == 5);
- REQUIRE(file_descriptor.offset() == 35);
+ REQUIRE(file_descriptor.get_offset() == 35);
REQUIRE(file_descriptor.write(nullptr, 15) == 15);
- REQUIRE(file_descriptor.offset() == 50);
+ REQUIRE(file_descriptor.get_offset() == 50);
}
}
}
@@ -78,14 +82,14 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope
auto & vfs = kernel::filesystem::vfs::get();
auto dentry = vfs.open("/information/info_1.txt");
REQUIRE(dentry != nullptr);
- auto ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry->get_inode());
+ auto ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
THEN("the file can be read and the offset is updated")
{
kstd::vector<std::byte> buffer(32);
auto bytes_read = ofd->read(buffer.data(), buffer.size());
REQUIRE(bytes_read == 7);
- REQUIRE(ofd->offset() == 7);
+ REQUIRE(ofd->get_offset() == 7);
std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)};
REQUIRE(buffer_as_str == "info_1\n");
@@ -96,11 +100,11 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope
kstd::vector<std::byte> buffer(4);
auto bytes_read_1 = ofd->read(buffer.data(), buffer.size() / 2);
REQUIRE(bytes_read_1 == buffer.size() / 2);
- REQUIRE(ofd->offset() == buffer.size() / 2);
+ REQUIRE(ofd->get_offset() == buffer.size() / 2);
auto bytes_read_2 = ofd->read(buffer.data() + buffer.size() / 2, buffer.size() / 2);
REQUIRE(bytes_read_2 == buffer.size() / 2);
- REQUIRE(ofd->offset() == buffer.size());
+ REQUIRE(ofd->get_offset() == buffer.size());
std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read_1 + bytes_read_2};
REQUIRE(buffer_as_str == "info");
diff --git a/kernel/src/filesystem/open_file_table.tests.cpp b/kernel/src/filesystem/open_file_table.tests.cpp
index a5c791d..456d6b7 100644
--- a/kernel/src/filesystem/open_file_table.tests.cpp
+++ b/kernel/src/filesystem/open_file_table.tests.cpp
@@ -1,5 +1,6 @@
#include <kernel/filesystem/open_file_table.hpp>
+#include <kernel/filesystem/dentry.hpp>
#include <kernel/filesystem/open_file_descriptor.hpp>
#include <kernel/test_support/filesystem/inode.hpp>
@@ -15,8 +16,10 @@ SCENARIO("Open file table add/get file", "[filesystem][open_file_table]")
{
auto & table = kernel::filesystem::open_file_table::get();
auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto file_descriptor_1 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(inode);
- auto file_descriptor_2 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(inode);
+ auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
+
+ auto file_descriptor_1 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
+ auto file_descriptor_2 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
WHEN("adding the open file descriptor to the open file table")
{
@@ -69,7 +72,8 @@ SCENARIO("Open file table remove file", "[filesystem][open_file_table]")
{
auto & table = kernel::filesystem::open_file_table::get();
auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(inode);
+ auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
+ auto file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
auto fd = table.add_file(file_descriptor);
WHEN("removing the file descriptor using the file descriptor")
diff --git a/kernel/src/filesystem/rootfs/filesystem.cpp b/kernel/src/filesystem/rootfs/filesystem.cpp
index 6187c3c..d49e237 100644
--- a/kernel/src/filesystem/rootfs/filesystem.cpp
+++ b/kernel/src/filesystem/rootfs/filesystem.cpp
@@ -11,18 +11,13 @@ namespace kernel::filesystem::rootfs
{
auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result
{
- auto rfs_inode = kstd::make_shared<inode>();
- rfs_inode->add_child("dev");
- m_root_inode = rfs_inode;
-
+ m_root_inode = kstd::make_shared<inode>();
return operation_result::success;
}
- auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name)
+ auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const &, std::string_view)
-> kstd::shared_ptr<kernel::filesystem::inode>
{
- if (auto * rfs_inode = static_cast<inode *>(parent.get()))
- return rfs_inode->lookup_child(name);
return nullptr;
}
} // namespace kernel::filesystem::rootfs
diff --git a/kernel/src/filesystem/rootfs/filesystem.tests.cpp b/kernel/src/filesystem/rootfs/filesystem.tests.cpp
index 81ac9e4..ae320e9 100644
--- a/kernel/src/filesystem/rootfs/filesystem.tests.cpp
+++ b/kernel/src/filesystem/rootfs/filesystem.tests.cpp
@@ -21,13 +21,6 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem]
REQUIRE(fs.root_inode() != nullptr);
}
- THEN("looking up the 'dev' directory returns a valid inode")
- {
- auto dev_inode = fs.lookup(fs.root_inode(), "dev");
- REQUIRE(dev_inode != nullptr);
- REQUIRE(dev_inode->is_directory());
- }
-
THEN("looking up a non-existent directory returns null")
{
auto non_existent_inode_1 = fs.lookup(fs.root_inode(), "");
diff --git a/kernel/src/filesystem/rootfs/inode.cpp b/kernel/src/filesystem/rootfs/inode.cpp
index d099676..dbe7948 100644
--- a/kernel/src/filesystem/rootfs/inode.cpp
+++ b/kernel/src/filesystem/rootfs/inode.cpp
@@ -5,10 +5,7 @@
#include <kstd/memory>
#include <kstd/string>
-#include <algorithm>
#include <cstddef>
-#include <string_view>
-#include <utility>
namespace kernel::filesystem::rootfs
{
@@ -22,17 +19,6 @@ namespace kernel::filesystem::rootfs
return 0;
}
- auto inode::add_child(std::string_view name) -> void
- {
- m_children.push_back(std::make_pair(kstd::string{name}, kstd::make_shared<inode>()));
- }
-
- auto inode::lookup_child(std::string_view name) -> kstd::shared_ptr<inode>
- {
- auto it = std::ranges::find_if(m_children, [&](auto const & pair) { return pair.first == name; });
- return (it != m_children.end()) ? it->second : nullptr;
- }
-
auto inode::is_directory() const -> bool
{
return true;
diff --git a/kernel/src/filesystem/rootfs/inode.tests.cpp b/kernel/src/filesystem/rootfs/inode.tests.cpp
index 7cc217f..f4b634f 100644
--- a/kernel/src/filesystem/rootfs/inode.tests.cpp
+++ b/kernel/src/filesystem/rootfs/inode.tests.cpp
@@ -6,53 +6,6 @@
#include <catch2/catch_test_macros.hpp>
-SCENARIO("Rootfs inode creation", "[filesystem][rootfs][inode]")
-{
- GIVEN("a rootfs inode")
- {
- auto inode = kernel::filesystem::rootfs::inode{};
-
- THEN("the inode has the correct kind")
- {
- REQUIRE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
-
- THEN("the inode has no children")
- {
- REQUIRE(inode.lookup_child("child") == nullptr);
- }
- }
-}
-
-SCENARIO("Rootfs inode child management", "[filesystem][rootfs][inode]")
-{
- GIVEN("a rootfs inode")
- {
- auto inode = kernel::filesystem::rootfs::inode{};
-
- WHEN("adding a child inode")
- {
- inode.add_child("child");
- inode.add_child("another child");
-
- THEN("the child can be looked up by name")
- {
- auto child_inode = inode.lookup_child("child");
- REQUIRE(child_inode != nullptr);
- REQUIRE(child_inode->is_directory());
- }
-
- THEN("looking up a non-existent child returns null")
- {
- REQUIRE(inode.lookup_child("nonexistent") == nullptr);
- }
- }
- }
-}
-
SCENARIO("Rootfs inode read/write", "[filesystem][rootfs][inode]")
{
GIVEN("a rootfs inode")
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp
index f5d57be..8636d0f 100644
--- a/kernel/src/filesystem/vfs.cpp
+++ b/kernel/src/filesystem/vfs.cpp
@@ -20,6 +20,7 @@
#include <optional>
#include <ranges>
#include <string_view>
+#include <utility>
namespace
{
@@ -46,20 +47,13 @@ namespace kernel::filesystem
root_fs->mount(nullptr);
auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/");
- m_mount_table.add_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);
+ m_mount_table.add_mount(root_mount);
// mount devfs at /dev (inside rootfs, temporary, will be shadowed)
auto device_fs = kstd::make_shared<devfs::filesystem>();
device_fs->mount(nullptr);
-
- if (auto dev_mount_point_dentry = resolve_path("/dev"))
- {
- do_mount_internal(dev_mount_point_dentry, device_fs);
- }
- else
- {
- kapi::system::panic("[FILESYSTEM] failed to resolve /dev for initial devfs mount.");
- }
+ graft_persistent_device_fs(device_fs);
// mount boot fs at / (shadows rootfs), re-graft devfs
if (auto boot_device_dentry = resolve_path("/dev/ram0"))
@@ -68,7 +62,7 @@ namespace kernel::filesystem
{
if (auto root_dentry = resolve_path("/"))
{
- do_mount_internal(root_dentry, boot_root_fs);
+ do_mount_internal(root_dentry, root_mount, boot_root_fs);
graft_persistent_device_fs(device_fs);
}
}
@@ -87,7 +81,26 @@ namespace kernel::filesystem
auto vfs::open(std::string_view path) -> kstd::shared_ptr<dentry>
{
- return resolve_path(path);
+ auto [dentry, mount] = resolve_path_internal(path);
+ if (!dentry || !mount)
+ {
+ return nullptr;
+ }
+ mount->increment_ref_count();
+ return dentry;
+ }
+
+ auto vfs::close(std::string_view path) -> operation_result
+ {
+ if (auto mount = find_mount(path))
+ {
+ if (mount->decrement_ref_count())
+ {
+ return operation_result::success;
+ }
+ return operation_result::close_failed;
+ }
+ return operation_result::invalid_path;
}
auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result
@@ -97,13 +110,15 @@ namespace kernel::filesystem
return operation_result::invalid_path;
}
- if (auto mount_point_dentry = resolve_path(target))
+ auto [mount_point_dentry, mount_context] = resolve_path_internal(target);
+
+ if (mount_point_dentry && mount_context)
{
if (auto source_dentry = resolve_path(source))
{
if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode()))
{
- do_mount_internal(mount_point_dentry, fs);
+ do_mount_internal(mount_point_dentry, mount_context, fs);
return operation_result::success;
}
return operation_result::invalid_filesystem;
@@ -125,25 +140,18 @@ namespace kernel::filesystem
{
return operation_result::success;
}
-
- if (remove_result == mount_table::operation_result::has_child_mounts)
+ else if (remove_result == mount_table::operation_result::mount_not_found)
{
- return operation_result::unmount_failed;
+ return operation_result::mount_point_not_found;
}
- return operation_result::mount_point_not_found;
+ return operation_result::unmount_failed;
}
auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry,
- kstd::shared_ptr<filesystem> const & fs) -> void
+ kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs)
+ -> void
{
- auto parent_mount_dentry = mount_point_dentry->find_mount_root_dentry();
- kstd::shared_ptr<mount> parent_mount = nullptr;
- if (parent_mount_dentry)
- {
- parent_mount = m_mount_table.find_exact_mount(parent_mount_dentry->get_absolute_path().view());
- }
-
auto new_fs_root =
kstd::make_shared<dentry>(mount_point_dentry->get_parent(), fs->root_inode(), mount_point_dentry->get_name());
auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, parent_mount);
@@ -152,27 +160,28 @@ namespace kernel::filesystem
auto vfs::graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void
{
- if (auto new_root_dentry = resolve_path("/"))
+ auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/");
+ if (root_mount_point_dentry && root_mount)
{
- auto dev_dentry = new_root_dentry->find_child("dev");
+ auto dev_dentry = root_mount_point_dentry->find_child("dev");
if (!dev_dentry)
{
- dev_dentry = kstd::make_shared<dentry>(new_root_dentry, device_fs->root_inode(), "dev");
- new_root_dentry->add_child(dev_dentry);
+ dev_dentry = kstd::make_shared<dentry>(root_mount_point_dentry, device_fs->root_inode(), "dev");
+ root_mount_point_dentry->add_child(dev_dentry);
}
- do_mount_internal(dev_dentry, device_fs);
+ do_mount_internal(dev_dentry, root_mount, device_fs);
}
}
- auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr<dentry>
+ auto vfs::resolve_path_internal(std::string_view path) -> std::pair<kstd::shared_ptr<dentry>, kstd::shared_ptr<mount>>
{
if (!path::is_valid_absolute_path(path))
{
- return nullptr;
+ return {nullptr, nullptr};
}
- auto current_mount = m_mount_table.find_exact_mount("/");
+ auto current_mount = m_mount_table.find_mount("/");
if (!current_mount)
{
kapi::system::panic("[FILESYSTEM] no root mount found.");
@@ -225,7 +234,7 @@ namespace kernel::filesystem
auto found_inode = current_fs->lookup(current_dentry->get_inode(), part.view());
if (!found_inode)
{
- return nullptr;
+ return {nullptr, nullptr};
}
next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part.view());
@@ -233,7 +242,7 @@ namespace kernel::filesystem
}
else if (next_dentry->has_flag(dentry::dentry_flags::is_mount_point))
{
- current_mount = m_mount_table.find_exact_mount(next_dentry->get_absolute_path().view());
+ current_mount = m_mount_table.find_mount(next_dentry->get_absolute_path().view());
if (!current_mount)
{
kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found.");
@@ -246,7 +255,7 @@ namespace kernel::filesystem
{
if (symlink_counter++ > constants::symloop_max)
{
- return nullptr;
+ return {nullptr, nullptr};
}
kstd::vector<uint8_t> buffer(constants::symlink_max_path_length);
@@ -261,7 +270,7 @@ namespace kernel::filesystem
if (path::is_valid_absolute_path(symbolic_link_path))
{
- current_mount = m_mount_table.find_exact_mount("/");
+ current_mount = m_mount_table.find_mount("/");
current_dentry = current_mount->get_root_dentry();
}
continue;
@@ -269,9 +278,19 @@ namespace kernel::filesystem
current_dentry = next_dentry;
}
+ return {current_dentry, current_mount};
+ }
- return current_dentry;
+ auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr<dentry>
+ {
+ return resolve_path_internal(path).first;
}
+
+ auto vfs::find_mount(std::string_view path) -> kstd::shared_ptr<mount>
+ {
+ return resolve_path_internal(path).second;
+ }
+
} // namespace kernel::filesystem
namespace kernel::tests::filesystem::vfs
diff --git a/kernel/src/filesystem/vfs.tests.cpp b/kernel/src/filesystem/vfs.tests.cpp
index 0f1d6d5..648ebb8 100644
--- a/kernel/src/filesystem/vfs.tests.cpp
+++ b/kernel/src/filesystem/vfs.tests.cpp
@@ -105,6 +105,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
REQUIRE(mounted_monkey_1 != nullptr);
+ REQUIRE(vfs.close(mounted_monkey_1->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
@@ -126,12 +128,47 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
REQUIRE(mounted_monkey_1 != nullptr);
REQUIRE(mounted_fish1 != nullptr);
+ REQUIRE(vfs.close(mounted_monkey_1->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_fish1->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") ==
kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
}
+ THEN("image can be mounted, unmount only if no files are open")
+ {
+ REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
+
+ auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
+ REQUIRE(mounted_monkey_1 != nullptr);
+
+ REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
+
+ REQUIRE(vfs.close(mounted_monkey_1->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
+
+ REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
+ }
+
+ 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);
+ }
+
+ THEN("file cannot be closed twice")
+ {
+ auto info_1 = vfs.open("/information/info_1.txt");
+ REQUIRE(info_1 != nullptr);
+
+ REQUIRE(vfs.close(info_1->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(info_1->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::close_failed);
+ }
+
THEN("images can be stacked mounted and correct file system is unmounted again")
{
REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
@@ -140,6 +177,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto mounted_tickets = vfs.open("/information/entrance/tickets.txt");
REQUIRE(mounted_tickets != nullptr);
+ REQUIRE(vfs.close(mounted_tickets->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
mounted_tickets = vfs.open("/information/entrance/tickets.txt");
REQUIRE(mounted_tickets == nullptr);
@@ -161,6 +201,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto water = vfs.open("/monkey_house/infrastructure/water.txt");
REQUIRE(water != nullptr);
+ REQUIRE(vfs.close(water->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
info_1 = vfs.open("/information/info_1.txt");
@@ -180,6 +222,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto water = vfs.open("/monkey_house/infrastructure/water.txt");
REQUIRE(water != nullptr);
+ REQUIRE(vfs.close(water->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+
auto dev_ram_16 = vfs.open("/dev/ram16");
REQUIRE(dev_ram_16 == nullptr);
@@ -196,6 +240,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto info_1 = vfs.open("/information/info_1.txt");
REQUIRE(info_1 != nullptr);
+ REQUIRE(vfs.close(info_1->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/dev") == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
@@ -310,13 +356,15 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto dentry = vfs.open("/information/sheep_1.txt");
REQUIRE(dentry != nullptr);
- auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry->get_inode());
+ auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
kstd::vector<std::byte> buffer(7);
auto bytes_read = sheep_1_ofd->read(buffer.data(), buffer.size());
std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read};
REQUIRE(buffer_as_str == "sheep_1");
+ REQUIRE(vfs.close(dentry->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
REQUIRE(unmounted_sheep_1 == nullptr);
@@ -335,8 +383,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
REQUIRE(sheep_1 != nullptr);
REQUIRE(goat_1 != nullptr);
- auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(sheep_1->get_inode());
- auto goat_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(goat_1->get_inode());
+ auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(sheep_1);
+ auto goat_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(goat_1);
kstd::vector<std::byte> sheep_buffer(7);
auto bytes_read = sheep_1_ofd->read(sheep_buffer.data(), sheep_buffer.size());
@@ -348,6 +396,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
buffer_as_str = std::string_view{reinterpret_cast<char *>(goat_buffer.data()), bytes_read};
REQUIRE(buffer_as_str == "goat_1");
+ REQUIRE(vfs.close(sheep_1->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(goat_1->get_absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
REQUIRE(vfs.unmount("/information/stable") == kernel::filesystem::vfs::operation_result::success);
@@ -357,6 +408,9 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto still_mounted_sheep_1 = vfs.open("/information/sheep_1.txt");
REQUIRE(still_mounted_sheep_1 != nullptr);
+ REQUIRE(vfs.close(still_mounted_sheep_1->get_absolute_path().view()) ==
+ kernel::filesystem::vfs::operation_result::success);
+
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
REQUIRE(unmounted_sheep_1 == nullptr);