aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/include/kernel/filesystem/devfs/filesystem.hpp4
-rw-r--r--kernel/include/kernel/filesystem/ext2/filesystem.hpp4
-rw-r--r--kernel/include/kernel/filesystem/filesystem.hpp12
-rw-r--r--kernel/include/kernel/filesystem/mount.hpp10
-rw-r--r--kernel/include/kernel/filesystem/mount_table.hpp21
-rw-r--r--kernel/include/kernel/filesystem/rootfs/filesystem.hpp4
-rw-r--r--kernel/include/kernel/filesystem/vfs.hpp23
-rw-r--r--kernel/src/filesystem/devfs/filesystem.cpp5
-rw-r--r--kernel/src/filesystem/ext2/filesystem.cpp12
-rw-r--r--kernel/src/filesystem/filesystem.cpp6
-rw-r--r--kernel/src/filesystem/mount.cpp9
-rw-r--r--kernel/src/filesystem/mount_table.cpp69
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.cpp4
-rw-r--r--kernel/src/filesystem/vfs.cpp45
-rw-r--r--kernel/src/main.cpp3
15 files changed, 187 insertions, 44 deletions
diff --git a/kernel/include/kernel/filesystem/devfs/filesystem.hpp b/kernel/include/kernel/filesystem/devfs/filesystem.hpp
index 60c39cf..137eca3 100644
--- a/kernel/include/kernel/filesystem/devfs/filesystem.hpp
+++ b/kernel/include/kernel/filesystem/devfs/filesystem.hpp
@@ -24,9 +24,9 @@ namespace kernel::filesystem::devfs
/**
@brief Initializes the devfs instance and builds the device inode table.
@param device Backing device passed by the generic filesystem interface (not required by devfs).
- @return 0 on success, -1 on failure.
+ @return The result of the mount operation.
*/
- auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int override;
+ auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result override;
/**
@brief Looks up an inode by @p name within a @p parent directory.
diff --git a/kernel/include/kernel/filesystem/ext2/filesystem.hpp b/kernel/include/kernel/filesystem/ext2/filesystem.hpp
index 32374dc..65324c8 100644
--- a/kernel/include/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/include/kernel/filesystem/ext2/filesystem.hpp
@@ -27,9 +27,9 @@ namespace kernel::filesystem::ext2
/**
@brief Initializes the ext2 filesystem with the given @p device.
@param device The device to mount.
- @return 0 on success, negative error code on failure.
+ @return The result of the mount operation.
*/
- auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int override;
+ auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result override;
/**
@brief Looks up an inode by @p name within a @p parent directory.
diff --git a/kernel/include/kernel/filesystem/filesystem.hpp b/kernel/include/kernel/filesystem/filesystem.hpp
index f855380..ef6929a 100644
--- a/kernel/include/kernel/filesystem/filesystem.hpp
+++ b/kernel/include/kernel/filesystem/filesystem.hpp
@@ -18,6 +18,14 @@ namespace kernel::filesystem
*/
struct filesystem
{
+ enum class operation_result : int
+ {
+ success = 0,
+ invalid_magic_number = -1,
+ invalid_root_inode = -2,
+ unmount_failed = -3
+ };
+
/**
@brief Virtual destructor for the filesystem.
*/
@@ -37,9 +45,9 @@ namespace kernel::filesystem
/**
@brief Initializes the filesystem with the given @p device.
@param device The device to mount.
- @return 0 on success, or a negative error code on failure.
+ @return The result of the mount operation.
*/
- virtual auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int;
+ virtual auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result;
/**
@brief Looks up a child inode within the given @p parent inode with the specified @p name. This method must be
diff --git a/kernel/include/kernel/filesystem/mount.hpp b/kernel/include/kernel/filesystem/mount.hpp
index 3e3c69f..0ac6b2f 100644
--- a/kernel/include/kernel/filesystem/mount.hpp
+++ b/kernel/include/kernel/filesystem/mount.hpp
@@ -24,9 +24,11 @@ namespace kernel::filesystem
@param root_dentry The root dentry of the mounted filesystem.
@param fs The filesystem instance being mounted.
@param mount_path The path at which the filesystem is mounted.
+ @param parent_mount The parent mount that this mount is attached beneath.
*/
mount(kstd::shared_ptr<dentry> const & mount_dentry, kstd::shared_ptr<dentry> const & root_dentry,
- kstd::shared_ptr<filesystem> const & fs, std::string_view mount_path);
+ kstd::shared_ptr<filesystem> const & fs, std::string_view mount_path,
+ kstd::shared_ptr<mount> const & parent_mount);
/**
@brief Get the dentry where the filesystem is mounted.
@@ -48,11 +50,17 @@ namespace kernel::filesystem
*/
[[nodiscard]] auto get_mount_path() const -> std::string_view;
+ /**
+ @brief Get the parent mount that this mount was attached beneath.
+ */
+ [[nodiscard]] auto get_parent_mount() const -> kstd::shared_ptr<mount> const &;
+
private:
kstd::string m_mount_path;
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{};
};
} // namespace kernel::filesystem
diff --git a/kernel/include/kernel/filesystem/mount_table.hpp b/kernel/include/kernel/filesystem/mount_table.hpp
index a8ef59e..a5cdde6 100644
--- a/kernel/include/kernel/filesystem/mount_table.hpp
+++ b/kernel/include/kernel/filesystem/mount_table.hpp
@@ -16,10 +16,27 @@ namespace kernel::filesystem
struct mount_table
{
/**
+ @brief Results for mount table operations.
+ */
+ enum class operation_result : int
+ {
+ removed = 0,
+ has_child_mounts = -1,
+ mount_not_found = -2
+ };
+
+ /**
@brief Adds a mount to the table.
@param mount The mount to add.
*/
- void add_mount(kstd::shared_ptr<mount> const & mount);
+ auto add_mount(kstd::shared_ptr<mount> const & mount) -> void;
+
+ /**
+ @brief Removes 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;
/**
@brief Finds the mount with the longest prefix matching the given @p path. This method is used to determine which
@@ -30,6 +47,8 @@ namespace kernel::filesystem
[[nodiscard]] auto find_longest_prefix_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;
+
kstd::vector<kstd::shared_ptr<mount>> m_mounts;
};
} // namespace kernel::filesystem
diff --git a/kernel/include/kernel/filesystem/rootfs/filesystem.hpp b/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
index b7e7c6f..0155c41 100644
--- a/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
+++ b/kernel/include/kernel/filesystem/rootfs/filesystem.hpp
@@ -25,9 +25,9 @@ namespace kernel::filesystem::rootfs
/**
@brief Initializes the rootfs filesystem with the given @p device.
@param device The device to mount (not required by rootfs).
- @return 0 on success, negative error code on failure.
+ @return The result of the mount operation.
*/
- auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int override;
+ auto mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result override;
/**
@brief Looks up an inode by @p name within a @p parent directory.
diff --git a/kernel/include/kernel/filesystem/vfs.hpp b/kernel/include/kernel/filesystem/vfs.hpp
index 2d05765..4dd2a83 100644
--- a/kernel/include/kernel/filesystem/vfs.hpp
+++ b/kernel/include/kernel/filesystem/vfs.hpp
@@ -21,6 +21,18 @@ namespace kernel::filesystem
struct vfs
{
/**
+ @brief Results for VFS operations.
+ */
+ enum class operation_result : int
+ {
+ success = 0,
+ invalid_path = -1,
+ mount_point_not_found = -2,
+ filesystem_null = -3,
+ unmount_failed = -4
+ };
+
+ /**
@brief Initialize the virtual filesystem.
@warning Panics if the VFS has already been initialized.
*/
@@ -49,9 +61,16 @@ namespace kernel::filesystem
@brief Mount a @p filesystem at a specific @p path.
@param path The path where the filesystem should be mounted.
@param filesystem The filesystem to mount.
- @return 0 on success, or a negative error code on failure.
+ @return The result of the mount operation.
+ */
+ auto do_mount(std::string_view path, kstd::shared_ptr<filesystem> const & filesystem) -> operation_result;
+
+ /**
+ @brief Unmount the filesystem mounted at the specified @p path.
+ @param path The path where the filesystem is mounted.
+ @return The result of the unmount operation.
*/
- auto do_mount(std::string_view path, kstd::shared_ptr<filesystem> const & filesystem) -> int;
+ auto unmount(std::string_view path) -> operation_result;
private:
vfs() = default;
diff --git a/kernel/src/filesystem/devfs/filesystem.cpp b/kernel/src/filesystem/devfs/filesystem.cpp
index 9043ac5..03b4218 100644
--- a/kernel/src/filesystem/devfs/filesystem.cpp
+++ b/kernel/src/filesystem/devfs/filesystem.cpp
@@ -1,6 +1,7 @@
#include "kernel/filesystem/devfs/filesystem.hpp"
#include "kapi/devices/device.hpp"
+
#include "kernel/devices/storage/management.hpp"
#include "kernel/filesystem/devfs/inode.hpp"
#include "kernel/filesystem/device_inode.hpp"
@@ -13,12 +14,12 @@
namespace kernel::filesystem::devfs
{
- auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const &) -> int
+ auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const &) -> operation_result
{
m_root_inode = kstd::make_shared<inode>();
build_device_inode_table();
- return 0;
+ return operation_result::success;
}
auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name)
diff --git a/kernel/src/filesystem/ext2/filesystem.cpp b/kernel/src/filesystem/ext2/filesystem.cpp
index 7ee1072..6d5960e 100644
--- a/kernel/src/filesystem/ext2/filesystem.cpp
+++ b/kernel/src/filesystem/ext2/filesystem.cpp
@@ -36,10 +36,6 @@ namespace kernel::filesystem::ext2
constexpr uint16_t S_IFREG = 0x8000;
constexpr uint16_t S_IFDIR = 0x4000;
- // Error codes
- constexpr int INVALID_MAGIC_NUMBER = -1;
- constexpr int INVALID_ROOT_INODE = -2;
-
auto S_ISREG(uint16_t mode) -> bool
{
return (mode & S_IFMT) == S_IFREG;
@@ -51,7 +47,7 @@ namespace kernel::filesystem::ext2
}
} // namespace
- auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int
+ auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result
{
kernel::filesystem::filesystem::mount(device);
@@ -59,7 +55,7 @@ namespace kernel::filesystem::ext2
if (m_superblock.magic != MAGIC_NUMBER)
{
- return INVALID_MAGIC_NUMBER;
+ return operation_result::invalid_magic_number;
}
auto const block_size = get_block_size();
@@ -77,9 +73,9 @@ namespace kernel::filesystem::ext2
if (!m_root_inode || !m_root_inode->is_directory())
{
- return INVALID_ROOT_INODE;
+ return operation_result::invalid_root_inode;
}
- return 0;
+ return operation_result::success;
}
auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name)
diff --git a/kernel/src/filesystem/filesystem.cpp b/kernel/src/filesystem/filesystem.cpp
index b08b520..da2838d 100644
--- a/kernel/src/filesystem/filesystem.cpp
+++ b/kernel/src/filesystem/filesystem.cpp
@@ -30,7 +30,7 @@ namespace kernel::filesystem
for (auto & factory : filesystem_factories)
{
auto fs = factory();
- if (fs->mount(device) == 0)
+ if (fs->mount(device) == operation_result::success)
{
return fs;
}
@@ -39,11 +39,11 @@ namespace kernel::filesystem
return nullptr;
}
- auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const & device) -> int
+ auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const & device) -> operation_result
{
// TODO BA-FS26 maybe check if device is null and panic here already?
m_device = device;
- return 0;
+ return operation_result::success;
}
auto filesystem::root_inode() const -> kstd::shared_ptr<inode> const &
diff --git a/kernel/src/filesystem/mount.cpp b/kernel/src/filesystem/mount.cpp
index a6d2f7e..d165385 100644
--- a/kernel/src/filesystem/mount.cpp
+++ b/kernel/src/filesystem/mount.cpp
@@ -13,11 +13,13 @@
namespace kernel::filesystem
{
mount::mount(kstd::shared_ptr<dentry> const & mount_dentry, kstd::shared_ptr<dentry> const & root_dentry,
- kstd::shared_ptr<filesystem> const & fs, std::string_view mount_path)
+ kstd::shared_ptr<filesystem> const & fs, std::string_view mount_path,
+ kstd::shared_ptr<mount> const & parent_mount)
: m_mount_path(mount_path)
, m_mount_dentry(mount_dentry)
, m_root_dentry(root_dentry)
, m_filesystem(fs)
+ , m_parent_mount(parent_mount)
{
if (!m_filesystem)
{
@@ -44,4 +46,9 @@ namespace kernel::filesystem
{
return m_mount_path.view();
}
+
+ auto mount::get_parent_mount() const -> kstd::shared_ptr<mount> const &
+ {
+ return m_parent_mount;
+ }
} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount_table.cpp b/kernel/src/filesystem/mount_table.cpp
index 195f48a..3b1dee3 100644
--- a/kernel/src/filesystem/mount_table.cpp
+++ b/kernel/src/filesystem/mount_table.cpp
@@ -1,17 +1,83 @@
#include "kernel/filesystem/mount_table.hpp"
+#include "kernel/filesystem/dentry.hpp"
#include "kernel/filesystem/mount.hpp"
#include <kstd/memory>
+#include <kstd/vector>
+#include <algorithm>
#include <cstddef>
+#include <ranges>
#include <string_view>
namespace kernel::filesystem
{
+ namespace
+ {
+ auto is_descendant_of(kstd::shared_ptr<mount> const & candidate, kstd::shared_ptr<mount> const & ancestor) -> bool
+ {
+ for (auto current = candidate; current; current = current->get_parent_mount())
+ {
+ if (current == ancestor)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ auto is_strict_prefix(std::string_view prefix, std::string_view path) -> bool
+ {
+ return prefix != "/" && path.starts_with(prefix) && path.size() > prefix.size() && path[prefix.size()] == '/';
+ }
+
+ auto is_visible_mount(kstd::shared_ptr<mount> const & candidate,
+ kstd::vector<kstd::shared_ptr<mount>> const & mounts) -> bool
+ {
+ return std::ranges::none_of(mounts, [&](auto const & other) {
+ return other != candidate && is_strict_prefix(other->get_mount_path(), candidate->get_mount_path()) &&
+ !is_descendant_of(candidate, other);
+ });
+ }
+ } // namespace
+
+ auto mount_table::has_child_mounts(kstd::shared_ptr<mount> const & parent_mount) const -> bool
+ {
+ return std::ranges::any_of(
+ m_mounts, [&parent_mount](auto const & mount) { return mount->get_parent_mount() == parent_mount; });
+ }
+
void mount_table::add_mount(kstd::shared_ptr<mount> const & mount)
{
m_mounts.push_back(mount);
+ if (auto mount_dentry = mount->get_mount_dentry())
+ {
+ mount_dentry->set_flag(dentry::dentry_flags::dcache_mounted);
+ }
+ }
+
+ auto mount_table::remove_mount(std::string_view path) -> operation_result
+ {
+ auto mount_it = std::ranges::find_if(std::ranges::reverse_view(m_mounts), [&](auto const & mount) {
+ return mount->get_mount_path() == path && is_visible_mount(mount, m_mounts);
+ });
+
+ if (mount_it == std::ranges::reverse_view(m_mounts).end())
+ {
+ return operation_result::mount_not_found;
+ }
+
+ auto const & mount = *mount_it;
+ if (has_child_mounts(mount))
+ {
+ return operation_result::has_child_mounts;
+ }
+
+ mount->get_mount_dentry()->unset_flag(dentry::dentry_flags::dcache_mounted);
+ m_mounts.erase(std::ranges::find(m_mounts, mount));
+ return operation_result::removed;
}
auto mount_table::find_longest_prefix_mount(std::string_view path) const -> kstd::shared_ptr<mount>
@@ -25,8 +91,9 @@ namespace kernel::filesystem
// /a/b/c should match /a/b but not /a/bb or /a/b/c/d, / should match everything
bool is_prefix = path.starts_with(mp) && (mp == "/" || path.size() == mp.size() || path[mp.size()] == '/');
+ bool visible = is_visible_mount(mount, m_mounts);
- if (is_prefix && mp.size() >= best_len)
+ if (is_prefix && visible && mp.size() >= best_len)
{
mount_with_longest_prefix = mount;
best_len = mp.size();
diff --git a/kernel/src/filesystem/rootfs/filesystem.cpp b/kernel/src/filesystem/rootfs/filesystem.cpp
index a7c746e..dffef99 100644
--- a/kernel/src/filesystem/rootfs/filesystem.cpp
+++ b/kernel/src/filesystem/rootfs/filesystem.cpp
@@ -11,13 +11,13 @@
namespace kernel::filesystem::rootfs
{
- auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const &) -> int
+ auto filesystem::mount(kstd::shared_ptr<kapi::devices::device> const &) -> operation_result
{
auto rfs_inode = kstd::make_shared<inode>();
rfs_inode->add_child("dev");
m_root_inode = rfs_inode;
- return 0;
+ return operation_result::success;
}
auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name)
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp
index 2578036..45ae053 100644
--- a/kernel/src/filesystem/vfs.cpp
+++ b/kernel/src/filesystem/vfs.cpp
@@ -7,6 +7,7 @@
#include "kernel/filesystem/devfs/filesystem.hpp"
#include "kernel/filesystem/filesystem.hpp"
#include "kernel/filesystem/mount.hpp"
+#include "kernel/filesystem/mount_table.hpp"
#include "kernel/filesystem/open_file_description.hpp"
#include "kernel/filesystem/rootfs/filesystem.hpp"
@@ -21,11 +22,6 @@ namespace kernel::filesystem
namespace
{
constinit auto static active_vfs = std::optional<vfs>{};
-
- // Error codes
- constexpr int INVALID_PATH = -1;
- constexpr int MOUNT_POINT_NOT_FOUND = -2;
- constexpr int FILESYSTEM_NULL = -3;
} // namespace
auto vfs::init() -> void
@@ -45,7 +41,7 @@ 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, ""));
+ m_mount_table.add_mount(kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, "", nullptr));
auto storage_mgmt = devices::storage::management::get();
if (auto boot_device = storage_mgmt.determine_boot_device())
@@ -79,36 +75,55 @@ namespace kernel::filesystem
return nullptr;
}
- // TODO BA-FS26 implement unmount
- auto vfs::do_mount(std::string_view path, kstd::shared_ptr<filesystem> const & filesystem) -> int
+ auto vfs::do_mount(std::string_view path, kstd::shared_ptr<filesystem> const & filesystem) -> operation_result
{
if (!filesystem)
{
- return FILESYSTEM_NULL;
+ return operation_result::filesystem_null;
}
if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/'))
{
- return INVALID_PATH;
+ return operation_result::invalid_path;
}
if (auto mount_point_dentry = resolve_path(path))
{
do_mount_internal(path, mount_point_dentry, filesystem);
- return 0;
+ return operation_result::success;
+ }
+
+ return operation_result::mount_point_not_found;
+ }
+
+ auto vfs::unmount(std::string_view path) -> operation_result
+ {
+ if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/'))
+ {
+ return operation_result::invalid_path;
+ }
+
+ auto remove_result = m_mount_table.remove_mount(path);
+ if (remove_result == mount_table::operation_result::removed)
+ {
+ return operation_result::success;
+ }
+
+ if (remove_result == mount_table::operation_result::has_child_mounts)
+ {
+ return operation_result::unmount_failed;
}
- return MOUNT_POINT_NOT_FOUND;
+ return operation_result::mount_point_not_found;
}
auto vfs::do_mount_internal(std::string_view path, kstd::shared_ptr<dentry> const & mount_point_dentry,
kstd::shared_ptr<filesystem> const & fs) -> void
{
- // TODO BA-FS26 check if mount point is already mounted and handle it (unmount old fs, fail, etc.)
+ auto parent_mount = m_mount_table.find_longest_prefix_mount(path);
auto new_fs_root = kstd::make_shared<dentry>(mount_point_dentry, fs->root_inode());
- auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, path);
+ auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, path, parent_mount);
m_mount_table.add_mount(new_mount);
- mount_point_dentry->set_flag(dentry::dentry_flags::dcache_mounted);
}
auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr<dentry>
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
index 1893b84..1d73e20 100644
--- a/kernel/src/main.cpp
+++ b/kernel/src/main.cpp
@@ -145,6 +145,9 @@ auto test_file_lookup() -> void
vfs.do_mount("/enclosures/aquarium", new_filesystem);
read_and_write_file("/enclosures/aquarium/closed.txt");
read_and_write_file("/enclosures/aquarium/information/info_2.txt");
+
+ vfs.unmount("/enclosures/aquarium");
+ read_and_write_file("/enclosures/aquarium/tank_1/fish_4.txt");
}
auto run_test_code() -> void