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)); diff --git a/Kernel/Devices/Device.h b/Kernel/Devices/Device.h index fcd503e1f6..cc1fc51827 100644 --- a/Kernel/Devices/Device.h +++ b/Kernel/Devices/Device.h @@ -17,15 +17,22 @@ #include #include #include +#include #include #include -#include +#include #include #include 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); 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> m_requests; + WeakPtr m_sysfs_component; }; } diff --git a/Kernel/FileSystem/SysFS.cpp b/Kernel/FileSystem/SysFS.cpp index e56744f050..d0447ee4f8 100644 --- a/Kernel/FileSystem/SysFS.cpp +++ b/Kernel/FileSystem/SysFS.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -35,6 +36,11 @@ UNMAP_AFTER_INIT void SysFSComponentRegistry::register_new_component(SysFSCompon m_root_directory->m_components.append(component); } +SysFSComponentRegistry::DevicesList& SysFSComponentRegistry::devices_list() +{ + return m_devices_list; +} + NonnullRefPtr SysFSRootDirectory::create() { return adopt_ref(*new (nothrow) SysFSRootDirectory); @@ -57,7 +63,9 @@ SysFSRootDirectory::SysFSRootDirectory() : SysFSDirectory(".") { auto buses_directory = SysFSBusDirectory::must_create(*this); + auto devices_directory = SysFSDevicesDirectory::must_create(*this); m_components.append(buses_directory); + m_components.append(devices_directory); m_buses_directory = buses_directory; } diff --git a/Kernel/FileSystem/SysFS.h b/Kernel/FileSystem/SysFS.h index 437ba4595a..c3523629c6 100644 --- a/Kernel/FileSystem/SysFS.h +++ b/Kernel/FileSystem/SysFS.h @@ -9,9 +9,11 @@ #include #include #include +#include namespace Kernel { +class SysFSDevicesDirectory; class SysFSRootDirectory final : public SysFSDirectory { friend class SysFSComponentRegistry; @@ -24,6 +26,50 @@ private: RefPtr m_buses_directory; }; +class SysFSDeviceComponent final + : public SysFSComponent + , public Weakable { + friend class SysFSComponentRegistry; + +public: + static NonnullRefPtr must_create(Device const&); + + Device const& device() const { return *m_associated_device; } + +private: + explicit SysFSDeviceComponent(Device const&); + IntrusiveListNode> m_list_node; + RefPtr m_associated_device; +}; + +class SysFSDevicesDirectory final : public SysFSDirectory { +public: + static NonnullRefPtr must_create(SysFSRootDirectory const&); + +private: + explicit SysFSDevicesDirectory(SysFSRootDirectory const&); +}; + +class SysFSBlockDevicesDirectory final : public SysFSDirectory { +public: + static NonnullRefPtr must_create(SysFSDevicesDirectory const&); + virtual KResult traverse_as_directory(unsigned, Function) const override; + virtual RefPtr lookup(StringView name) override; + +private: + explicit SysFSBlockDevicesDirectory(SysFSDevicesDirectory const&); +}; + +class SysFSCharacterDevicesDirectory final : public SysFSDirectory { +public: + static NonnullRefPtr must_create(SysFSDevicesDirectory const&); + virtual KResult traverse_as_directory(unsigned, Function) const override; + virtual RefPtr lookup(StringView name) override; + +private: + explicit SysFSCharacterDevicesDirectory(SysFSDevicesDirectory const&); +}; + class SysFSBusDirectory : public SysFSDirectory { friend class SysFSComponentRegistry; @@ -35,6 +81,8 @@ private: }; class SysFSComponentRegistry { + using DevicesList = MutexProtected, &SysFSDeviceComponent::m_list_node>>; + public: static SysFSComponentRegistry& the(); @@ -49,9 +97,12 @@ public: void register_new_bus_directory(SysFSDirectory&); SysFSBusDirectory& buses_directory(); + DevicesList& devices_list(); + private: Mutex m_lock; NonnullRefPtr m_root_directory; + DevicesList m_devices_list; }; class SysFS final : public FileSystem { diff --git a/Kernel/init.cpp b/Kernel/init.cpp index abc57179b0..a08b8dd6c8 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -182,6 +182,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info) load_kernel_symbol_table(); + SysFSComponentRegistry::initialize(); ConsoleDevice::initialize(); s_bsp_processor.initialize(0); @@ -275,7 +276,6 @@ void init_stage2(void*) } // Initialize the PCI Bus as early as possible, for early boot (PCI based) serial logging - SysFSComponentRegistry::initialize(); PCI::initialize(); PCISerialDevice::detect();