From 8054f6c6186e269946b346f016ebdcc3603f9adf Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 21 Nov 2024 15:45:48 +0200 Subject: [PATCH] Kernel: Wait 10 seconds to find root device If root device is initialized asynchronously it may not be ready when main initialization thread is finished. This patch adds searching for root device every 500 ms for 10 seconds. --- bootloader/bios/command_line.S | 4 +- kernel/kernel/FS/VirtualFileSystem.cpp | 139 +++++++++++++++++-------- 2 files changed, 97 insertions(+), 46 deletions(-) diff --git a/bootloader/bios/command_line.S b/bootloader/bios/command_line.S index 847db219..001c0e8f 100644 --- a/bootloader/bios/command_line.S +++ b/bootloader/bios/command_line.S @@ -83,5 +83,5 @@ command_line_enter_msg: command_line: # 100 character command line command_line_buffer: - .ascii "root=/dev/sda2" - .skip 100 - 28 + .ascii "root=UUID=9C87D2AF-566A-4517-971A-57BA86EEA88D" + .skip 100 - (. - command_line_buffer) diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index 55f20239..c7b40f49 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -14,55 +15,105 @@ namespace Kernel static BAN::RefPtr s_instance; + static BAN::ErrorOr> find_partition_by_uuid(BAN::StringView uuid) + { + ASSERT(uuid.size() == 36); + + BAN::RefPtr result; + DevFileSystem::get().for_each_inode( + [&result, uuid](BAN::RefPtr inode) -> BAN::Iteration + { + if (!inode->is_device()) + return BAN::Iteration::Continue; + if (!static_cast(inode.ptr())->is_partition()) + return BAN::Iteration::Continue; + auto* partition = static_cast(inode.ptr()); + if (partition->uuid() != uuid) + return BAN::Iteration::Continue; + result = partition; + return BAN::Iteration::Break; + } + ); + + if (!result) + return BAN::Error::from_errno(ENOENT); + return result; + } + + static BAN::ErrorOr> find_block_device_by_name(BAN::StringView name) + { + auto device_inode = TRY(DevFileSystem::get().root_inode()->find_inode(name)); + if (!device_inode->mode().ifblk()) + return BAN::Error::from_errno(ENOTBLK); + return BAN::RefPtr(static_cast(device_inode.ptr())); + } + + static BAN::RefPtr find_root_device(BAN::StringView root_path) + { + enum class RootType + { + PartitionUUID, + BlockDeviceName, + }; + + BAN::StringView entry; + RootType type; + + if (root_path.size() >= 5 && root_path.substring(0, 5) == "UUID="_sv) + { + entry = root_path.substring(5); + if (entry.size() != 36) + panic("Invalid UUID '{}'", entry); + type = RootType::PartitionUUID; + } + else if (root_path.size() >= 5 && root_path.substring(0, 5) == "/dev/"_sv) + { + entry = root_path.substring(5); + if (entry.empty() || entry.contains('/')) + panic("Invalid root path '{}'", root_path); + type = RootType::BlockDeviceName; + } + else + { + panic("Unsupported root path format '{}'", root_path); + } + + constexpr size_t timeout_ms = 10'000; + constexpr size_t sleep_ms = 500; + + for (size_t i = 0; i < timeout_ms / sleep_ms; i++) + { + BAN::ErrorOr> ret = BAN::Error::from_errno(EINVAL); + + switch (type) + { + case RootType::PartitionUUID: + ret = find_partition_by_uuid(entry); + break; + case RootType::BlockDeviceName: + ret = find_block_device_by_name(entry); + break; + } + + if (!ret.is_error()) + return ret.release_value(); + + if (ret.error().get_error_code() != ENOENT) + panic("could not open root device '{}': {}", root_path, ret.error()); + + SystemTimer::get().sleep_ms(sleep_ms); + } + + panic("could not find root device '{}' after {} ms", root_path, timeout_ms); + } + void VirtualFileSystem::initialize(BAN::StringView root_path) { ASSERT(!s_instance); s_instance = MUST(BAN::RefPtr::create()); - BAN::RefPtr root_device; - if (root_path.size() >= 5 && root_path.substring(0, 5) == "UUID="_sv) - { - auto uuid = root_path.substring(5); - if (uuid.size() != 36) - panic("Invalid UUID specified for root '{}'", uuid); - - BAN::RefPtr root_partition; - DevFileSystem::get().for_each_inode( - [&root_partition, uuid](BAN::RefPtr inode) -> BAN::Iteration - { - if (!inode->is_device()) - return BAN::Iteration::Continue; - if (!static_cast(inode.ptr())->is_partition()) - return BAN::Iteration::Continue; - auto* partition = static_cast(inode.ptr()); - if (partition->uuid() != uuid) - return BAN::Iteration::Continue; - root_partition = partition; - return BAN::Iteration::Break; - } - ); - if (!root_partition) - panic("Could not find partition with UUID '{}'", uuid); - root_device = root_partition; - } - else if (root_path.size() >= 5 && root_path.substring(0, 5) == "/dev/"_sv) - { - auto device_name = root_path.substring(5); - - auto device_result = DevFileSystem::get().root_inode()->find_inode(device_name); - if (device_result.is_error()) - panic("Could not open root device '{}': {}", root_path, device_result.error()); - - auto device_inode = device_result.release_value(); - if (!device_inode->mode().ifblk()) - panic("Root inode '{}' is not an block device", root_path); - - root_device = static_cast(device_inode.ptr()); - } - else - { - panic("Unknown root path format '{}' specified", root_path); - } + auto root_device = find_root_device(root_path); + ASSERT(root_device); auto filesystem_result = FileSystem::from_block_device(root_device); if (filesystem_result.is_error())