summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-08-14 11:40:37 +0300
committerAndreas Kling <kling@serenityos.org>2021-09-08 00:42:20 +0200
commit6a9c717a301c16b60e80ecd55b19909418561b5b (patch)
tree19a8fc87b583bd4e96a2acf239ae6d358a1ac4c1
parent009feefee0dc45af2a38b0c6c9f6963ddda5468d (diff)
downloadserenity-6a9c717a301c16b60e80ecd55b19909418561b5b.zip
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).
-rw-r--r--Kernel/Devices/Device.cpp111
-rw-r--r--Kernel/Devices/Device.h13
-rw-r--r--Kernel/FileSystem/SysFS.cpp8
-rw-r--r--Kernel/FileSystem/SysFS.h51
-rw-r--r--Kernel/init.cpp2
5 files changed, 183 insertions, 2 deletions
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 <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));
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 <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;
};
}
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 <AK/Singleton.h>
#include <AK/StringView.h>
+#include <Kernel/Devices/Device.h>
#include <Kernel/FileSystem/SysFS.h>
#include <Kernel/Sections.h>
@@ -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> 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 <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/FileSystem/SysFSComponent.h>
+#include <Kernel/Locking/MutexProtected.h>
namespace Kernel {
+class SysFSDevicesDirectory;
class SysFSRootDirectory final : public SysFSDirectory {
friend class SysFSComponentRegistry;
@@ -24,6 +26,50 @@ private:
RefPtr<SysFSBusDirectory> m_buses_directory;
};
+class SysFSDeviceComponent final
+ : public SysFSComponent
+ , public Weakable<SysFSDeviceComponent> {
+ friend class SysFSComponentRegistry;
+
+public:
+ static NonnullRefPtr<SysFSDeviceComponent> must_create(Device const&);
+
+ Device const& device() const { return *m_associated_device; }
+
+private:
+ explicit SysFSDeviceComponent(Device const&);
+ IntrusiveListNode<SysFSDeviceComponent, NonnullRefPtr<SysFSDeviceComponent>> m_list_node;
+ RefPtr<Device> m_associated_device;
+};
+
+class SysFSDevicesDirectory final : public SysFSDirectory {
+public:
+ static NonnullRefPtr<SysFSDevicesDirectory> must_create(SysFSRootDirectory const&);
+
+private:
+ explicit SysFSDevicesDirectory(SysFSRootDirectory const&);
+};
+
+class SysFSBlockDevicesDirectory final : public SysFSDirectory {
+public:
+ static NonnullRefPtr<SysFSBlockDevicesDirectory> must_create(SysFSDevicesDirectory const&);
+ virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual RefPtr<SysFSComponent> lookup(StringView name) override;
+
+private:
+ explicit SysFSBlockDevicesDirectory(SysFSDevicesDirectory const&);
+};
+
+class SysFSCharacterDevicesDirectory final : public SysFSDirectory {
+public:
+ static NonnullRefPtr<SysFSCharacterDevicesDirectory> must_create(SysFSDevicesDirectory const&);
+ virtual KResult traverse_as_directory(unsigned, Function<bool(FileSystem::DirectoryEntryView const&)>) const override;
+ virtual RefPtr<SysFSComponent> 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<IntrusiveList<SysFSDeviceComponent, NonnullRefPtr<SysFSDeviceComponent>, &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<SysFSRootDirectory> 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();