[PATCH v10 01/15] ata: libata-acpi: pin the SCSI device while emitting a bay event
From: Phil Pemberton
Date: Fri Oct 09 2026 - 12:29:10 EST
ata_acpi_uevent() reads dev->sdev without taking a reference. SCSI device
removal can clear the pointer and release the device after the notifier
has obtained its kobject, leaving kobject_uevent_env() accessing freed
memory. Dock notification ordering does not exclude independent SCSI
removal, such as deletion through sysfs.
Acquire a SCSI device reference while holding ap->lock, which protects
clearing dev->sdev during removal. Emit the event and drop the reference
outside the spinlock because both operations may sleep. Preserve the
existing port-level event behavior and skip devices that cannot be pinned.
Fixes: 1253f7aabfeb ("dock: introduce .uevent for devices in dock, eg libata")
Assisted-by: LLM
Signed-off-by: Phil Pemberton <philpem@xxxxxxxxxxxxx>
---
drivers/ata/libata-acpi.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 4433f626246b..bee738b68b3f 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -149,19 +149,29 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
u32 event)
{
struct kobject *kobj = NULL;
+ struct scsi_device *sdev = NULL;
+ unsigned long flags;
char event_string[20];
char *envp[] = { event_string, NULL };
if (dev) {
- if (dev->sdev)
- kobj = &dev->sdev->sdev_gendev.kobj;
- } else
+ spin_lock_irqsave(ap->lock, flags);
+ sdev = dev->sdev;
+ if (sdev && scsi_device_get(sdev))
+ sdev = NULL;
+ spin_unlock_irqrestore(ap->lock, flags);
+ if (sdev)
+ kobj = &sdev->sdev_gendev.kobj;
+ } else {
kobj = &ap->dev->kobj;
+ }
if (kobj) {
snprintf(event_string, 20, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
+ if (sdev)
+ scsi_device_put(sdev);
}
static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
--
2.43.0