1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 12:48:10 +00:00

Kernel/Storage: Implement basic AHCI hotplug support

This is really a basic support for AHCI hotplug events, so we know how
to add a node representing the device in /sys/dev/block and removing it
according to the event type (insertion/removal).

This change doesn't take into account what happens if the device was
mounted or a read/write operation is being handled.

For this to work correctly, StorageManagement now uses the Singleton
container, as it might be accessed simultaneously from many CPUs
for hotplug events. DiskPartition holds a WeakPtr instead of a RefPtr,
to allow removal of a StorageDevice object from the heap.
StorageDevices are now stored and being referenced to via an
IntrusiveList to make it easier to remove them on hotplug event.

In future changes, all of the stated above might change, but for now,
this commit represents the least amount of changes to make everything
to work correctly.
This commit is contained in:
Liav A 2021-08-27 08:08:43 +03:00 committed by Andreas Kling
parent 74c4c864bd
commit fb7b4caa57
11 changed files with 96 additions and 61 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Singleton.h>
#include <AK/UUID.h>
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/Access.h>
@ -21,21 +22,16 @@
namespace Kernel {
static StorageManagement* s_the;
static size_t s_device_minor_number;
static Singleton<StorageManagement> s_the;
static Atomic<size_t> s_device_minor_number;
UNMAP_AFTER_INIT StorageManagement::StorageManagement(String boot_argument, bool force_pio)
: m_boot_argument(boot_argument)
, m_controllers(enumerate_controllers(force_pio))
, m_storage_devices(enumerate_storage_devices())
, m_disk_partitions(enumerate_disk_partitions())
UNMAP_AFTER_INIT StorageManagement::StorageManagement()
{
s_device_minor_number = 0;
if (!boot_argument_contains_partition_uuid()) {
determine_boot_device();
return;
}
determine_boot_device_with_partition_uuid();
}
void StorageManagement::remove_device(StorageDevice& device)
{
m_storage_devices.remove(device);
}
bool StorageManagement::boot_argument_contains_partition_uuid()
@ -43,40 +39,37 @@ bool StorageManagement::boot_argument_contains_partition_uuid()
return m_boot_argument.starts_with("PARTUUID=");
}
UNMAP_AFTER_INIT NonnullRefPtrVector<StorageController> StorageManagement::enumerate_controllers(bool force_pio) const
UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio)
{
NonnullRefPtrVector<StorageController> controllers;
VERIFY(m_controllers.is_empty());
if (!kernel_command_line().disable_physical_storage()) {
if (kernel_command_line().is_ide_enabled()) {
PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_IDE_CTRL_SUBCLASS_ID) {
controllers.append(IDEController::initialize(address, force_pio));
m_controllers.append(IDEController::initialize(address, force_pio));
}
});
}
PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_SATA_CTRL_SUBCLASS_ID && PCI::get_programming_interface(address) == PCI_AHCI_IF_PROGIF) {
controllers.append(AHCIController::initialize(address));
m_controllers.append(AHCIController::initialize(address));
}
});
}
controllers.append(RamdiskController::initialize());
return controllers;
m_controllers.append(RamdiskController::initialize());
}
UNMAP_AFTER_INIT NonnullRefPtrVector<StorageDevice> StorageManagement::enumerate_storage_devices() const
UNMAP_AFTER_INIT void StorageManagement::enumerate_storage_devices()
{
VERIFY(!m_controllers.is_empty());
NonnullRefPtrVector<StorageDevice> devices;
for (auto& controller : m_controllers) {
for (size_t device_index = 0; device_index < controller.devices_count(); device_index++) {
auto device = controller.device(device_index);
if (device.is_null())
continue;
devices.append(device.release_nonnull());
m_storage_devices.append(device.release_nonnull());
}
}
return devices;
}
UNMAP_AFTER_INIT OwnPtr<PartitionTable> StorageManagement::try_to_initialize_partition_table(const StorageDevice& device) const
@ -99,7 +92,7 @@ UNMAP_AFTER_INIT OwnPtr<PartitionTable> StorageManagement::try_to_initialize_par
return {};
}
UNMAP_AFTER_INIT NonnullRefPtrVector<DiskPartition> StorageManagement::enumerate_disk_partitions() const
UNMAP_AFTER_INIT void StorageManagement::enumerate_disk_partitions() const
{
VERIFY(!m_storage_devices.is_empty());
NonnullRefPtrVector<DiskPartition> partitions;
@ -119,7 +112,6 @@ UNMAP_AFTER_INIT NonnullRefPtrVector<DiskPartition> StorageManagement::enumerate
}
device_index++;
}
return partitions;
}
UNMAP_AFTER_INIT void StorageManagement::determine_boot_device()
@ -141,7 +133,7 @@ UNMAP_AFTER_INIT void StorageManagement::determine_boot_device()
UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_partition_uuid()
{
VERIFY(!m_disk_partitions.is_empty());
VERIFY(!m_storage_devices.is_empty());
VERIFY(m_boot_argument.starts_with("PARTUUID="));
auto partition_uuid = UUID(m_boot_argument.substring_view(strlen("PARTUUID=")));
@ -149,20 +141,21 @@ UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_partition_uu
if (partition_uuid.to_string().length() != 36) {
PANIC("StorageManagement: Specified partition UUID is not valid");
}
for (auto& partition : m_disk_partitions) {
if (partition.metadata().unique_guid().is_zero())
continue;
if (partition.metadata().unique_guid() == partition_uuid) {
m_boot_block_device = partition;
break;
for (auto& storage_device : m_storage_devices) {
for (auto& partition : storage_device.partitions()) {
if (partition.metadata().unique_guid().is_zero())
continue;
if (partition.metadata().unique_guid() == partition_uuid) {
m_boot_block_device = partition;
break;
}
}
}
}
RefPtr<BlockDevice> StorageManagement::boot_block_device() const
{
return m_boot_block_device;
return m_boot_block_device.strong_ref();
}
int StorageManagement::major_number()
@ -171,7 +164,9 @@ int StorageManagement::major_number()
}
int StorageManagement::minor_number()
{
return s_device_minor_number++;
auto minor_number = s_device_minor_number.load();
s_device_minor_number++;
return minor_number;
}
NonnullRefPtr<FileSystem> StorageManagement::root_filesystem() const
@ -191,15 +186,18 @@ NonnullRefPtr<FileSystem> StorageManagement::root_filesystem() const
return file_system;
}
bool StorageManagement::initialized()
{
return (s_the != nullptr);
}
UNMAP_AFTER_INIT void StorageManagement::initialize(String root_device, bool force_pio)
{
VERIFY(!StorageManagement::initialized());
s_the = new StorageManagement(root_device, force_pio);
VERIFY(s_device_minor_number == 0);
m_boot_argument = root_device;
enumerate_controllers(force_pio);
enumerate_storage_devices();
enumerate_disk_partitions();
if (!boot_argument_contains_partition_uuid()) {
determine_boot_device();
return;
}
determine_boot_device_with_partition_uuid();
}
StorageManagement& StorageManagement::the()