diff options
24 files changed, 348 insertions, 439 deletions
diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index f621c3f1..e6ae3425 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -76,9 +76,9 @@ SECTIONS . = ALIGN(8); /* Filesystem driver factories */ - PROVIDE(__start_fs_types = .); - KEEP(*(fs_types)); - PROVIDE(__stop_fs_types = .); + PROVIDE(__start_filesystem_drivers = .); + KEEP(*(filesystem_drivers)); + PROVIDE(__stop_filesystem_drivers = .); /* Kernel driver factories */ PROVIDE(__start_kernel_drivers = .); diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c7cf9498..2cca2dda 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -60,14 +60,13 @@ target_sources("kernel_lib" PRIVATE "kernel/filesystem/dentry.cpp" "kernel/filesystem/device_inode.cpp" "kernel/filesystem/device_number_registry.cpp" + "kernel/filesystem/driver_registry.cpp" "kernel/filesystem/error.cpp" - "kernel/filesystem/filesystem.cpp" "kernel/filesystem/inode.cpp" "kernel/filesystem/mount_table.cpp" "kernel/filesystem/mount.cpp" "kernel/filesystem/open_file_descriptor.cpp" "kernel/filesystem/open_file_table.cpp" - "kernel/filesystem/type_registry.cpp" "kernel/filesystem/vfs.cpp" # DevFS Filesystem diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 0e3f3164..a7c8e50c 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -3,10 +3,10 @@ #include <kernel/filesystem/devfs/inode.hpp> #include <kernel/filesystem/device_inode.hpp> #include <kernel/filesystem/device_number_registry.hpp> +#include <kernel/filesystem/driver_registry.hpp> #include <kernel/filesystem/error.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kernel/filesystem/type.hpp> #include <kapi/filesystem.hpp> @@ -21,23 +21,13 @@ namespace kernel::filesystem::devfs { - struct type final : kernel::filesystem::type + struct descriptor final : kernel::filesystem::driver_descriptor { [[nodiscard]] auto name() const noexcept -> std::string_view override { return "devfs"; } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result<std::uint32_t> override - { - if (backing_inode) - { - return kstd::failure(vfs_errc::invalid_argument); - } - return 0; - } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared<filesystem>(); @@ -45,10 +35,20 @@ namespace kernel::filesystem::devfs }; [[gnu::used]] - constexpr auto registration = type_registration<type>{}; + constexpr auto registration = driver_module<descriptor>{}; static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(devfs::filesystem)); + auto filesystem::probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> + { + if (inode) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + return 0; + } + auto filesystem::mount(inode_ptr const &) -> kstd::result<mount_result> { auto root = kstd::make_shared<inode>(); diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index 56744477..aa33c58b 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -3,6 +3,7 @@ #include <kernel/filesystem/device_inode.hpp> #include <kernel/filesystem/device_number_registry.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> @@ -13,6 +14,7 @@ #include <kstd/string.hpp> #include <kstd/system_error.hpp> +#include <cstdint> #include <optional> #include <string_view> @@ -25,8 +27,10 @@ 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 final : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> override; + auto mount(inode_ptr const & backing_inode) -> kstd::result<mount_result> override; [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const diff --git a/kernel/kernel/filesystem/driver_registry.cpp b/kernel/kernel/filesystem/driver_registry.cpp new file mode 100644 index 00000000..22bc306d --- /dev/null +++ b/kernel/kernel/filesystem/driver_registry.cpp @@ -0,0 +1,125 @@ +#include <kernel/filesystem/driver_registry.hpp> + +#include <kernel/filesystem/error.hpp> +#include <kernel/filesystem/filesystem.hpp> +#include <kernel/filesystem/inode.hpp> + +#include <kapi/system.hpp> + +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/result.hpp> +#include <kstd/vector.hpp> + +#include <algorithm> +#include <cstdint> +#include <functional> +#include <optional> +#include <ranges> +#include <span> +#include <string_view> +#include <utility> + +namespace kernel::filesystem +{ + + extern "C" + { + // We need to suppress clang-tidy linting warnings here, since these symbols are generated by the linker and we + // cannot choose their names, unless we wanted to extend the linker script needlessly. + // NOLINTBEGIN(readability-identifier-naming) + extern kstd::observer_ptr<driver_descriptor const> const __start_filesystem_drivers; + extern kstd::observer_ptr<driver_descriptor const> const __stop_filesystem_drivers; + // NOLINTEND(readability-identifier-naming) + } + + namespace + { + auto constinit instance = std::optional<driver_registry>{}; + } + + auto driver_registry::init() -> void + { + if (instance) + { + kapi::system::panic("[OS:FS] The filesystem driver registry was already initialized!"); + } + + instance.emplace(); + + auto instances = + std::span{&__start_filesystem_drivers, &__stop_filesystem_drivers} | + std::views::filter([](auto descriptor) { return descriptor != nullptr; }) | + std::views::transform([](auto descriptor) { return std::pair{descriptor, descriptor->make_instance()}; }) | + std::views::filter([](auto entry) { return entry.second != nullptr; }); + + std::ranges::for_each(instances, [](auto entry) { + auto [descriptor, driver] = entry; + kstd::println("[OS:FS] Registering filesystem driver '{}'", descriptor->name()); + instance->add(descriptor->name(), driver); + }); + } + + auto driver_registry::get() -> driver_registry & + { + if (!instance) + { + kapi::system::panic("[OS:FS] The filesystem driver registry has not been initialized!"); + } + + return *instance; + } + + auto driver_registry::find(std::string_view name) const -> std::optional<kstd::shared_ptr<filesystem>> + { + if (auto it = m_drivers.find(name); it != m_drivers.end()) + { + return it->second; + } + return std::nullopt; + } + + auto driver_registry::add(std::string_view name, kstd::shared_ptr<filesystem> descriptor) -> bool + { + auto result = m_drivers.emplace(name, descriptor); + return result.second; + } + + auto driver_registry::match(kstd::shared_ptr<inode> const & inode) const -> kstd::result<kstd::shared_ptr<filesystem>> + { + struct candidate + { + std::uint32_t priority; + kstd::shared_ptr<filesystem> driver; + }; + + auto candidates = kstd::vector<candidate>{}; + + for (auto const & entry : m_drivers) + { + auto const & [name, driver] = entry; + auto priority = driver->probe(inode); + if (priority) + { + candidates.push_back({*priority, driver}); + } + } + + std::ranges::stable_sort(candidates, std::ranges::greater{}, &candidate::priority); + + if (candidates.empty()) + { + return kstd::failure(vfs_errc::unsupported_filesystem); + } + + return candidates.front().driver; + } +} // namespace kernel::filesystem + +namespace kernel::tests::filesystem::driver_registry +{ + auto deinit() -> void + { + kernel::filesystem::instance.reset(); + } +} // namespace kernel::tests::filesystem::driver_registry
\ No newline at end of file diff --git a/kernel/kernel/filesystem/driver_registry.hpp b/kernel/kernel/filesystem/driver_registry.hpp new file mode 100644 index 00000000..1a6cd47e --- /dev/null +++ b/kernel/kernel/filesystem/driver_registry.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_KERNEL_DRIVER_REGISTRY_HPP +#define TEACHOS_KERNEL_DRIVER_REGISTRY_HPP + +#include <kernel/filesystem/filesystem.hpp> +#include <kernel/filesystem/inode.hpp> + +#include <kstd/flat_map.hpp> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> + +#include <concepts> +#include <optional> +#include <string_view> + +namespace kernel::filesystem +{ + + struct driver_descriptor + { + virtual ~driver_descriptor() = default; + + //! Get the name of the driver. + [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; + + //! Create a new instance of the driver represented by this descriptor. + [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr<filesystem> = 0; + }; + + template<std::derived_from<driver_descriptor> Type> + struct driver_module + { + constexpr auto static instance = Type{}; + [[using gnu: section("filesystem_drivers"), used, visibility("hidden")]] constexpr auto static pointer{ + kstd::make_observer<driver_descriptor const>(&instance), + }; + }; + + struct driver_registry + { + constexpr driver_registry() noexcept = default; + + auto static init() -> void; + + auto static get() -> driver_registry &; + + //! Register a new filesystem. + //! + //! @param name The name of the filesystem. + //! @param driver The filesystem driver to register. + //! @return @c true iff. the driver was successfully added, @c false if not. + auto add(std::string_view name, kstd::shared_ptr<filesystem> driver) -> bool; + + //! Find a registered filesystem driver + //! + //! @param name The name of the filesystem + [[nodiscard]] auto find(std::string_view name) const -> std::optional<kstd::shared_ptr<filesystem>>; + + //! Match all currently registered filesystem drivers against a given inode. + //! + //! @param inode The inode to match on, if any. + //! @return a match priority if th + [[nodiscard]] auto match(kstd::shared_ptr<inode> const & inode) const -> kstd::result<kstd::shared_ptr<filesystem>>; + + private: + //! A map from filesystem names to filesystem drivers. + kstd::flat_map<std::string_view, kstd::shared_ptr<filesystem>> m_drivers{}; + }; + +} // namespace kernel::filesystem + +#endif diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index ef81f6ac..579094e0 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -1,5 +1,6 @@ #include <kernel/filesystem/ext2/filesystem.hpp> +#include <kernel/filesystem/driver_registry.hpp> #include <kernel/filesystem/error.hpp> #include <kernel/filesystem/ext2/block_group_descriptor.hpp> #include <kernel/filesystem/ext2/error.hpp> @@ -9,7 +10,6 @@ #include <kernel/filesystem/ext2/superblock.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kernel/filesystem/type.hpp> #include <kapi/filesystem.hpp> #include <kapi/system.hpp> @@ -34,6 +34,25 @@ using namespace kstd::units_literals; namespace kernel::filesystem::ext2 { + + struct descriptor final : kernel::filesystem::driver_descriptor + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override + { + return kstd::make_shared<filesystem>(); + } + }; + + [[gnu::used]] + constexpr auto registration = driver_module<descriptor>{}; + + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); + namespace { [[nodiscard]] auto bitmap_is_set(kstd::vector<uint8_t> const & bitmap, size_t index) -> bool @@ -55,57 +74,38 @@ namespace kernel::filesystem::ext2 read_only_compatible_features::large_file_support; } // namespace - struct type final : kernel::filesystem::type + auto filesystem::indirect_levels(mount_state const & state) const -> std::array<indirect_level, 3> { - [[nodiscard]] auto name() const noexcept -> std::string_view override + return { + {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, + {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, + {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} + }; + } + + auto filesystem::probe(inode_ptr const & backing_inode) const -> kstd::result<std::uint32_t> + { + auto superblock = ext2::superblock{}; + auto bytes = std::as_writable_bytes(std::span{&superblock, 1}); + auto read_result = backing_inode->read(bytes, constants::superblock_offset); + + if (!read_result) { - return "ext2"; + return kstd::failure(read_result.error()); } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result<std::uint32_t> override + if (superblock.magic != constants::magic_number) { - auto superblock = ext2::superblock{}; - auto bytes = std::as_writable_bytes(std::span{&superblock, 1}); - auto read_result = backing_inode->read(bytes, constants::superblock_offset); - - if (!read_result) - { - return kstd::failure(read_result.error()); - } - - if (superblock.magic != constants::magic_number) - { - return kstd::failure(ext2_errc::invalid_magic_number); - } - - if (superblock.feature_incompat & std::to_underlying(~supported_incompatible_features) || - superblock.feature_ro_compat & std::to_underlying(~supported_ro_compatible_features)) - { - return kstd::failure(ext2_errc::unsupported_features_present); - } - - return 0; + return kstd::failure(ext2_errc::invalid_magic_number); } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override + if (superblock.feature_incompat & std::to_underlying(~supported_incompatible_features) || + superblock.feature_ro_compat & std::to_underlying(~supported_ro_compatible_features)) { - return kstd::make_shared<filesystem>(); + return kstd::failure(ext2_errc::unsupported_features_present); } - }; - - [[gnu::used]] - constexpr auto registration = type_registration<type>{}; - - static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(kernel::filesystem::ext2::filesystem)); - auto filesystem::indirect_levels(mount_state const & state) const -> std::array<indirect_level, 3> - { - return { - {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block(state)}, - {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block(state)}, - {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block(state)}} - }; + return 0; } auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result<mount_result> diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 9ee737a7..4b5604e5 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -76,6 +76,8 @@ namespace kernel::filesystem::ext2 //! The Second Extended Filesystem (ext2) struct filesystem final : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & backing_inode) const -> kstd::result<std::uint32_t> override; + auto mount(inode_ptr const & backing_inode) -> kstd::result<mount_result> override; [[nodiscard]] auto lookup(inode_ptr const & parent, std::string_view name, driver_data_ptr driver_data) const diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp deleted file mode 100644 index d2e3adde..00000000 --- a/kernel/kernel/filesystem/filesystem.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include <kernel/filesystem/filesystem.hpp> - -#include <kernel/filesystem/error.hpp> -#include <kernel/filesystem/inode.hpp> -#include <kernel/filesystem/type_registry.hpp> - -#include <kstd/memory.hpp> -#include <kstd/result.hpp> -#include <kstd/system_error.hpp> - -namespace kernel::filesystem -{ - - auto filesystem::probe(kstd::shared_ptr<inode> const & backing_inode) -> kstd::result<kstd::shared_ptr<filesystem>> - { - for (auto & type : type_registry::get().all()) - { - if (!type || !type->probe(backing_inode)) - { - continue; - } - - if (auto fs = type->make_instance()) - { - return fs; - } - } - - return kstd::failure(vfs_errc::unsupported_filesystem); - } - -} // namespace kernel::filesystem
\ No newline at end of file diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index 2e713c89..f9fb2859 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -10,6 +10,7 @@ #include <kstd/system_error.hpp> #include <kstd/vector.hpp> +#include <cstdint> #include <optional> #include <string_view> #include <utility> @@ -30,11 +31,11 @@ namespace kernel::filesystem //! Virtual destructor enabling polymorphic destruction. virtual ~filesystem() = default; - //! Probes the given inode to determine if it contains a recognizable filesystem. + //! Check if the data represented by the given inode is recognized as this filesystem. //! - //! @param backing_inode The inode to probe and mount, if any. - //! @return A pointer to the instantiated filesystem and the root of it on success, an error otherwise. - auto static probe(inode_ptr const & backing_inode) -> kstd::result<filesystem_ptr>; + //! @param inode The inode to probe, if any. + //! @return the priority (higher is better) of the match on success, an error otherwise. + [[nodiscard]] virtual auto probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> = 0; //! Initializes the filesystem with the given inode. //! diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index 994ebaca..a14addba 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -1,9 +1,9 @@ #include <kernel/filesystem/rootfs/filesystem.hpp> +#include <kernel/filesystem/driver_registry.hpp> #include <kernel/filesystem/error.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/rootfs/inode.hpp> -#include <kernel/filesystem/type.hpp> #include <kapi/filesystem.hpp> @@ -17,24 +17,13 @@ namespace kernel::filesystem::rootfs { - struct type final : kernel::filesystem::type + struct descriptor final : kernel::filesystem::driver_descriptor { [[nodiscard]] auto name() const noexcept -> std::string_view override { return "rootfs"; } - [[nodiscard]] auto probe(filesystem::inode_ptr const & backing_inode) const noexcept - -> kstd::result<std::uint32_t> override - { - if (backing_inode) - { - return kstd::failure(vfs_errc::invalid_argument); - } - - return 0; - } - [[nodiscard]] auto make_instance() const -> filesystem::filesystem_ptr override { return kstd::make_shared<filesystem>(); @@ -42,7 +31,19 @@ namespace kernel::filesystem::rootfs }; [[gnu::used]] - constexpr auto registration = type_registration<type>{}; + constexpr auto registration = driver_module<descriptor>{}; + + static_assert(sizeof(kernel::filesystem::filesystem) == sizeof(rootfs::filesystem)); + + auto filesystem::probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> + { + if (inode) + { + return kstd::failure(vfs_errc::invalid_argument); + } + + return 0; + } auto filesystem::mount(inode_ptr const &) -> kstd::result<mount_result> { diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index edef76d4..0195b250 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -12,6 +12,7 @@ #include <kstd/system_error.hpp> #include <kstd/vector.hpp> +#include <cstdint> #include <optional> #include <string_view> @@ -24,6 +25,8 @@ namespace kernel::filesystem::rootfs //! hierarchy. It is responsible for providing a stable and consistent interface to the root directory. struct filesystem : kernel::filesystem::filesystem { + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> override; + //! @copydoc kernel::filesystem::filesystem::mount auto mount(inode_ptr const & backing_inode) -> kstd::result<mount_result> override; diff --git a/kernel/kernel/filesystem/type.hpp b/kernel/kernel/filesystem/type.hpp deleted file mode 100644 index c2f2595b..00000000 --- a/kernel/kernel/filesystem/type.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TEACHOS_KERNEL_FILESYSTEM_TYPE_HPP -#define TEACHOS_KERNEL_FILESYSTEM_TYPE_HPP - -#include <kernel/filesystem/filesystem.hpp> -#include <kernel/filesystem/inode.hpp> - -#include <kstd/memory.hpp> -#include <kstd/result.hpp> - -#include <cstdint> -#include <string_view> - -namespace kernel::filesystem -{ - - //! A type descriptor for a filesystem driver. - //! - //! Each filesystem must expose an instance of a class derived from this type in order to be registered with the vfs - //! filesystem registry. - struct type - { - virtual ~type() = default; - - //! Get the name of the filesystem represented by this descriptor. - [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0; - - //! Check if the filesystem is applicable. - //! - //! @return the priority of this filesystem for the given inode. - [[nodiscard]] virtual auto probe(kstd::shared_ptr<inode> const & backing_inode) const noexcept - -> kstd::result<std::uint32_t> = 0; - - //! Create a new instance of the filesystem represented by this descriptor. - [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr<filesystem> = 0; - }; - - template<typename Type> - struct type_registration - { - constexpr auto static instance = Type{}; - [[using gnu: section("fs_types"), used, visibility("hidden")]] constexpr auto static pointer{ - kstd::make_observer<type const>(&instance), - }; - }; - -} // namespace kernel::filesystem - -#endif diff --git a/kernel/kernel/filesystem/type_registry.cpp b/kernel/kernel/filesystem/type_registry.cpp deleted file mode 100644 index 05fb116a..00000000 --- a/kernel/kernel/filesystem/type_registry.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include <kernel/filesystem/type_registry.hpp> - -#include <kapi/system.hpp> - -#include <kstd/memory.hpp> -#include <kstd/print.hpp> -#include <kstd/vector.hpp> - -#include <algorithm> -#include <cstddef> -#include <optional> -#include <ranges> -#include <span> - -namespace kernel::filesystem -{ - - extern "C" - { - // We need to suppress clang-tidy linting warnings here, since these symbols are generated by the linker and we - // cannot choose their names, unless we wanted to extend the linker script needlessly. - // NOLINTBEGIN(readability-identifier-naming) - extern type_registry::pointer const __start_fs_types; - extern type_registry::pointer const __stop_fs_types; - // NOLINTEND(readability-identifier-naming) - } - - namespace - { - auto constinit instance = std::optional<type_registry>{}; - } - - auto type_registry::init() -> void - { - if (instance) - { - kapi::system::panic("[FILESYSTEM] tried to initialize type registry more than once!"); - } - - instance.emplace(); - - auto type_descriptors = std::span{&__start_fs_types, &__stop_fs_types} | // - std::views::filter([](auto p) { return p != nullptr; }); - - std::ranges::for_each(type_descriptors, [](auto descriptor) { - kstd::println("[FILESYSTEM] registering '{}'", descriptor->name()); - instance->add(descriptor); - }); - } - - auto type_registry::get() -> type_registry & - { - if (!instance) - { - kapi::system::panic("[FILESYSTEM] type registry has not been initialized!"); - } - - return *instance; - } - - auto type_registry::find(std::string_view name) const -> std::optional<pointer> - { - if (auto it = m_descriptors.find(name); it != m_descriptors.end()) - { - return it->second; - } - return std::nullopt; - } - - auto type_registry::add(pointer descriptor) -> bool - { - auto result = m_descriptors.emplace(descriptor->name(), descriptor); - return result.second; - } - - auto type_registry::all() const noexcept -> kstd::vector<pointer> - { - return m_descriptors.values(); - } - - auto type_registry::size() const noexcept -> std::size_t - { - return m_descriptors.size(); - } - -} // namespace kernel::filesystem - -namespace kernel::tests::filesystem::type_registry -{ - auto deinit() -> void - { - kernel::filesystem::instance.reset(); - } -} // namespace kernel::tests::filesystem::type_registry
\ No newline at end of file diff --git a/kernel/kernel/filesystem/type_registry.hpp b/kernel/kernel/filesystem/type_registry.hpp deleted file mode 100644 index 11669ab3..00000000 --- a/kernel/kernel/filesystem/type_registry.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef TEACHOS_KERNEL_TYPE_REGISTRY_HPP -#define TEACHOS_KERNEL_TYPE_REGISTRY_HPP - -#include <kernel/filesystem/type.hpp> - -#include <kstd/flat_map.hpp> -#include <kstd/memory.hpp> -#include <kstd/string.hpp> -#include <kstd/vector.hpp> - -#include <cstddef> -#include <optional> -#include <string_view> - -namespace kernel::filesystem -{ - - struct type_registry - { - using value_type = type; - using pointer = kstd::observer_ptr<value_type const>; - - auto static init() -> void; - auto static get() -> type_registry &; - - constexpr type_registry() noexcept = default; - - //! Add a type descriptor to this registry. - //! - //! This function will register the given descriptor with this registry, given that no descriptor for a filesystem - //! with the same name exists in this registry already. - //! - //! @param descriptor The filesystem type descriptor to add to the registry. - //! @return @p true iff. the descriptor was successfully added, @p false if not. - auto add(pointer descriptor) -> bool; - - //! Find a registered type descriptor by name - //! - //! @param name The name of the filesystem - [[nodiscard]] auto find(std::string_view name) const -> std::optional<pointer>; - - //! Get all currently registered type descriptors. - //! - //! @return A span containing all currently registered filesystem type descriptors. - [[nodiscard]] auto all() const noexcept -> kstd::vector<pointer>; - - //! Get the number of registered filesystem types. - //! - //! @return The number of filesystem descriptors currently registered with this registry. - [[nodiscard]] auto size() const noexcept -> std::size_t; - - private: - //! A map from filesystem names (identifiers) to filesystem type descriptors. - kstd::flat_map<std::string_view, pointer> m_descriptors{}; - }; - -} // namespace kernel::filesystem - -#endif diff --git a/kernel/kernel/filesystem/type_registry.tests.cpp b/kernel/kernel/filesystem/type_registry.tests.cpp deleted file mode 100644 index b38c16f8..00000000 --- a/kernel/kernel/filesystem/type_registry.tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <kernel/filesystem/type_registry.hpp> - -#include <kernel/filesystem/filesystem.hpp> -#include <kernel/filesystem/inode.hpp> -#include <kernel/filesystem/type.hpp> - -#include <kstd/memory.hpp> -#include <kstd/result.hpp> - -#include <catch2/catch_test_macros.hpp> - -#include <cstdint> -#include <iterator> -#include <string_view> - -struct test_type final : kernel::filesystem::type -{ - [[nodiscard]] auto name() const noexcept -> std::string_view override - { - return "bht_testfs"; - } - - [[nodiscard]] auto probe(kstd::shared_ptr<kernel::filesystem::inode> const &) const noexcept - -> kstd::result<std::uint32_t> override - { - return false; - } - - [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override - { - return nullptr; - } -}; - -SCENARIO("Filesystem type registry initialization and construction", "[filesystem]") -{ - GIVEN("A default constructed type_registry") - { - auto instance = kernel::filesystem::type_registry{}; - - WHEN("getting the span of filesystem descriptors") - { - auto descriptors = instance.all(); - - THEN("the span is empty") - { - REQUIRE(descriptors.empty()); - } - } - } -} - -SCENARIO("Filesystem type registry modifiers", "[filesystem]") -{ - GIVEN("A default constructed type_registry") - { - auto instance = kernel::filesystem::type_registry{}; - - WHEN("adding a type descriptor") - { - auto descriptor = test_type{}; - - instance.add(kstd::make_observer(&descriptor)); - - THEN("the size of the registry is one") - { - REQUIRE(instance.size() == 1); - } - - THEN("the span is not empty") - { - REQUIRE_FALSE(instance.all().empty()); - } - - THEN("the span's size is equal to the registry size") - { - REQUIRE(std::size(instance.all()) == std::size(instance)); - } - } - } -} diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 43da7130..d8bcb6b6 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -4,6 +4,7 @@ #include <kernel/filesystem/dentry.hpp> #include <kernel/filesystem/device_inode.hpp> #include <kernel/filesystem/device_number_registry.hpp> +#include <kernel/filesystem/driver_registry.hpp> #include <kernel/filesystem/error.hpp> #include <kernel/filesystem/file_type.hpp> #include <kernel/filesystem/filesystem.hpp> @@ -11,12 +12,12 @@ #include <kernel/filesystem/mount.hpp> #include <kernel/filesystem/mount_table.hpp> #include <kernel/filesystem/path.hpp> -#include <kernel/filesystem/type_registry.hpp> #include <kapi/filesystem.hpp> #include <kapi/system.hpp> #include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <kstd/result.hpp> #include <kstd/system_error.hpp> #include <kstd/units.hpp> @@ -53,14 +54,13 @@ namespace kernel::filesystem vfs::vfs() { // mount rootfs at / - auto root_fs_descriptor = type_registry::get().find("rootfs"); - if (!root_fs_descriptor) + auto rootfs = driver_registry::get().find("rootfs"); + if (!rootfs) { kapi::system::panic("[OS:FS] rootfs driver is missing!"); } - auto root_fs = (*root_fs_descriptor)->make_instance(); - auto root_mount_result = root_fs->mount(nullptr); + auto root_mount_result = (*rootfs)->mount(nullptr); if (!root_mount_result) { kapi::system::panic("[FILESYSTEM] failed to mount root FS", root_mount_result.error()); @@ -68,45 +68,53 @@ namespace kernel::filesystem auto [root_inode, root_state] = *root_mount_result; - auto root_mount = mount::attach(nullptr, root_fs, root_inode, root_state, nullptr, nullptr); + auto root_mount = mount::attach(nullptr, *rootfs, root_inode, root_state, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) - auto device_fs_descriptor = type_registry::get().find("devfs"); - if (!device_fs_descriptor) + auto devfs = driver_registry::get().find("devfs"); + if (!devfs) { kapi::system::panic("[OS:FS] devfs driver is missing!"); } - auto device_fs = (*device_fs_descriptor)->make_instance(); - auto device_fs_mount_result = device_fs->mount(nullptr); + auto device_fs_mount_result = (*devfs)->mount(nullptr); if (!device_fs_mount_result) { kapi::system::panic("[FILESYSTEM] failed to mount device FS", device_fs_mount_result.error()); } auto [device_fs_root, device_fs_data] = *device_fs_mount_result; - graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); + graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data); // mount boot fs at / (shadows rootfs), re-graft devfs auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { - if (auto result = kernel::filesystem::filesystem::probe(boot_device_dentry->inode())) + auto driver = driver_registry::get().match(boot_device_dentry->inode()); + if (!driver) { - if (auto root_dentry = resolve_path("/")) - { - auto mount = - mount::create(*root_dentry, *result, root_mount, boot_device_mount_context, boot_device_dentry->inode()); - if (!mount) - { - kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); - } - m_mount_table.add_mount(*mount); - graft_persistent_device_fs(device_fs, device_fs_root, device_fs_data); - } + kstd::println(kstd::print_sink::stderr, "[OS:FS] Missing driver for root disk!"); + return; + } + + auto root_dentry = resolve_path("/"); + if (!root_dentry) + { + kapi::system::panic("[OS:FS] No root directory found!"); + } + + auto mount = + mount::create(*root_dentry, *driver, root_mount, boot_device_mount_context, boot_device_dentry->inode()); + + if (!mount) + { + kapi::system::panic("[OS:FS] failed to mount boot FS", mount.error()); } + m_mount_table.add_mount(*mount); + + graft_persistent_device_fs(*devfs, device_fs_root, device_fs_data); } } @@ -188,13 +196,14 @@ namespace kernel::filesystem } auto [source_dentry, source_mount_context] = *resolved_source; - auto fs = kernel::filesystem::filesystem::probe(source_dentry->inode()); - if (!fs) + auto driver = driver_registry::get().match(source_dentry->inode()); + if (!driver) { - return kstd::failure(fs.error()); + return kstd::failure(driver.error()); } - auto mount = mount::create(mount_point_dentry, *fs, mount_context, source_mount_context, source_dentry->inode()); + auto mount = + mount::create(mount_point_dentry, *driver, mount_context, source_mount_context, source_dentry->inode()); if (!mount) { return kstd::failure(mount.error()); diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp index db47f167..f8322b31 100644 --- a/kernel/kernel/main.cpp +++ b/kernel/kernel/main.cpp @@ -1,4 +1,4 @@ -#include "kernel/filesystem/type_registry.hpp" +#include "kernel/filesystem/driver_registry.hpp" #include <kernel/devices/init.hpp> #include <kernel/devices/storage.hpp> #include <kernel/drivers/init.hpp> @@ -248,7 +248,7 @@ auto main() -> int kernel::filesystem::open_file_table::init(); kstd::println("[OS] Global open file table initialized."); - kernel::filesystem::type_registry::init(); + kernel::filesystem::driver_registry::init(); kstd::println("[OS] Builtin filesystems registered."); kernel::filesystem::vfs::init(); diff --git a/kernel/kernel/test_support/filesystem/driver_registry.hpp b/kernel/kernel/test_support/filesystem/driver_registry.hpp new file mode 100644 index 00000000..b91acd57 --- /dev/null +++ b/kernel/kernel/test_support/filesystem/driver_registry.hpp @@ -0,0 +1,10 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_DRIVER_REGISTRY_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_DRIVER_REGISTRY_HPP + +namespace kernel::tests::filesystem::driver_registry +{ + //! Deinitialize the FS type registry singleton. + auto deinit() -> void; +} // namespace kernel::tests::filesystem::driver_registry + +#endif
\ No newline at end of file diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 105746e8..0d4610ab 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -9,12 +9,18 @@ #include <kstd/result.hpp> #include <kstd/system_error.hpp> +#include <cstdint> #include <optional> #include <string_view> #include <utility> namespace kernel::tests::filesystem { + auto filesystem::probe(inode_ptr const &) const -> kstd::result<std::uint32_t> + { + return 0; + } + auto filesystem::mount(inode_ptr const &) -> kstd::result<mount_result> { return std::pair{kstd::make_shared<inode>(), nullptr}; diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index 52111a5a..3df2cccb 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -10,6 +10,7 @@ #include <kstd/result.hpp> #include <kstd/system_error.hpp> +#include <cstdint> #include <optional> #include <string_view> @@ -19,6 +20,8 @@ namespace kernel::tests::filesystem { filesystem() = default; + [[nodiscard]] auto probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t> override; + auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<mount_result> override; diff --git a/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp b/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp index 3df23751..b9228c69 100644 --- a/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp +++ b/kernel/kernel/test_support/filesystem/storage_boot_module_fixture.cpp @@ -2,8 +2,6 @@ #include <kernel/bus/boot_modules.hpp> #include <kernel/devices/storage.hpp> -#include <kernel/filesystem/type.hpp> -#include <kernel/filesystem/type_registry.hpp> #include <kapi/boot_modules.hpp> #include <kapi/boot_modules/device.hpp> diff --git a/kernel/kernel/test_support/filesystem/type_registry.hpp b/kernel/kernel/test_support/filesystem/type_registry.hpp deleted file mode 100644 index 8d5b6029..00000000 --- a/kernel/kernel/test_support/filesystem/type_registry.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_TYPE_REGISTRY_HPP -#define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_TYPE_REGISTRY_HPP - -namespace kernel::tests::filesystem::type_registry -{ - //! Deinitialize the FS type registry singleton. - auto deinit() -> void; -} // namespace kernel::tests::filesystem::type_registry - -#endif
\ No newline at end of file diff --git a/kernel/kernel/test_support/state_reset_listener.cpp b/kernel/kernel/test_support/state_reset_listener.cpp index e900b31c..948f2f7e 100644 --- a/kernel/kernel/test_support/state_reset_listener.cpp +++ b/kernel/kernel/test_support/state_reset_listener.cpp @@ -1,13 +1,13 @@ #include <kernel/devices/storage.hpp> #include <kernel/drivers/init.hpp> +#include <kernel/filesystem/driver_registry.hpp> #include <kernel/filesystem/open_file_table.hpp> -#include <kernel/filesystem/type_registry.hpp> #include <kernel/filesystem/vfs.hpp> #include <kernel/test_support/cio.hpp> #include <kernel/test_support/cpu.hpp> #include <kernel/test_support/filesystem/device_number_registry.hpp> +#include <kernel/test_support/filesystem/driver_registry.hpp> #include <kernel/test_support/filesystem/open_file_table.hpp> -#include <kernel/test_support/filesystem/type_registry.hpp> #include <kernel/test_support/filesystem/vfs.hpp> #include <kernel/test_support/memory.hpp> @@ -42,15 +42,14 @@ struct state_reset_listener : Catch::EventListenerBase std::ignore = kernel::devices::storage::init(); kernel::filesystem::open_file_table::init(); - kernel::filesystem::type_registry::init(); + kernel::filesystem::driver_registry::init(); } void testCaseEnded(Catch::TestCaseStats const &) override { - kernel::tests::filesystem::type_registry::deinit(); + kernel::tests::filesystem::driver_registry::deinit(); kernel::tests::filesystem::device_number_registry::deinit(); kernel::tests::filesystem::vfs::deinit(); - kernel::tests::filesystem::type_registry::deinit(); kernel::tests::filesystem::open_file_table::deinit(); kapi::test_support::devices::deinit(); |
