From 6a9c717a301c16b60e80ecd55b19909418561b5b Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 14 Aug 2021 11:40:37 +0300 Subject: Kernel: Expose device presence in /sys/dev/char and /sys/dev/block These files are not marked as block devices or character devices so they are not meant to be used as device nodes. The filenames are formatted to the pattern "major:minor", but a Userland program need to call the parse these format and inspect the the major and minor numbers and create the real device nodes in /dev. Later on, it might be a good idea to ensure we don't create new SysFSComponents on the heap for each Device, but rather generate them only when required (and preferably to not create a SysFSComponent at all if possible). --- Kernel/Devices/Device.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'Kernel/Devices/Device.cpp') diff --git a/Kernel/Devices/Device.cpp b/Kernel/Devices/Device.cpp index 42684fa75c..e74365e2d0 100644 --- a/Kernel/Devices/Device.cpp +++ b/Kernel/Devices/Device.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,100 @@ MutexProtected>& Device::all_devices() return *s_all_devices; } +NonnullRefPtr SysFSDeviceComponent::must_create(Device const& device) +{ + return adopt_ref_if_nonnull(new SysFSDeviceComponent(device)).release_nonnull(); +} +SysFSDeviceComponent::SysFSDeviceComponent(Device const& device) + : SysFSComponent(String::formatted("{}:{}", device.major(), device.minor())) + , m_associated_device(device) +{ +} + +UNMAP_AFTER_INIT NonnullRefPtr SysFSDevicesDirectory::must_create(SysFSRootDirectory const& root_directory) +{ + auto devices_directory = adopt_ref_if_nonnull(new SysFSDevicesDirectory(root_directory)).release_nonnull(); + devices_directory->m_components.append(SysFSBlockDevicesDirectory::must_create(*devices_directory)); + devices_directory->m_components.append(SysFSCharacterDevicesDirectory::must_create(*devices_directory)); + return devices_directory; +} +SysFSDevicesDirectory::SysFSDevicesDirectory(SysFSRootDirectory const& root_directory) + : SysFSDirectory("dev"sv, root_directory) +{ +} + +NonnullRefPtr SysFSBlockDevicesDirectory::must_create(SysFSDevicesDirectory const& devices_directory) +{ + return adopt_ref_if_nonnull(new SysFSBlockDevicesDirectory(devices_directory)).release_nonnull(); +} +SysFSBlockDevicesDirectory::SysFSBlockDevicesDirectory(SysFSDevicesDirectory const& devices_directory) + : SysFSDirectory("block"sv, devices_directory) +{ +} +KResult SysFSBlockDevicesDirectory::traverse_as_directory(unsigned fsid, Function callback) const +{ + VERIFY(m_parent_directory); + callback({ ".", { fsid, component_index() }, 0 }); + callback({ "..", { fsid, m_parent_directory->component_index() }, 0 }); + + SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> void { + for (auto& exposed_device : list) { + if (!exposed_device.device().is_block_device()) + continue; + callback({ exposed_device.name(), { fsid, exposed_device.component_index() }, 0 }); + } + }); + return KSuccess; +} +RefPtr SysFSBlockDevicesDirectory::lookup(StringView name) +{ + return SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> RefPtr { + for (auto& exposed_device : list) { + if (!exposed_device.device().is_block_device()) + continue; + if (exposed_device.name() == name) + return exposed_device; + } + return nullptr; + }); +} + +NonnullRefPtr SysFSCharacterDevicesDirectory::must_create(SysFSDevicesDirectory const& devices_directory) +{ + return adopt_ref_if_nonnull(new SysFSCharacterDevicesDirectory(devices_directory)).release_nonnull(); +} +SysFSCharacterDevicesDirectory::SysFSCharacterDevicesDirectory(SysFSDevicesDirectory const& devices_directory) + : SysFSDirectory("char"sv, devices_directory) +{ +} +KResult SysFSCharacterDevicesDirectory::traverse_as_directory(unsigned fsid, Function callback) const +{ + VERIFY(m_parent_directory); + callback({ ".", { fsid, component_index() }, 0 }); + callback({ "..", { fsid, m_parent_directory->component_index() }, 0 }); + + SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> void { + for (auto& exposed_device : list) { + if (!exposed_device.device().is_character_device()) + continue; + callback({ exposed_device.name(), { fsid, exposed_device.component_index() }, 0 }); + } + }); + return KSuccess; +} +RefPtr SysFSCharacterDevicesDirectory::lookup(StringView name) +{ + return SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> RefPtr { + for (auto& exposed_device : list) { + if (!exposed_device.device().is_character_device()) + continue; + if (exposed_device.name() == name) + return exposed_device; + } + return nullptr; + }); +} + void Device::for_each(Function callback) { all_devices().with_exclusive([&](auto& map) -> void { @@ -50,10 +145,26 @@ Device::Device(unsigned major, unsigned minor) VERIFY(!map.contains(device_id)); map.set(device_id, this); }); + auto sys_fs_component = SysFSDeviceComponent::must_create(*this); + m_sysfs_component = sys_fs_component; + SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> void { + list.append(sys_fs_component); + }); +} + +void Device::before_removing() +{ + auto sys_fs_component = m_sysfs_component.strong_ref(); + VERIFY(sys_fs_component); + SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> void { + list.remove(*sys_fs_component); + }); + m_state = State::BeingRemoved; } Device::~Device() { + VERIFY(m_state == State::BeingRemoved); u32 device_id = encoded_device(m_major, m_minor); all_devices().with_exclusive([&](auto& map) -> void { VERIFY(map.contains(device_id)); -- cgit v1.2.3