summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2026-05-21 10:33:29 -0700
committerNiklas Cassel <cassel@kernel.org>2026-06-01 19:07:37 +0200
commitaa0ae1c35f7b3e9afed2324bed5f5c87ad55b92c (patch)
tree7f0f0df6a0eb5f228001507d43b4882db9d0288a /drivers/ata
parentfa0f6679c73553d3e457884759ae4c6f220a71de (diff)
downloadlinux-next-aa0ae1c35f7b3e9afed2324bed5f5c87ad55b92c.tar.gz
linux-next-aa0ae1c35f7b3e9afed2324bed5f5c87ad55b92c.zip
ata: libata: Fix ata_exec_internal()
Some but not all ata_exec_internal() calls happen from the context of the ATA error handler. Commit c0c362b60e25 ("libata: implement cross-port EH exclusion") added ata_eh_release() and ata_eh_acquire() calls in ata_exec_internal(). Calling these functions is necessary if the caller holds the eh_mutex but is not allowed if the caller doesn't hold that mutex. Fix this by only calling ata_eh_release() and ata_eh_acquire() if the caller holds the eh_mutex. An example of an indirect caller of ata_exec_internal() that does not hold the eh_mutex is ata_host_register(). Fixes: c0c362b60e25 ("libata: implement cross-port EH exclusion") Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Niklas Cassel <cassel@kernel.org> Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@kernel.org> Signed-off-by: Niklas Cassel <cassel@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-core.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3d0027ec33c2..3e19a00a9239 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1540,6 +1540,7 @@ unsigned int ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf,
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
+ const bool owns_eh_mutex = ap->host->eh_owner == current;
u8 command = tf->command;
struct ata_queued_cmd *qc;
struct scatterlist sgl;
@@ -1617,11 +1618,25 @@ unsigned int ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf,
}
}
- ata_eh_release(ap);
+ if (owns_eh_mutex) {
+ /*
+ * To prevent that the compiler complains about the
+ * ata_eh_release() call below.
+ */
+ __acquire(&ap->host->eh_mutex);
+ ata_eh_release(ap);
+ }
rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
- ata_eh_acquire(ap);
+ if (owns_eh_mutex) {
+ ata_eh_acquire(ap);
+ /*
+ * To prevent that the compiler complains about the above
+ * ata_eh_acquire() call.
+ */
+ __release(&ap->host->eh_mutex);
+ }
ata_sff_flush_pio_task(ap);