aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-25 13:52:43 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-25 13:52:43 +0200
commit948453d3d073de207274535376d7274e82f04bc6 (patch)
tree6cb36b1f4e6902693a2a14b22b178e351a9a5cfb
parentdb92fcd2a865889dbf5cc524f2c27e5855167e9c (diff)
downloadkernel-948453d3d073de207274535376d7274e82f04bc6.tar.xz
kernel-948453d3d073de207274535376d7274e82f04bc6.zip
kernel: subscribe devfs to the number registry
-rw-r--r--kernel/kapi/filesystem.tests.cpp9
-rw-r--r--kernel/kernel/filesystem/devfs/filesystem.cpp34
-rw-r--r--kernel/kernel/filesystem/devfs/filesystem.hpp12
-rw-r--r--kernel/kernel/filesystem/devfs/filesystem.tests.cpp35
4 files changed, 57 insertions, 33 deletions
diff --git a/kernel/kapi/filesystem.tests.cpp b/kernel/kapi/filesystem.tests.cpp
index 1cd2c610..80fc7d3f 100644
--- a/kernel/kapi/filesystem.tests.cpp
+++ b/kernel/kapi/filesystem.tests.cpp
@@ -276,10 +276,17 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap
REQUIRE(kapi::filesystem::umount("/information"));
}
}
+}
+
+// NOTE: This must be it's own scenario, because it relies on concrete minor numbers, which in turn depend on global
+// singleton state that only resets on a new scenario.
+SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture,
+ "Kapi filesystem resolves a persistent device node to the matching devfs entry", "[kapi][filesystem]")
+{
+ auto image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_devnode_fs.img";
GIVEN("A real image file containing a device node")
{
- auto image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_devnode_fs.img";
REQUIRE(std::filesystem::exists(image_path));
REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_devnode"}, {image_path}));
diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp
index b97884e6..c8447a2d 100644
--- a/kernel/kernel/filesystem/devfs/filesystem.cpp
+++ b/kernel/kernel/filesystem/devfs/filesystem.cpp
@@ -11,12 +11,12 @@
#include <kapi/filesystem.hpp>
-#include <kstd/flat_map.hpp>
#include <kstd/memory.hpp>
#include <kstd/result.hpp>
-#include <kstd/string.hpp>
#include <kstd/system_error.hpp>
+#include <kstd/vector.hpp>
+#include <algorithm>
#include <optional>
#include <string_view>
@@ -46,7 +46,15 @@ namespace kernel::filesystem::devfs
auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> kstd::result<void>
{
m_root_inode = kstd::make_shared<inode>();
- build_device_inode_table();
+
+ std::ranges::for_each(device_number_registry::get().all(), [&](auto const & numbered) {
+ if (auto device = numbered.device.lock())
+ {
+ m_inodes.emplace_back(numbered.name, kstd::make_shared<device_inode>(device));
+ }
+ });
+
+ device_number_registry::get().subscribe(shared_from_this());
return kstd::success();
}
@@ -69,7 +77,7 @@ namespace kernel::filesystem::devfs
return kstd::failure(vfs_errc::invalid_inode);
}
- auto found = m_inodes.find(kstd::string{name});
+ auto found = std::ranges::find_if(m_inodes, [&](auto const & entry) { return entry.first == name; });
if (found != m_inodes.end())
{
return found->second;
@@ -85,17 +93,17 @@ namespace kernel::filesystem::devfs
return kstd::failure(vfs_errc::read_only_file_system);
}
- auto filesystem::build_device_inode_table() -> void
+ auto filesystem::on_device_numbered(device_number_registry::entry const & numbered) -> void
{
- // TODO: implement clear on flat_map
- m_inodes = kstd::flat_map<kstd::string, kstd::shared_ptr<device_inode>>{};
-
- for (auto const & entry : device_number_registry::get().all())
+ if (auto device = numbered.device.lock())
{
- if (auto device = entry.device.lock())
- {
- m_inodes.emplace(entry.name, kstd::make_shared<device_inode>(device));
- }
+ m_inodes.emplace_back(numbered.name, kstd::make_shared<device_inode>(device));
}
}
+
+ auto filesystem::on_device_unnumbered(device_number_registry::entry const & numbered) -> void
+ {
+ erase_if(m_inodes, [&](auto const & entry) { return entry.first == numbered.name; });
+ }
+
} // namespace kernel::filesystem::devfs \ No newline at end of file
diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp
index abc4975a..8d2199e3 100644
--- a/kernel/kernel/filesystem/devfs/filesystem.hpp
+++ b/kernel/kernel/filesystem/devfs/filesystem.hpp
@@ -2,6 +2,7 @@
#define TEACH_OS_KERNEL_FILESYSTEM_DEVFS_FILESYSTEM_HPP
#include <kernel/filesystem/device_inode.hpp>
+#include <kernel/filesystem/device_number_registry.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/vfs_types.hpp>
@@ -17,6 +18,7 @@
#include <optional>
#include <string_view>
+#include <utility>
namespace kernel::filesystem::devfs
{
@@ -27,7 +29,9 @@ namespace kernel::filesystem::devfs
//! applications to interact with devices using standard file operations. The devfs filesystem dynamically creates
//! inodes for devices registered in the system, enabling seamless access to device functionality through the
//! filesystem interface.
- struct filesystem : kernel::filesystem::filesystem
+ struct filesystem : kernel::filesystem::filesystem,
+ kstd::enable_shared_from_this<filesystem>,
+ device_number_registry_observer
{
//! @copydoc kernel::filesystem::filesystem::mount
auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<void> override;
@@ -44,9 +48,11 @@ namespace kernel::filesystem::devfs
-> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> override;
private:
- auto build_device_inode_table() -> void;
+ auto on_device_numbered(device_number_registry::entry const & numbered) -> void override;
+ auto on_device_unnumbered(device_number_registry::entry const & numbered) -> void override;
- kstd::flat_map<kstd::string, kstd::shared_ptr<device_inode>> m_inodes{};
+ // TODO: change to flat_map again once flat_map supports erase.
+ kstd::vector<std::pair<kstd::string, kstd::shared_ptr<device_inode>>> m_inodes{};
};
} // namespace kernel::filesystem::devfs
diff --git a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp
index 93805440..29a33231 100644
--- a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp
+++ b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp
@@ -4,6 +4,8 @@
#include <kernel/filesystem/vfs_types.hpp>
#include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp>
+#include <kstd/memory.hpp>
+
#include <catch2/catch_test_macros.hpp>
SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
@@ -13,50 +15,51 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
{
setup_modules(1);
- auto fs = kernel::filesystem::devfs::filesystem{};
- auto result = fs.mount(nullptr);
+ auto fs = kstd::make_shared<kernel::filesystem::devfs::filesystem>();
+ auto result = fs->mount(nullptr);
THEN("mount succeeds")
{
REQUIRE(result);
- REQUIRE(fs.root_inode());
+ REQUIRE(fs->root_inode());
}
THEN("lookup on root finds ram0 device inode")
{
- auto inode = fs.lookup(fs.root_inode(), "ram0");
+ auto inode = fs->lookup(fs->root_inode(), "ram0");
REQUIRE(inode);
REQUIRE(inode.value()->is_device());
}
THEN("lookup of an unknown device returns error")
{
- auto inode = fs.lookup(fs.root_inode(), "ram99");
+ auto inode = fs->lookup(fs->root_inode(), "ram99");
REQUIRE(!inode);
}
THEN("lookup with wrong parent returns error")
{
- auto other_fs = kernel::filesystem::devfs::filesystem{};
- CHECK(other_fs.mount(nullptr));
+ auto other_fs = kstd::make_shared<kernel::filesystem::devfs::filesystem>();
+ CHECK(other_fs->mount(nullptr));
- auto inode = fs.lookup(other_fs.root_inode(), "ram0");
+ auto inode = fs->lookup(other_fs->root_inode(), "ram0");
REQUIRE(!inode);
}
THEN("lookup with a non-directory parent returns error")
{
- auto non_directory_inode = fs.lookup(fs.root_inode(), "ram0");
+ auto non_directory_inode = fs->lookup(fs->root_inode(), "ram0");
REQUIRE(non_directory_inode);
REQUIRE_FALSE(non_directory_inode.value()->is_directory());
- auto result = fs.lookup(*non_directory_inode, "anything");
+ auto result = fs->lookup(*non_directory_inode, "anything");
REQUIRE(!result);
}
THEN("create_inode always returns an error")
{
- auto result = fs.create_inode(fs.root_inode(), "new_device", kernel::filesystem::vfs_types::inode_type::regular);
+ auto result =
+ fs->create_inode(fs->root_inode(), "new_device", kernel::filesystem::vfs_types::inode_type::regular);
REQUIRE(!result);
}
}
@@ -65,15 +68,15 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
{
setup_modules(3, 2048);
- auto fs = kernel::filesystem::devfs::filesystem{};
- auto result = fs.mount(nullptr);
+ auto fs = kstd::make_shared<kernel::filesystem::devfs::filesystem>();
+ auto result = fs->mount(nullptr);
REQUIRE(result);
THEN("lookup finds all generated RAM devices")
{
- REQUIRE(fs.lookup(fs.root_inode(), "ram0"));
- REQUIRE(fs.lookup(fs.root_inode(), "ram1"));
- REQUIRE(fs.lookup(fs.root_inode(), "ram2"));
+ REQUIRE(fs->lookup(fs->root_inode(), "ram0"));
+ REQUIRE(fs->lookup(fs->root_inode(), "ram1"));
+ REQUIRE(fs->lookup(fs->root_inode(), "ram2"));
}
}
}