aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-05-26 21:54:27 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-05-26 21:54:27 -0400
commitaa8f0dc6c3dbf1cf3ff58f3e945c981be134814d (patch)
tree3e343cd5493d442d1a26dc7a421422d84698831e /drivers/scsi/libata-core.c
parentbef9c558841604116704e10b3d9ff3dbf4939423 (diff)
libata: Fix use-after-iounmap
Jens Axboe pointed out that the iounmap() call in libata was occurring too early, and some drivers (ahci, probably others) were using ioremap'd memory after it had been unmapped. The patch should address that problem by way of improving the libata driver API: * move ->host_stop() call after all ->port_stop() calls have occurred. * create default helper function ata_host_stop(), and move iounmap() call there. * add ->host_stop_prewalk() hook, use it in sata_qstor.c (hi Mark). sata_qstor appears to require the host-stop-before-port-stop ordering that existed prior to applying the attached patch.
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index ee9b96da841..2b41cd3a8ec 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3321,6 +3321,13 @@ void ata_port_stop (struct ata_port *ap)
3321 dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); 3321 dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
3322} 3322}
3323 3323
3324void ata_host_stop (struct ata_host_set *host_set)
3325{
3326 if (host_set->mmio_base)
3327 iounmap(host_set->mmio_base);
3328}
3329
3330
3324/** 3331/**
3325 * ata_host_remove - Unregister SCSI host structure with upper layers 3332 * ata_host_remove - Unregister SCSI host structure with upper layers
3326 * @ap: Port to unregister 3333 * @ap: Port to unregister
@@ -3877,10 +3884,6 @@ void ata_pci_remove_one (struct pci_dev *pdev)
3877 } 3884 }
3878 3885
3879 free_irq(host_set->irq, host_set); 3886 free_irq(host_set->irq, host_set);
3880 if (host_set->ops->host_stop)
3881 host_set->ops->host_stop(host_set);
3882 if (host_set->mmio_base)
3883 iounmap(host_set->mmio_base);
3884 3887
3885 for (i = 0; i < host_set->n_ports; i++) { 3888 for (i = 0; i < host_set->n_ports; i++) {
3886 ap = host_set->ports[i]; 3889 ap = host_set->ports[i];
@@ -3899,6 +3902,9 @@ void ata_pci_remove_one (struct pci_dev *pdev)
3899 scsi_host_put(ap->host); 3902 scsi_host_put(ap->host);
3900 } 3903 }
3901 3904
3905 if (host_set->ops->host_stop)
3906 host_set->ops->host_stop(host_set);
3907
3902 kfree(host_set); 3908 kfree(host_set);
3903 3909
3904 pci_release_regions(pdev); 3910 pci_release_regions(pdev);
@@ -3996,6 +4002,7 @@ EXPORT_SYMBOL_GPL(ata_chk_err);
3996EXPORT_SYMBOL_GPL(ata_exec_command); 4002EXPORT_SYMBOL_GPL(ata_exec_command);
3997EXPORT_SYMBOL_GPL(ata_port_start); 4003EXPORT_SYMBOL_GPL(ata_port_start);
3998EXPORT_SYMBOL_GPL(ata_port_stop); 4004EXPORT_SYMBOL_GPL(ata_port_stop);
4005EXPORT_SYMBOL_GPL(ata_host_stop);
3999EXPORT_SYMBOL_GPL(ata_interrupt); 4006EXPORT_SYMBOL_GPL(ata_interrupt);
4000EXPORT_SYMBOL_GPL(ata_qc_prep); 4007EXPORT_SYMBOL_GPL(ata_qc_prep);
4001EXPORT_SYMBOL_GPL(ata_bmdma_setup); 4008EXPORT_SYMBOL_GPL(ata_bmdma_setup);