diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-08-25 22:01:20 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-25 22:01:20 -0400 |
commit | b8f6153ee421014f42b620238f4203a4106db309 (patch) | |
tree | ebc9eac4517325be0a91a4e2b2cb38f08d36812e /drivers/scsi/libata-core.c | |
parent | 617e44fdfd7ee3d53388ab295d9411b826437ce9 (diff) |
libata: fix EH locking
Wrap ata_qc_complete() calls in EH context in spinlocks, to prevent
races (mainly in ATAPI code paths).
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 157a3e914cb..ec7bff73ae1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2388,12 +2388,13 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct ata_port *ap = qc->ap; + unsigned long flags; - spin_lock_irq(&ap->host_set->lock); + spin_lock_irqsave(&ap->host_set->lock, flags); ap->flags &= ~ATA_FLAG_NOINTR; ata_irq_on(ap); ata_qc_complete(qc, drv_stat); - spin_unlock_irq(&ap->host_set->lock); + spin_unlock_irqrestore(&ap->host_set->lock, flags); } /** @@ -2973,8 +2974,10 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_host_set *host_set = ap->host_set; struct ata_device *dev = qc->dev; u8 host_stat = 0, drv_stat; + unsigned long flags; DPRINTK("ENTER\n"); @@ -2985,7 +2988,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) { /* finish completing original command */ + spin_lock_irqsave(&host_set->lock, flags); __ata_qc_complete(qc); + spin_unlock_irqrestore(&host_set->lock, flags); atapi_request_sense(ap, dev, cmd); @@ -2996,6 +3001,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) } } + spin_lock_irqsave(&host_set->lock, flags); + /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -3029,6 +3036,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ata_qc_complete(qc, drv_stat); break; } + + spin_unlock_irqrestore(&host_set->lock, flags); + out: DPRINTK("EXIT\n"); } |