[PATCH v10 06/15] ata: libata-core: pin SCSI devices during port detach

From: Phil Pemberton

Date: Fri Oct 09 2026 - 12:33:04 EST


ata_port_detach() drops ap->lock before removing dev->sdev. Concurrent
sysfs deletion can release the device before scsi_remove_device() uses it.

Take a device reference and clear the slot under ap->lock, then remove
the saved device. Release the reference outside the lock because device
release can sleep.

Use get_device() to hold the reference during host-driver unload, when
scsi_device_get() can fail its module reference check. The SCSI core
uses the same approach for target removal.

Fixes: 84d76529c650 ("ata: libata-core: Fix port and device removal")
Link: https://lore.kernel.org/linux-ide/20260731220740.7E14E1F00ACF@xxxxxxxxxxxxxxx/
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Phil Pemberton <philpem@xxxxxxxxxxxxx>
---
drivers/ata/libata-core.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 92233fb25051..5518525357ce 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -26,6 +26,7 @@
*/

#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -6388,10 +6389,15 @@ static void ata_port_detach(struct ata_port *ap)
ata_for_each_link(link, ap, HOST_FIRST) {
ata_for_each_dev(dev, link, ALL) {
if (dev->sdev) {
+ struct scsi_device *sdev = dev->sdev;
+
+ /* The host driver may already be unloading. */
+ get_device(&sdev->sdev_gendev);
+ dev->sdev = NULL;
spin_unlock_irqrestore(ap->lock, flags);
- scsi_remove_device(dev->sdev);
+ scsi_remove_device(sdev);
+ put_device(&sdev->sdev_gendev);
spin_lock_irqsave(ap->lock, flags);
- dev->sdev = NULL;
}
}
}
--
2.43.0