Kernel: Register block and character devices in separate HashMaps

Instead of putting everything in one hash map, let's distinguish between
the devices based on their type.

This change makes the devices semantically separated, and is considered
a preparation before we could expose a comprehensive list of allocations
per major numbers and their purpose.
This commit is contained in:
Liav A. 2024-05-04 13:06:01 +03:00 committed by Nico Weber
parent fdff05cc97
commit 7f5a2c1466
7 changed files with 71 additions and 42 deletions

View file

@ -10,3 +10,8 @@
AK_TYPEDEF_DISTINCT_ORDERED_ID(unsigned, MajorNumber);
AK_TYPEDEF_DISTINCT_ORDERED_ID(unsigned, MinorNumber);
enum class DeviceNodeType {
Block = 1,
Character = 2,
};

View file

@ -42,9 +42,20 @@ DeviceManagement& DeviceManagement::the()
return *s_the;
}
RefPtr<Device> DeviceManagement::get_device(MajorNumber major, MinorNumber minor)
RefPtr<Device> DeviceManagement::get_device(DeviceNodeType type, MajorNumber major, MinorNumber minor)
{
return m_devices.with([&](auto& map) -> RefPtr<Device> {
VERIFY(type == DeviceNodeType::Block || type == DeviceNodeType::Character);
if (type == DeviceNodeType::Block) {
return m_block_devices.with([&](auto& map) -> RefPtr<Device> {
auto it = map.find(encoded_device(major.value(), minor.value()));
if (it == map.end())
return nullptr;
return *it->value;
});
}
return m_char_devices.with([&](auto& map) -> RefPtr<Device> {
auto it = map.find(encoded_device(major.value(), minor.value()));
if (it == map.end())
return nullptr;
@ -55,10 +66,19 @@ RefPtr<Device> DeviceManagement::get_device(MajorNumber major, MinorNumber minor
void DeviceManagement::before_device_removal(Badge<Device>, Device& device)
{
u64 device_id = encoded_device(device.major(), device.minor());
m_devices.with([&](auto& map) -> void {
VERIFY(map.contains(device_id));
map.remove(encoded_device(device.major(), device.minor()));
});
if (device.is_block_device()) {
m_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());
m_char_devices.with([&](auto& map) -> void {
VERIFY(map.contains(device_id));
map.remove(encoded_device(device.major(), device.minor()));
});
}
m_event_queue.with([&](auto& queue) {
DeviceEvent event { DeviceEvent::State::Removed, device.is_block_device(), device.major().value(), device.minor().value() };
@ -77,17 +97,32 @@ SpinlockProtected<CircularQueue<DeviceEvent, 100>, LockRank::None>& DeviceManage
void DeviceManagement::after_inserting_device(Badge<Device>, Device& device)
{
u64 device_id = encoded_device(device.major(), device.minor());
m_devices.with([&](auto& map) -> void {
if (map.contains(device_id)) {
dbgln("Already registered {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
auto result = map.set(device_id, &device);
if (result != AK::HashSetResult::InsertedNewEntry) {
dbgln("Failed to register {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
});
if (device.is_block_device()) {
m_block_devices.with([&](auto& map) -> void {
if (map.contains(device_id)) {
dbgln("Already registered {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
auto result = map.set(device_id, static_cast<BlockDevice*>(&device));
if (result != AK::HashSetResult::InsertedNewEntry) {
dbgln("Failed to register {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
});
} else {
VERIFY(device.is_character_device());
m_char_devices.with([&](auto& map) -> void {
if (map.contains(device_id)) {
dbgln("Already registered {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
auto result = map.set(device_id, static_cast<CharacterDevice*>(&device));
if (result != AK::HashSetResult::InsertedNewEntry) {
dbgln("Failed to register {},{}: {}", device.major(), device.minor(), device.class_name());
VERIFY_NOT_REACHED();
}
});
}
m_event_queue.with([&](auto& queue) {
DeviceEvent event { DeviceEvent::State::Inserted, device.is_block_device(), device.major().value(), device.minor().value() };
@ -98,23 +133,6 @@ void DeviceManagement::after_inserting_device(Badge<Device>, Device& device)
m_device_control_device->evaluate_block_conditions();
}
void DeviceManagement::for_each(Function<void(Device&)> callback)
{
m_devices.with([&](auto& map) -> void {
for (auto& entry : map)
callback(*entry.value);
});
}
ErrorOr<void> DeviceManagement::try_for_each(Function<ErrorOr<void>(Device&)> callback)
{
return m_devices.with([&](auto& map) -> ErrorOr<void> {
for (auto& entry : map)
TRY(callback(*entry.value));
return {};
});
}
NullDevice& DeviceManagement::null_device()
{
return *m_null_device;

View file

@ -11,8 +11,10 @@
#include <AK/OwnPtr.h>
#include <AK/Types.h>
#include <Kernel/API/DeviceEvent.h>
#include <Kernel/API/DeviceFileTypes.h>
#include <Kernel/API/TimePage.h>
#include <Kernel/Arch/RegisterState.h>
#include <Kernel/Devices/BlockDevice.h>
#include <Kernel/Devices/CharacterDevice.h>
#include <Kernel/Devices/Device.h>
#include <Kernel/Devices/Generic/ConsoleDevice.h>
@ -39,9 +41,7 @@ public:
void after_inserting_device(Badge<Device>, Device&);
void before_device_removal(Badge<Device>, Device&);
void for_each(Function<void(Device&)>);
ErrorOr<void> try_for_each(Function<ErrorOr<void>(Device&)>);
RefPtr<Device> get_device(MajorNumber major, MinorNumber minor);
RefPtr<Device> get_device(DeviceNodeType, MajorNumber major, MinorNumber minor);
NullDevice const& null_device() const;
NullDevice& null_device();
@ -72,7 +72,8 @@ private:
LockRefPtr<NullDevice> m_null_device;
LockRefPtr<ConsoleDevice> m_console_device;
LockRefPtr<DeviceControlDevice> m_device_control_device;
SpinlockProtected<HashMap<u64, Device*>, LockRank::None> m_devices {};
SpinlockProtected<HashMap<u64, BlockDevice*>, LockRank::None> m_block_devices {};
SpinlockProtected<HashMap<u64, CharacterDevice*>, LockRank::None> m_char_devices {};
SpinlockProtected<CircularQueue<DeviceEvent, 100>, LockRank::None> m_event_queue {};
};

View file

@ -12,6 +12,7 @@
#if ARCH(AARCH64)
# include <Kernel/Arch/aarch64/RPi/SDHostController.h>
#endif
#include <Kernel/API/DeviceFileTypes.h>
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/Access.h>
@ -342,7 +343,7 @@ UNMAP_AFTER_INIT void StorageManagement::determine_block_boot_device()
// Note: We simply fetch the corresponding BlockDevice with the major and minor parameters.
// We don't try to accept and resolve a partition number as it will make this code much more
// complicated. This rule is also explained in the boot_device_addressing(7) manual page.
auto device = DeviceManagement::the().get_device(parameters_view[0], parameters_view[1]);
auto device = DeviceManagement::the().get_device(DeviceNodeType::Block, parameters_view[0], parameters_view[1]);
if (device && device->is_block_device())
m_boot_block_device = *static_ptr_cast<BlockDevice>(device);
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/API/DeviceFileTypes.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/Loop/LoopDevice.h>
#include <Kernel/FileSystem/DevLoopFS/FileSystem.h>
@ -57,7 +58,7 @@ ErrorOr<NonnullRefPtr<Inode>> DevLoopFS::get_inode(InodeIdentifier inode_id) con
return *m_root_inode;
unsigned loop_index = inode_index_to_loop_index(inode_id.index());
auto device = DeviceManagement::the().get_device(20, loop_index);
auto device = DeviceManagement::the().get_device(DeviceNodeType::Block, 20, loop_index);
VERIFY(device);
auto& loop_device = static_cast<LoopDevice&>(*device);

View file

@ -5,6 +5,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/API/DeviceFileTypes.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/TTY/SlavePTY.h>
#include <Kernel/FileSystem/DevPtsFS/FileSystem.h>
@ -55,7 +56,7 @@ ErrorOr<NonnullRefPtr<Inode>> DevPtsFS::get_inode(InodeIdentifier inode_id) cons
return *m_root_inode;
unsigned pty_index = inode_index_to_pty_index(inode_id.index());
auto device = DeviceManagement::the().get_device(201, pty_index);
auto device = DeviceManagement::the().get_device(DeviceNodeType::Character, 201, pty_index);
VERIFY(device);
auto& pts_device = static_cast<SlavePTY&>(*device);

View file

@ -10,6 +10,7 @@
#include <AK/RefPtr.h>
#include <AK/Singleton.h>
#include <AK/StringBuilder.h>
#include <Kernel/API/DeviceFileTypes.h>
#include <Kernel/API/POSIX/errno.h>
#include <Kernel/Debug.h>
#include <Kernel/Devices/BlockDevice.h>
@ -531,7 +532,8 @@ ErrorOr<NonnullRefPtr<OpenFileDescription>> VirtualFileSystem::open(Process cons
if (metadata.is_device()) {
if (custody.mount_flags() & MS_NODEV)
return EACCES;
auto device = DeviceManagement::the().get_device(metadata.major_device, metadata.minor_device);
auto device_type = metadata.is_block_device() ? DeviceNodeType::Block : DeviceNodeType::Character;
auto device = DeviceManagement::the().get_device(device_type, metadata.major_device, metadata.minor_device);
if (device == nullptr) {
return ENODEV;
}