1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:58:11 +00:00

Kernel/Devices: Introduce the LoopDevice device

This device is a block device that allows a user to effectively treat an
Inode as a block device.

The static construction method is given an OpenFileDescription reference
but validates that:
- The description has a valid custody (so it's not some arbitrary file).
  Failing this requirement will yield EINVAL.
- The description custody points to an Inode which is a regular file, as
  we only support (seekable) regular files. Failing this requirement
  will yield ENOTSUP.

LoopDevice can be used to mount a regular file on the filesystem like
other supported types of (physical) block devices.
This commit is contained in:
Liav A 2024-02-23 17:11:48 +02:00 committed by Andrew Kaster
parent a9d240c647
commit 5dcf03ad9a
12 changed files with 254 additions and 4 deletions

View file

@ -4,8 +4,11 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/API/Ioctl.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/Generic/DeviceControlDevice.h>
#include <Kernel/Devices/Loop/LoopDevice.h>
#include <Kernel/Library/StdLib.h>
namespace Kernel {
@ -51,9 +54,33 @@ ErrorOr<size_t> DeviceControlDevice::read(OpenFileDescription&, u64 offset, User
});
}
ErrorOr<void> DeviceControlDevice::ioctl(OpenFileDescription&, unsigned, Userspace<void*>)
ErrorOr<void> DeviceControlDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
{
return Error::from_errno(ENOTSUP);
switch (request) {
case DEVCTL_CREATE_LOOP_DEVICE: {
unsigned fd { 0 };
TRY(copy_from_user(&fd, static_ptr_cast<unsigned*>(arg)));
auto file_description = TRY(Process::current().open_file_description(fd));
auto device = TRY(LoopDevice::create_with_file_description(file_description));
unsigned index = device->index();
return copy_to_user(static_ptr_cast<unsigned*>(arg), &index);
}
case DEVCTL_DESTROY_LOOP_DEVICE: {
unsigned index { 0 };
TRY(copy_from_user(&index, static_ptr_cast<unsigned*>(arg)));
return LoopDevice::all_instances().with([index](auto& list) -> ErrorOr<void> {
for (auto& device : list) {
if (device.index() == index) {
device.remove({});
return {};
}
}
return Error::from_errno(ENODEV);
});
}
default:
return Error::from_errno(EINVAL);
};
}
}