From: Bart Van Assche Date: Fri, 29 May 2026 18:03:10 +0000 (-0700) Subject: ata: libata: Document when host->eh_mutex should be held X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7725c45682abd7a6590676c33c35a7bdfdec6db5;p=thirdparty%2Fkernel%2Flinux.git 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 [cassel: drop note about clang 23 from commit log] Signed-off-by: Niklas Cassel --- diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 20e6645ab7371..b96025abd45e3 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +CONTEXT_ANALYSIS := y + obj-$(CONFIG_ATA) += libata.o # non-SFF interface diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 9e8b6319025c4..b57cca352faa7 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -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, diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 3d26595524d3e..6aaa18e29abc6 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -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; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index e0af4b5716b3f..6d72eb017b498 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -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; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3e19a00a92393..f68882706fdca 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -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 */ } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ecfb9d96249f6..05df7ea6954a9 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -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; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index ffd6549960674..736eaf0586f7d 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -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); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 785b6e371abfb..734e7c88439a7 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -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; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a5920c10aacaf..d0b0ecd3d0867 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -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 *), diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index a77fefd320c26..e05a4847e0371 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -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; diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 64cb544903d88..4fc22ce4bd9aa 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -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); } diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index be829fcc584de..70b210afd2911 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1035,6 +1035,7 @@ err: } static void sata_fsl_error_handler(struct ata_port *ap) + __must_hold(&ap->host->eh_mutex) { sata_pmp_error_handler(ap); } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 46a8c20daf180..065408975f5b5 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -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); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index ffb396f61731f..f6942fd80bae7 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -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; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 841e7de2bba6e..19b9270658686 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -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; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 2a005aede123d..c5fad448bafcd 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -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); diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index cfb9b5b61cd7e..1add7a7d5ff60 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -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); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 57f1081b86db3..b4549ba968a48 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -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; diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 0986ebd1eb4e5..227dc1d4e85bd 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -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); diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 68e9003ec2d47..b672a1e058674 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -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); diff --git a/include/linux/libata.h b/include/linux/libata.h index 127229fbd1a63..7091bc903c05f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -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);