Kernel: Simplify mount syscall flow for regular calls

We do this by putting a distinction between two types of filesystems -
the first type is backed in RAM, and includes TmpFS, ProcFS, SysFS,
DevPtsFS and DevTmpFS. Because these filesystems are backed in RAM,
trying to mount them doesn't require source open file description.
The second type is filesystems that are backed by a file, therefore the
userspace program has to open them (hence it has a open file description
on them) and provide the appropriate source open file description.
By putting this distinction, we can early check if the user tried to
mount the second type of filesystems without a valid file description,
and fail with EBADF then.
Otherwise, we can proceed to either mount either type of filesystem,
provided that the fs_type is valid.
This commit is contained in:
Liav A 2022-05-28 14:52:48 +03:00 committed by Linus Groh
parent be3fec7c9e
commit 4c588441e3
Notes: sideshowbarker 2024-07-17 10:35:42 +09:00

View file

@ -18,6 +18,63 @@
namespace Kernel {
static ErrorOr<NonnullRefPtr<FileSystem>> create_ram_backed_filesystem_instance(StringView fs_type)
{
RefPtr<FileSystem> fs;
if (fs_type == "proc"sv || fs_type == "ProcFS"sv) {
fs = TRY(ProcFS::try_create());
} else if (fs_type == "devpts"sv || fs_type == "DevPtsFS"sv) {
fs = TRY(DevPtsFS::try_create());
} else if (fs_type == "dev"sv || fs_type == "DevTmpFS"sv) {
fs = TRY(DevTmpFS::try_create());
} else if (fs_type == "sys"sv || fs_type == "SysFS"sv) {
fs = TRY(SysFS::try_create());
} else if (fs_type == "tmp"sv || fs_type == "TmpFS"sv) {
fs = TRY(TmpFS::try_create());
}
if (!fs)
return ENODEV;
return fs.release_nonnull();
}
static bool filesystem_mount_require_open_file_description(StringView fs_type)
{
if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) {
return true;
} else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) {
return true;
} else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) {
return true;
}
return false;
}
static ErrorOr<NonnullRefPtr<FileSystem>> create_open_file_description_backed_filesystem_instance(StringView fs_type, OpenFileDescription& description)
{
RefPtr<FileSystem> fs;
if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) {
if (!description.file().is_block_device())
return ENOTBLK;
if (!description.file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return ENODEV;
}
fs = TRY(Ext2FS::try_create(description));
} else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) {
fs = TRY(Plan9FS::try_create(description));
} else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) {
if (!description.file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return ENODEV;
}
fs = TRY(ISO9660FS::try_create(description));
}
if (!fs)
return ENODEV;
return fs.release_nonnull();
}
ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> user_params)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
@ -59,58 +116,26 @@ ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> u
return 0;
}
RefPtr<FileSystem> fs;
if (fs_type == "ext2"sv || fs_type == "Ext2FS"sv) {
if (description_or_error.is_error())
return EBADF;
auto description = description_or_error.release_value();
if (!description->file().is_block_device())
return ENOTBLK;
if (!description->file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return ENODEV;
}
auto source_pseudo_path = TRY(description->pseudo_path());
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
fs = TRY(Ext2FS::try_create(*description));
} else if (fs_type == "9p"sv || fs_type == "Plan9FS"sv) {
if (description_or_error.is_error())
return EBADF;
auto description = description_or_error.release_value();
fs = TRY(Plan9FS::try_create(*description));
} else if (fs_type == "proc"sv || fs_type == "ProcFS"sv) {
fs = TRY(ProcFS::try_create());
} else if (fs_type == "devpts"sv || fs_type == "DevPtsFS"sv) {
fs = TRY(DevPtsFS::try_create());
} else if (fs_type == "dev"sv || fs_type == "DevTmpFS"sv) {
fs = TRY(DevTmpFS::try_create());
} else if (fs_type == "sys"sv || fs_type == "SysFS"sv) {
fs = TRY(SysFS::try_create());
} else if (fs_type == "tmp"sv || fs_type == "TmpFS"sv) {
fs = TRY(TmpFS::try_create());
} else if (fs_type == "iso9660"sv || fs_type == "ISO9660FS"sv) {
if (description_or_error.is_error())
return EBADF;
auto description = description_or_error.release_value();
if (!description->file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return ENODEV;
}
auto source_pseudo_path = TRY(description->pseudo_path());
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
fs = TRY(ISO9660FS::try_create(*description));
} else {
return ENODEV;
// Note: Try to determine as early as possible if we deal with a filesystem type
// that must be backed by a open file description, so if there's no such valid
// description, we can fail with EBADF now.
if (filesystem_mount_require_open_file_description(fs_type) && description_or_error.is_error()) {
return EBADF;
}
if (!fs)
return ENOMEM;
if (description_or_error.is_error()) {
auto synthetic_filesystem = TRY(create_ram_backed_filesystem_instance(fs_type));
TRY(synthetic_filesystem->initialize());
TRY(VirtualFileSystem::the().mount(*synthetic_filesystem, target_custody, params.flags));
return 0;
}
auto description = description_or_error.release_value();
auto open_file_description_backed_filesystem = TRY(create_open_file_description_backed_filesystem_instance(fs_type, description));
auto source_pseudo_path = TRY(description->pseudo_path());
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
TRY(open_file_description_backed_filesystem->initialize());
TRY(VirtualFileSystem::the().mount(*open_file_description_backed_filesystem, target_custody, params.flags));
TRY(fs->initialize());
TRY(VirtualFileSystem::the().mount(fs.release_nonnull(), target_custody, params.flags));
return 0;
}