Kernel: Change internal handling of filesystem-specific options

Instead of using a raw `KBuffer` and letting each implementation to
populating the specific flags on its own, we change things so we only
let each FileSystem implementation to validate the flag and its value
but then store it in a HashMap which its key is the flag name and
the value is a special new class called `FileSystemSpecificOption`
which wraps around `AK::Variant<...>`.

This approach has multiple advantages over the previous:
- It allows runtime inspection of what the user has set on a `MountFile`
  description for a specific filesystem.
- It ensures accidental overriding of filesystem specific option that
  was already set is not possible
- It removes ugly casting of a `KBuffer` contents to a strongly-typed
  values. Instead, a strongly-typed `AK::Variant` is used which ensures
  we always get a value without doing any casting.

Please note that we have removed support for ASCII string-oriented flags
as there were no actual use cases, and supporting such type would make
`FileSystemSpecificOption` more complicated unnecessarily for now.
This commit is contained in:
Liav A.
2024-07-14 14:07:23 +03:00
committed by Tim Schumacher
parent f439f02083
commit cb10f70394
29 changed files with 307 additions and 121 deletions

View File

@@ -84,37 +84,37 @@ SpinlockProtected<VFSRootContext::List, LockRank::FileSystem>& VFSRootContext::a
return s_details->root_contexts;
}
static ErrorOr<void> handle_mount_boolean_flag_as_invalid(Span<u8>, StringView, bool)
static ErrorOr<void> validate_mount_boolean_flag_as_invalid(StringView, bool)
{
return EINVAL;
}
static ErrorOr<void> handle_mount_unsigned_integer_flag_as_invalid(Span<u8>, StringView, u64)
static ErrorOr<void> validate_mount_unsigned_integer_flag_as_invalid(StringView, u64)
{
return EINVAL;
}
static ErrorOr<void> handle_mount_signed_integer_flag_as_invalid(Span<u8>, StringView, i64)
static ErrorOr<void> validate_mount_signed_integer_flag_as_invalid(StringView, i64)
{
return EINVAL;
}
static ErrorOr<void> handle_mount_ascii_string_flag_as_invalid(Span<u8>, StringView, StringView)
static ErrorOr<void> validate_mount_ascii_string_flag_as_invalid(StringView, StringView)
{
return EINVAL;
}
static constexpr FileSystemInitializer s_initializers[] = {
{ "proc"sv, "ProcFS"sv, false, false, false, {}, ProcFS::try_create, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "devpts"sv, "DevPtsFS"sv, false, false, false, {}, DevPtsFS::try_create, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "sys"sv, "SysFS"sv, false, false, false, {}, SysFS::try_create, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "ram"sv, "RAMFS"sv, false, false, false, {}, RAMFS::try_create, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {}, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {}, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {}, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {}, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "devloop"sv, "DevLoopFS"sv, false, false, false, {}, DevLoopFS::try_create, handle_mount_boolean_flag_as_invalid, handle_mount_unsigned_integer_flag_as_invalid, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "fuse"sv, "FUSE"sv, false, false, false, {}, FUSE::try_create, handle_mount_boolean_flag_as_invalid, FUSE::handle_mount_unsigned_integer_flag, handle_mount_signed_integer_flag_as_invalid, handle_mount_ascii_string_flag_as_invalid },
{ "proc"sv, "ProcFS"sv, false, false, false, {}, ProcFS::try_create, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "devpts"sv, "DevPtsFS"sv, false, false, false, {}, DevPtsFS::try_create, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "sys"sv, "SysFS"sv, false, false, false, {}, SysFS::try_create, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "ram"sv, "RAMFS"sv, false, false, false, {}, RAMFS::try_create, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {}, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {}, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {}, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {}, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "devloop"sv, "DevLoopFS"sv, false, false, false, {}, DevLoopFS::try_create, validate_mount_boolean_flag_as_invalid, validate_mount_unsigned_integer_flag_as_invalid, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
{ "fuse"sv, "FUSE"sv, false, false, false, {}, FUSE::try_create, validate_mount_boolean_flag_as_invalid, FUSE::validate_mount_unsigned_integer_flag, validate_mount_signed_integer_flag_as_invalid, validate_mount_ascii_string_flag_as_invalid },
};
ErrorOr<FileSystemInitializer const*> VirtualFileSystem::find_filesystem_type_initializer(StringView fs_type)
@@ -163,8 +163,8 @@ ErrorOr<NonnullRefPtr<FileSystem>> create_and_initialize_filesystem_from_mount_f
if (!file_system_initializer.create)
return ENOTSUP;
RefPtr<FileSystem> fs;
TRY(mount_file.mount_file_system_specific_data().with_exclusive([&](auto& mount_specific_data) -> ErrorOr<void> {
fs = TRY(file_system_initializer.create(mount_specific_data->bytes()));
TRY(mount_file.filesystem_specific_options().with_exclusive([&](auto const& filesystem_specific_options) -> ErrorOr<void> {
fs = TRY(file_system_initializer.create(filesystem_specific_options));
return {};
}));
VERIFY(fs);
@@ -207,8 +207,8 @@ ErrorOr<NonnullRefPtr<FileSystem>> create_and_initialize_filesystem_from_mount_f
}
}
if (!fs) {
TRY(mount_file.mount_file_system_specific_data().with_exclusive([&](auto& mount_specific_data) -> ErrorOr<void> {
fs = TRY(file_system_initializer.create_with_fd(source_description, mount_specific_data->bytes()));
TRY(mount_file.filesystem_specific_options().with_exclusive([&](auto const& filesystem_specific_options) -> ErrorOr<void> {
fs = TRY(file_system_initializer.create_with_fd(source_description, filesystem_specific_options));
return {};
}));
TRY(fs->initialize());