2020-01-18 09:38:21 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
2020-08-24 19:35:19 -06:00
|
|
|
#include <AK/Singleton.h>
|
2024-07-12 22:17:17 +03:00
|
|
|
#include <Kernel/Devices/BaseDevices.h>
|
|
|
|
#include <Kernel/Devices/BlockDevice.h>
|
|
|
|
#include <Kernel/Devices/CharacterDevice.h>
|
2019-04-29 04:55:54 +02:00
|
|
|
#include <Kernel/Devices/Device.h>
|
2020-01-22 22:23:50 +01:00
|
|
|
#include <Kernel/FileSystem/InodeMetadata.h>
|
2022-10-23 21:51:56 +03:00
|
|
|
#include <Kernel/FileSystem/SysFS/Component.h>
|
2022-04-23 00:26:36 +03:00
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/DeviceIdentifiers/BlockDevicesDirectory.h>
|
|
|
|
#include <Kernel/FileSystem/SysFS/Subsystems/DeviceIdentifiers/CharacterDevicesDirectory.h>
|
2021-08-14 10:13:27 +03:00
|
|
|
#include <Kernel/Sections.h>
|
2019-02-16 00:47:20 +01:00
|
|
|
|
2020-02-16 01:27:42 +01:00
|
|
|
namespace Kernel {
|
|
|
|
|
2024-07-12 22:17:17 +03:00
|
|
|
struct AllDevicesDetails {
|
|
|
|
SpinlockProtected<HashMap<u64, BlockDevice*>, LockRank::None> block_devices {};
|
|
|
|
SpinlockProtected<HashMap<u64, CharacterDevice*>, LockRank::None> char_devices {};
|
|
|
|
SpinlockProtected<CircularQueue<DeviceEvent, 100>, LockRank::None> event_queue {};
|
|
|
|
// NOTE: There's no locking on this pointer because we expect to initialize it once
|
|
|
|
// and never touch it again.
|
|
|
|
OwnPtr<BaseDevices> base_devices;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Singleton<AllDevicesDetails> s_all_details;
|
|
|
|
|
|
|
|
SpinlockProtected<CircularQueue<DeviceEvent, 100>, LockRank::None>& Device::event_queue()
|
2019-02-17 10:38:07 +01:00
|
|
|
{
|
2024-07-12 22:17:17 +03:00
|
|
|
return s_all_details->event_queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseDevices* Device::base_devices()
|
|
|
|
{
|
|
|
|
return s_all_details->base_devices.ptr();
|
|
|
|
}
|
|
|
|
|
|
|
|
UNMAP_AFTER_INIT void Device::initialize_base_devices()
|
|
|
|
{
|
|
|
|
auto base_devices = MUST(adopt_nonnull_own_or_enomem(new (nothrow) BaseDevices(*NullDevice::must_initialize(), *ConsoleDevice::must_create(), *DeviceControlDevice::must_create())));
|
|
|
|
s_all_details->base_devices = move(base_devices);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Device> Device::acquire_by_type_and_major_minor_numbers(DeviceNodeType type, MajorNumber major, MinorNumber minor)
|
|
|
|
{
|
|
|
|
VERIFY(type == DeviceNodeType::Block || type == DeviceNodeType::Character);
|
|
|
|
|
|
|
|
auto find_device_in_map = [major, minor](auto& map) -> RefPtr<Device> {
|
|
|
|
auto it = map.find(encoded_device(major.value(), minor.value()));
|
|
|
|
if (it == map.end())
|
|
|
|
return nullptr;
|
|
|
|
return *it->value;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (type == DeviceNodeType::Block) {
|
|
|
|
return s_all_details->block_devices.with([&](auto& map) -> RefPtr<Device> {
|
|
|
|
return find_device_in_map(map);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return s_all_details->char_devices.with([&](auto& map) -> RefPtr<Device> {
|
|
|
|
return find_device_in_map(map);
|
|
|
|
});
|
2021-09-10 14:44:46 +03:00
|
|
|
}
|
|
|
|
|
2022-04-23 11:19:02 +03:00
|
|
|
void Device::before_will_be_destroyed_remove_from_device_management()
|
|
|
|
{
|
2024-07-12 22:17:17 +03:00
|
|
|
before_device_removal({}, *this);
|
2022-04-23 11:19:02 +03:00
|
|
|
m_state = State::BeingRemoved;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Device::after_inserting_add_to_device_management()
|
2021-09-10 14:44:46 +03:00
|
|
|
{
|
2024-07-12 22:17:17 +03:00
|
|
|
after_inserting_device({}, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
Device::Device(MajorNumber major, MinorNumber minor)
|
|
|
|
: m_major(major)
|
|
|
|
, m_minor(minor)
|
|
|
|
{
|
2022-04-23 11:19:02 +03:00
|
|
|
}
|
|
|
|
|
2022-12-21 22:33:56 +02:00
|
|
|
ErrorOr<void> Device::after_inserting()
|
2022-04-23 11:19:02 +03:00
|
|
|
{
|
2021-09-10 14:44:46 +03:00
|
|
|
VERIFY(!m_sysfs_component);
|
2021-08-14 11:40:37 +03:00
|
|
|
auto sys_fs_component = SysFSDeviceComponent::must_create(*this);
|
|
|
|
m_sysfs_component = sys_fs_component;
|
2022-07-16 10:39:57 +03:00
|
|
|
after_inserting_add_to_device_identifier_directory();
|
2023-04-05 13:21:11 +03:00
|
|
|
after_inserting_add_to_device_management();
|
2022-12-21 22:33:56 +02:00
|
|
|
return {};
|
2021-08-14 11:40:37 +03:00
|
|
|
}
|
|
|
|
|
2021-12-29 01:00:29 +02:00
|
|
|
void Device::will_be_destroyed()
|
2021-08-14 11:40:37 +03:00
|
|
|
{
|
2021-09-10 14:44:46 +03:00
|
|
|
VERIFY(m_sysfs_component);
|
2022-04-23 11:19:02 +03:00
|
|
|
before_will_be_destroyed_remove_from_device_management();
|
2023-04-05 13:21:11 +03:00
|
|
|
before_will_be_destroyed_remove_from_device_identifier_directory();
|
2019-02-17 10:38:07 +01:00
|
|
|
}
|
|
|
|
|
2019-02-16 00:47:20 +01:00
|
|
|
Device::~Device()
|
|
|
|
{
|
2021-08-14 11:40:37 +03:00
|
|
|
VERIFY(m_state == State::BeingRemoved);
|
2019-02-16 00:47:20 +01:00
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
ErrorOr<NonnullOwnPtr<KString>> Device::pseudo_path(OpenFileDescription const&) const
|
2019-02-16 00:47:20 +01:00
|
|
|
{
|
2021-11-29 03:03:33 -08:00
|
|
|
return KString::formatted("device:{},{}", major(), minor());
|
2019-08-17 12:17:36 +03:00
|
|
|
}
|
2020-02-16 01:27:42 +01:00
|
|
|
|
2023-03-06 19:29:25 +01:00
|
|
|
ErrorOr<NonnullRefPtr<OpenFileDescription>> Device::open(int options)
|
2022-12-02 11:33:57 +02:00
|
|
|
{
|
Kernel+Userland: Reduce jails to be a simple boolean flag
The whole concept of Jails was far more complicated than I actually want
it to be, so let's reduce the complexity of how it works from now on.
Please note that we always leaked the attach count of a Jail object in
the fork syscall if it failed midway.
Instead, we should have attach to the jail just before registering the
new Process, so we don't need to worry about unsuccessful Process
creation.
The reduction of complexity in regard to jails means that instead of
relying on jails to provide PID isolation, we could simplify the whole
idea of them to be a simple SetOnce, and let the ProcessList (now called
ScopedProcessList) to be responsible for this type of isolation.
Therefore, we apply the following changes to do so:
- We make the Jail concept no longer a class of its own. Instead, we
simplify the idea of being jailed to a simple ProtectedValues boolean
flag. This means that we no longer check of matching jail pointers
anywhere in the Kernel code.
To set a process as jailed, a new prctl option was added to set a
Kernel SetOnce boolean flag (so it cannot change ever again).
- We provide Process & Thread methods to iterate over process lists.
A process can either iterate on the global process list, or if it's
attached to a scoped process list, then only over that list.
This essentially replaces the need of checking the Jail pointer of a
process when iterating over process lists.
2024-01-27 10:54:47 +02:00
|
|
|
if (Process::current().is_jailed() && !is_openable_by_jailed_processes())
|
|
|
|
return Error::from_errno(EPERM);
|
2022-12-02 11:33:57 +02:00
|
|
|
return File::open(options);
|
|
|
|
}
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
void Device::process_next_queued_request(Badge<AsyncDeviceRequest>, AsyncDeviceRequest const& completed_request)
|
2020-11-02 11:16:01 -07:00
|
|
|
{
|
2021-08-22 01:49:22 +02:00
|
|
|
SpinlockLocker lock(m_requests_lock);
|
2021-02-06 16:59:32 -07:00
|
|
|
VERIFY(!m_requests.is_empty());
|
|
|
|
VERIFY(m_requests.first().ptr() == &completed_request);
|
|
|
|
m_requests.remove(m_requests.begin());
|
|
|
|
if (!m_requests.is_empty()) {
|
|
|
|
auto* next_request = m_requests.first().ptr();
|
|
|
|
next_request->do_start(move(lock));
|
2020-11-02 11:16:01 -07:00
|
|
|
}
|
|
|
|
|
2020-11-29 16:05:27 -07:00
|
|
|
evaluate_block_conditions();
|
2020-11-02 11:16:01 -07:00
|
|
|
}
|
|
|
|
|
2024-07-12 22:17:17 +03:00
|
|
|
void Device::after_inserting_device(Badge<Device>, Device& device)
|
|
|
|
{
|
|
|
|
if (device.is_block_device()) {
|
|
|
|
s_all_details->block_devices.with([&](auto& map) -> void {
|
|
|
|
add_device_to_map<BlockDevice>(map, device);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
VERIFY(device.is_character_device());
|
|
|
|
s_all_details->char_devices.with([&](auto& map) -> void {
|
|
|
|
add_device_to_map<CharacterDevice>(map, device);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
s_all_details->event_queue.with([&](auto& queue) {
|
|
|
|
DeviceEvent event { DeviceEvent::State::Inserted, device.is_block_device(), device.major().value(), device.minor().value() };
|
|
|
|
queue.enqueue(event);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (s_all_details->base_devices)
|
|
|
|
s_all_details->base_devices->device_control_device->evaluate_block_conditions();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Device::before_device_removal(Badge<Device>, Device& device)
|
|
|
|
{
|
|
|
|
u64 device_id = encoded_device(device.major(), device.minor());
|
|
|
|
|
|
|
|
if (device.is_block_device()) {
|
|
|
|
s_all_details->block_devices.with([&](auto& map) -> void {
|
|
|
|
VERIFY(map.contains(device_id));
|
|
|
|
map.remove(encoded_device(device.major(), device.minor()));
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
VERIFY(device.is_character_device());
|
|
|
|
s_all_details->char_devices.with([&](auto& map) -> void {
|
|
|
|
VERIFY(map.contains(device_id));
|
|
|
|
map.remove(encoded_device(device.major(), device.minor()));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
s_all_details->event_queue.with([&](auto& queue) {
|
|
|
|
DeviceEvent event { DeviceEvent::State::Removed, device.is_block_device(), device.major().value(), device.minor().value() };
|
|
|
|
queue.enqueue(event);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (s_all_details->base_devices)
|
|
|
|
s_all_details->base_devices->device_control_device->evaluate_block_conditions();
|
|
|
|
}
|
|
|
|
|
2020-02-16 01:27:42 +01:00
|
|
|
}
|