Skip to content

Commit 3b8e0af

Browse files
committed
ata: libata-core: Fix ata_port_request_pm() locking
The function ata_port_request_pm() checks the port flag ATA_PFLAG_PM_PENDING and calls ata_port_wait_eh() if this flag is set to ensure that power management operations for a port are not scheduled simultaneously. However, this flag check is done without holding the port lock. Fix this by taking the port lock on entry to the function and checking the flag under this lock. The lock is released and re-taken if ata_port_wait_eh() needs to be called. The two WARN_ON() macros checking that the ATA_PFLAG_PM_PENDING flag was cleared are removed as the first call is racy and the second one done without holding the port lock. Fixes: 5ef4108 ("ata: add ata port system PM callbacks") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com> Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
1 parent 753a4d5 commit 3b8e0af

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

drivers/ata/libata-core.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,17 +5037,19 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
50375037
struct ata_link *link;
50385038
unsigned long flags;
50395039

5040-
/* Previous resume operation might still be in
5041-
* progress. Wait for PM_PENDING to clear.
5040+
spin_lock_irqsave(ap->lock, flags);
5041+
5042+
/*
5043+
* A previous PM operation might still be in progress. Wait for
5044+
* ATA_PFLAG_PM_PENDING to clear.
50425045
*/
50435046
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
5047+
spin_unlock_irqrestore(ap->lock, flags);
50445048
ata_port_wait_eh(ap);
5045-
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5049+
spin_lock_irqsave(ap->lock, flags);
50465050
}
50475051

5048-
/* request PM ops to EH */
5049-
spin_lock_irqsave(ap->lock, flags);
5050-
5052+
/* Request PM operation to EH */
50515053
ap->pm_mesg = mesg;
50525054
ap->pflags |= ATA_PFLAG_PM_PENDING;
50535055
ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5059,10 +5061,8 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
50595061

50605062
spin_unlock_irqrestore(ap->lock, flags);
50615063

5062-
if (!async) {
5064+
if (!async)
50635065
ata_port_wait_eh(ap);
5064-
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
5065-
}
50665066
}
50675067

50685068
/*

0 commit comments

Comments
 (0)