mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
ata fixes for 6.4-rc7
- Avoid deadlocks on resume from sleep by delaying scsi rescan until the scsi device is also fully resumed. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCZI50JAAKCRDdoc3SxdoY ds+rAQCKnd8/Vmdh76a1DJTEwCQ/+2bAR0RSf6kOX8nwEUc1BgD/fhDIUBBFEWK9 nszZA2BreiTkx5iUycVn0vOedeeDoAc= =lrpe -----END PGP SIGNATURE----- Merge tag 'ata-6.4-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata Pull ata fix from Damien Le Moal: - Avoid deadlocks on resume from sleep by delaying scsi rescan until the scsi device is also fully resumed. * tag 'ata-6.4-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata: ata: libata-scsi: Avoid deadlock on rescan after device resume
This commit is contained in:
commit
ecbcffe3b7
4 changed files with 25 additions and 4 deletions
|
@ -5348,7 +5348,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
|
||||||
|
|
||||||
mutex_init(&ap->scsi_scan_mutex);
|
mutex_init(&ap->scsi_scan_mutex);
|
||||||
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
|
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
|
||||||
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
|
INIT_DELAYED_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
|
||||||
INIT_LIST_HEAD(&ap->eh_done_q);
|
INIT_LIST_HEAD(&ap->eh_done_q);
|
||||||
init_waitqueue_head(&ap->eh_wait_q);
|
init_waitqueue_head(&ap->eh_wait_q);
|
||||||
init_completion(&ap->park_req_pending);
|
init_completion(&ap->park_req_pending);
|
||||||
|
@ -5954,6 +5954,7 @@ static void ata_port_detach(struct ata_port *ap)
|
||||||
WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
|
WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
|
||||||
|
|
||||||
cancel_delayed_work_sync(&ap->hotplug_task);
|
cancel_delayed_work_sync(&ap->hotplug_task);
|
||||||
|
cancel_delayed_work_sync(&ap->scsi_rescan_task);
|
||||||
|
|
||||||
skip_eh:
|
skip_eh:
|
||||||
/* clean up zpodd on port removal */
|
/* clean up zpodd on port removal */
|
||||||
|
|
|
@ -2984,7 +2984,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
|
||||||
ehc->i.flags |= ATA_EHI_SETMODE;
|
ehc->i.flags |= ATA_EHI_SETMODE;
|
||||||
|
|
||||||
/* schedule the scsi_rescan_device() here */
|
/* schedule the scsi_rescan_device() here */
|
||||||
schedule_work(&(ap->scsi_rescan_task));
|
schedule_delayed_work(&ap->scsi_rescan_task, 0);
|
||||||
} else if (dev->class == ATA_DEV_UNKNOWN &&
|
} else if (dev->class == ATA_DEV_UNKNOWN &&
|
||||||
ehc->tries[dev->devno] &&
|
ehc->tries[dev->devno] &&
|
||||||
ata_class_enabled(ehc->classes[dev->devno])) {
|
ata_class_enabled(ehc->classes[dev->devno])) {
|
||||||
|
|
|
@ -4597,10 +4597,11 @@ int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
|
||||||
void ata_scsi_dev_rescan(struct work_struct *work)
|
void ata_scsi_dev_rescan(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ata_port *ap =
|
struct ata_port *ap =
|
||||||
container_of(work, struct ata_port, scsi_rescan_task);
|
container_of(work, struct ata_port, scsi_rescan_task.work);
|
||||||
struct ata_link *link;
|
struct ata_link *link;
|
||||||
struct ata_device *dev;
|
struct ata_device *dev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
bool delay_rescan = false;
|
||||||
|
|
||||||
mutex_lock(&ap->scsi_scan_mutex);
|
mutex_lock(&ap->scsi_scan_mutex);
|
||||||
spin_lock_irqsave(ap->lock, flags);
|
spin_lock_irqsave(ap->lock, flags);
|
||||||
|
@ -4614,6 +4615,21 @@ void ata_scsi_dev_rescan(struct work_struct *work)
|
||||||
if (scsi_device_get(sdev))
|
if (scsi_device_get(sdev))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the rescan work was scheduled because of a resume
|
||||||
|
* event, the port is already fully resumed, but the
|
||||||
|
* SCSI device may not yet be fully resumed. In such
|
||||||
|
* case, executing scsi_rescan_device() may cause a
|
||||||
|
* deadlock with the PM code on device_lock(). Prevent
|
||||||
|
* this by giving up and retrying rescan after a short
|
||||||
|
* delay.
|
||||||
|
*/
|
||||||
|
delay_rescan = sdev->sdev_gendev.power.is_suspended;
|
||||||
|
if (delay_rescan) {
|
||||||
|
scsi_device_put(sdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
scsi_rescan_device(&(sdev->sdev_gendev));
|
scsi_rescan_device(&(sdev->sdev_gendev));
|
||||||
scsi_device_put(sdev);
|
scsi_device_put(sdev);
|
||||||
|
@ -4623,4 +4639,8 @@ void ata_scsi_dev_rescan(struct work_struct *work)
|
||||||
|
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
mutex_unlock(&ap->scsi_scan_mutex);
|
mutex_unlock(&ap->scsi_scan_mutex);
|
||||||
|
|
||||||
|
if (delay_rescan)
|
||||||
|
schedule_delayed_work(&ap->scsi_rescan_task,
|
||||||
|
msecs_to_jiffies(5));
|
||||||
}
|
}
|
||||||
|
|
|
@ -836,7 +836,7 @@ struct ata_port {
|
||||||
|
|
||||||
struct mutex scsi_scan_mutex;
|
struct mutex scsi_scan_mutex;
|
||||||
struct delayed_work hotplug_task;
|
struct delayed_work hotplug_task;
|
||||||
struct work_struct scsi_rescan_task;
|
struct delayed_work scsi_rescan_task;
|
||||||
|
|
||||||
unsigned int hsm_task_state;
|
unsigned int hsm_task_state;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue