]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ata: libata: Fix ata_exec_internal()
authorBart Van Assche <bvanassche@acm.org>
Thu, 21 May 2026 17:33:29 +0000 (10:33 -0700)
committerNiklas Cassel <cassel@kernel.org>
Mon, 1 Jun 2026 17:07:37 +0000 (19:07 +0200)
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>
drivers/ata/libata-core.c

index 3d0027ec33c2a2730bc6eedced44af5041b67337..3e19a00a92393fc6134367b2c1f97aa1972e5e1a 100644 (file)
@@ -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);