ata: libata: Document when host->eh_mutex should be held

Annotate the following functions with __must_hold(&host->eh_mutex):
 * All ata_port_operations.error_handler() implementations.
 * ata_eh_reset() and ata_eh_recover() because these functions call
   ata_eh_release() and ata_eh_acquire().
 * All callers of ata_eh_reset() and ata_eh_recover().

Enable Clang's context analysis. This will cause the build to fail if
e.g. a locking bug would be introduced in an error path. This patch
should not affect the generated assembler code.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
[cassel: drop note about clang 23 from commit log]
Signed-off-by: Niklas Cassel <cassel@kernel.org>
This commit is contained in:
Bart Van Assche
2026-05-29 11:03:10 -07:00
committed by Niklas Cassel
parent 4b3c2ca268
commit 7725c45682
21 changed files with 48 additions and 10 deletions

View File

@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
CONTEXT_ANALYSIS := y
obj-$(CONFIG_ATA) += libata.o
# non-SFF interface

View File

@@ -448,7 +448,8 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s);
int ahci_host_activate(struct ata_host *host, const struct scsi_host_template *sht);
void ahci_error_handler(struct ata_port *ap);
void ahci_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
static inline void __iomem *__ahci_port_base(struct ahci_host_priv *hpriv,

View File

@@ -598,6 +598,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
}
static void ahci_imx_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
u32 reg_val;
struct ata_device *dev;

View File

@@ -2208,6 +2208,7 @@ static void ahci_thaw(struct ata_port *ap)
}
void ahci_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ahci_host_priv *hpriv = ap->host->private_data;

View File

@@ -6835,6 +6835,7 @@ EXPORT_SYMBOL_GPL(ata_ratelimit);
* Might sleep.
*/
void ata_msleep(struct ata_port *ap, unsigned int msecs)
__context_unsafe(conditional locking)
{
bool owns_eh = ap && ap->host->eh_owner == current;
@@ -6909,6 +6910,7 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
}
static void ata_dummy_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
/* truly dummy */
}

View File

@@ -469,6 +469,7 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
* EH context.
*/
void ata_eh_acquire(struct ata_port *ap)
__acquires(&ap->host->eh_mutex)
{
mutex_lock(&ap->host->eh_mutex);
WARN_ON_ONCE(ap->host->eh_owner);
@@ -486,6 +487,7 @@ void ata_eh_acquire(struct ata_port *ap)
* EH context.
*/
void ata_eh_release(struct ata_port *ap)
__releases(&ap->host->eh_mutex)
{
WARN_ON_ONCE(ap->host->eh_owner != current);
ap->host->eh_owner = NULL;
@@ -2833,6 +2835,7 @@ static bool ata_eh_followup_srst_needed(struct ata_link *link, int rc)
int ata_eh_reset(struct ata_port *ap, struct ata_link *link, int classify,
struct ata_reset_operations *reset_ops)
__must_hold(&ap->host->eh_mutex)
{
struct ata_link *slave = ap->slave_link;
struct ata_eh_context *ehc = &link->eh_context;
@@ -3815,6 +3818,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
*/
int ata_eh_recover(struct ata_port *ap, struct ata_reset_operations *reset_ops,
struct ata_link **r_failed_link)
__must_hold(&ap->host->eh_mutex)
{
struct ata_link *link;
struct ata_device *dev;
@@ -4112,6 +4116,7 @@ void ata_eh_finish(struct ata_port *ap)
* Kernel thread context (may sleep).
*/
void ata_std_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ata_reset_operations *reset_ops = &ap->ops->reset;
struct ata_link *link = &ap->link;

View File

@@ -756,6 +756,7 @@ static int sata_pmp_revalidate_quick(struct ata_device *dev)
*/
static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
struct ata_reset_operations *reset_ops)
__must_hold(&ap->host->eh_mutex)
{
struct ata_link *link = &ap->link;
struct ata_eh_context *ehc = &link->eh_context;
@@ -921,6 +922,7 @@ static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
* 0 on success, -errno on failure.
*/
static int sata_pmp_eh_recover(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ata_port_operations *ops = ap->ops;
int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
@@ -1098,6 +1100,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
* Kernel thread context (may sleep).
*/
void sata_pmp_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
ata_eh_autopsy(ap);
ata_eh_report(ap);

View File

@@ -2053,6 +2053,7 @@ EXPORT_SYMBOL_GPL(ata_sff_drain_fifo);
* Kernel thread context (may sleep)
*/
void ata_sff_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ata_queued_cmd *qc;
unsigned long flags;
@@ -2769,6 +2770,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_interrupt);
* Kernel thread context (may sleep)
*/
void ata_bmdma_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ata_queued_cmd *qc;
unsigned long flags;

View File

@@ -173,8 +173,10 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap);
/* libata-eh.c */
extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
extern void ata_eh_acquire(struct ata_port *ap);
extern void ata_eh_release(struct ata_port *ap);
extern void ata_eh_acquire(struct ata_port *ap)
__acquires(&ap->host->eh_mutex);
extern void ata_eh_release(struct ata_port *ap)
__releases(&ap->host->eh_mutex);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_eh_fastdrain_timerfn(struct timer_list *t);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
@@ -188,10 +190,12 @@ extern void ata_eh_autopsy(struct ata_port *ap);
const char *ata_get_cmd_name(u8 command);
extern void ata_eh_report(struct ata_port *ap);
extern int ata_eh_reset(struct ata_port *ap, struct ata_link *link,
int classify, struct ata_reset_operations *reset_ops);
int classify, struct ata_reset_operations *reset_ops)
__must_hold(&ap->host->eh_mutex);
extern int ata_eh_recover(struct ata_port *ap,
struct ata_reset_operations *reset_ops,
struct ata_link **r_failed_disk);
struct ata_link **r_failed_disk)
__must_hold(&ap->host->eh_mutex);
extern void ata_eh_finish(struct ata_port *ap);
extern int ata_ering_map(struct ata_ering *ering,
int (*map_fn)(struct ata_ering_entry *, void *),

View File

@@ -658,6 +658,7 @@ static void arasan_cf_freeze(struct ata_port *ap)
}
static void arasan_cf_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct arasan_cf_dev *acdev = ap->host->private_data;

View File

@@ -1041,6 +1041,7 @@ static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
}
static void sata_dwc_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
ata_sff_error_handler(ap);
}

View File

@@ -1035,6 +1035,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
}
static void sata_fsl_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
sata_pmp_error_handler(ap);
}

View File

@@ -660,6 +660,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
}
static void inic_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
void __iomem *port_base = inic_port_base(ap);

View File

@@ -2398,6 +2398,7 @@ static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
}
static void mv_pmp_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
unsigned int pmp, pmp_map;
struct mv_port_priv *pp = ap->private_data;

View File

@@ -1626,6 +1626,7 @@ static void nv_mcp55_thaw(struct ata_port *ap)
}
static void nv_adma_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct nv_adma_port_priv *pp = ap->private_data;
if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
@@ -1795,6 +1796,7 @@ static void nv_swncq_ncq_stop(struct ata_port *ap)
}
static void nv_swncq_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct ata_eh_context *ehc = &ap->link.eh_context;

View File

@@ -816,6 +816,7 @@ static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
}
static void pdc_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
if (!ata_port_is_frozen(ap))
pdc_reset_port(ap);

View File

@@ -220,6 +220,7 @@ static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
}
static void qs_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
qs_enter_reg_mode(ap);
ata_sff_error_handler(ap);

View File

@@ -1171,6 +1171,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
}
static void sil24_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct sil24_port_priv *pp = ap->private_data;

View File

@@ -853,6 +853,7 @@ static int pdc_softreset(struct ata_link *link, unsigned int *class,
}
static void pdc_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
if (!ata_port_is_frozen(ap))
pdc_reset_port(ap);

View File

@@ -573,6 +573,7 @@ static irqreturn_t vt642x_interrupt(int irq, void *dev_instance)
}
static void vt6421_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex)
{
struct svia_priv *hpriv = ap->host->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);

View File

@@ -984,7 +984,8 @@ struct ata_port_operations {
void (*thaw)(struct ata_port *ap);
struct ata_reset_operations reset;
struct ata_reset_operations pmp_reset;
void (*error_handler)(struct ata_port *ap);
void (*error_handler)(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
void (*lost_interrupt)(struct ata_port *ap);
void (*post_internal_cmd)(struct ata_queued_cmd *qc);
void (*sched_eh)(struct ata_port *ap);
@@ -1419,7 +1420,8 @@ extern void ata_eh_thaw_port(struct ata_port *ap);
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
extern void ata_std_error_handler(struct ata_port *ap);
extern void ata_std_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
extern void ata_std_sched_eh(struct ata_port *ap);
extern void ata_std_end_eh(struct ata_port *ap);
extern int ata_link_nr_enabled(struct ata_link *link);
@@ -1999,7 +2001,8 @@ extern void ata_timing_merge(const struct ata_timing *,
extern const struct ata_port_operations sata_pmp_port_ops;
extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc);
extern void sata_pmp_error_handler(struct ata_port *ap);
extern void sata_pmp_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
#else /* CONFIG_SATA_PMP */
@@ -2063,7 +2066,8 @@ extern int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
extern void ata_sff_postreset(struct ata_link *link, unsigned int *classes);
extern void ata_sff_drain_fifo(struct ata_queued_cmd *qc);
extern void ata_sff_error_handler(struct ata_port *ap);
extern void ata_sff_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
extern void ata_sff_std_ports(struct ata_ioports *ioaddr);
#ifdef CONFIG_PCI
extern int ata_pci_sff_init_host(struct ata_host *host);
@@ -2093,7 +2097,8 @@ extern enum ata_completion_errors ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *
extern unsigned int ata_bmdma_port_intr(struct ata_port *ap,
struct ata_queued_cmd *qc);
extern irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance);
extern void ata_bmdma_error_handler(struct ata_port *ap);
extern void ata_bmdma_error_handler(struct ata_port *ap)
__must_hold(&ap->host->eh_mutex);
extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc);
extern void ata_bmdma_irq_clear(struct ata_port *ap);
extern void ata_bmdma_setup(struct ata_queued_cmd *qc);