mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:27:45 +00:00
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).
This commit is contained in:
parent
009feefee0
commit
6a9c717a30
5 changed files with 183 additions and 2 deletions
|
@ -7,6 +7,7 @@
|
|||
#include <AK/Singleton.h>
|
||||
#include <Kernel/Devices/Device.h>
|
||||
#include <Kernel/FileSystem/InodeMetadata.h>
|
||||
#include <Kernel/FileSystem/SysFS.h>
|
||||
#include <Kernel/Locking/MutexProtected.h>
|
||||
#include <Kernel/Sections.h>
|
||||
|
||||
|
@ -19,6 +20,100 @@ MutexProtected<HashMap<u32, Device*>>& Device::all_devices()
|
|||
return *s_all_devices;
|
||||
}
|
||||
|
||||
NonnullRefPtr<SysFSDeviceComponent> 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> 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> 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<bool(FileSystem::DirectoryEntryView const&)> 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<SysFSComponent> SysFSBlockDevicesDirectory::lookup(StringView name)
|
||||
{
|
||||
return SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> RefPtr<SysFSComponent> {
|
||||
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> 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<bool(FileSystem::DirectoryEntryView const&)> 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<SysFSComponent> SysFSCharacterDevicesDirectory::lookup(StringView name)
|
||||
{
|
||||
return SysFSComponentRegistry::the().devices_list().with_exclusive([&](auto& list) -> RefPtr<SysFSComponent> {
|
||||
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<void(Device&)> 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));
|
||||
|
|
|
@ -17,15 +17,22 @@
|
|||
#include <AK/DoublyLinkedList.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <Kernel/Devices/AsyncDeviceRequest.h>
|
||||
#include <Kernel/FileSystem/File.h>
|
||||
#include <Kernel/FileSystem/SysFSComponent.h>
|
||||
#include <Kernel/FileSystem/SysFS.h>
|
||||
#include <Kernel/Locking/Mutex.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class Device : public File {
|
||||
protected:
|
||||
enum class State {
|
||||
Normal,
|
||||
BeingRemoved,
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~Device() override;
|
||||
|
||||
|
@ -39,6 +46,7 @@ public:
|
|||
GroupID gid() const { return m_gid; }
|
||||
|
||||
virtual bool is_device() const override { return true; }
|
||||
virtual void before_removing();
|
||||
|
||||
static void for_each(Function<void(Device&)>);
|
||||
static Device* get_device(unsigned major, unsigned minor);
|
||||
|
@ -70,8 +78,11 @@ private:
|
|||
UserID m_uid { 0 };
|
||||
GroupID m_gid { 0 };
|
||||
|
||||
State m_state { State::Normal };
|
||||
|
||||
Spinlock m_requests_lock;
|
||||
DoublyLinkedList<RefPtr<AsyncDeviceRequest>> m_requests;
|
||||
WeakPtr<SysFSDeviceComponent> m_sysfs_component;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue