85 lines
2.9 KiB
Diff
85 lines
2.9 KiB
Diff
From: Tejun Heo <teheo@suse.de>
|
|
Subject: libata/SCSI: fix locking around blk_abort_request()
|
|
References: bnc#585927
|
|
Patch-mainline: submitted for 2.6.34-rc5 and stable (as two patches)
|
|
|
|
blk_abort_request() expects queue lock to be held by the caller.
|
|
Grab it before calling the function.
|
|
|
|
Lack of this synchronization led to infinite loop on corrupt
|
|
q->timeout_list.
|
|
|
|
Signed-off-by: Tejun Heo <teheo@suse.de>
|
|
---
|
|
drivers/ata/libata-eh.c | 4 ++++
|
|
drivers/scsi/libsas/sas_ata.c | 4 ++++
|
|
drivers/scsi/libsas/sas_scsi_host.c | 4 ++++
|
|
3 files changed, 12 insertions(+)
|
|
|
|
Index: linux-2.6.32-SLE11-SP1/drivers/ata/libata-eh.c
|
|
===================================================================
|
|
--- linux-2.6.32-SLE11-SP1.orig/drivers/ata/libata-eh.c
|
|
+++ linux-2.6.32-SLE11-SP1/drivers/ata/libata-eh.c
|
|
@@ -870,6 +870,8 @@ static void ata_eh_set_pending(struct at
|
|
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
|
|
{
|
|
struct ata_port *ap = qc->ap;
|
|
+ struct request_queue *q = qc->scsicmd->device->request_queue;
|
|
+ unsigned long flags;
|
|
|
|
WARN_ON(!ap->ops->error_handler);
|
|
|
|
@@ -881,7 +883,9 @@ void ata_qc_schedule_eh(struct ata_queue
|
|
* Note that ATA_QCFLAG_FAILED is unconditionally set after
|
|
* this function completes.
|
|
*/
|
|
+ spin_lock_irqsave(q->queue_lock, flags);
|
|
blk_abort_request(qc->scsicmd->request);
|
|
+ spin_unlock_irqrestore(q->queue_lock, flags);
|
|
}
|
|
|
|
/**
|
|
Index: linux-2.6.32-SLE11-SP1/drivers/scsi/libsas/sas_ata.c
|
|
===================================================================
|
|
--- linux-2.6.32-SLE11-SP1.orig/drivers/scsi/libsas/sas_ata.c
|
|
+++ linux-2.6.32-SLE11-SP1/drivers/scsi/libsas/sas_ata.c
|
|
@@ -394,11 +394,15 @@ int sas_ata_init_host_and_port(struct do
|
|
void sas_ata_task_abort(struct sas_task *task)
|
|
{
|
|
struct ata_queued_cmd *qc = task->uldd_task;
|
|
+ struct request_queue *q = qc->scsicmd->device->request_queue;
|
|
struct completion *waiting;
|
|
+ unsigned long flags;
|
|
|
|
/* Bounce SCSI-initiated commands to the SCSI EH */
|
|
if (qc->scsicmd) {
|
|
+ spin_lock_irqsave(q->queue_lock, flags);
|
|
blk_abort_request(qc->scsicmd->request);
|
|
+ spin_unlock_irqrestore(q->queue_lock, flags);
|
|
scsi_schedule_eh(qc->scsicmd->device->host);
|
|
return;
|
|
}
|
|
Index: linux-2.6.32-SLE11-SP1/drivers/scsi/libsas/sas_scsi_host.c
|
|
===================================================================
|
|
--- linux-2.6.32-SLE11-SP1.orig/drivers/scsi/libsas/sas_scsi_host.c
|
|
+++ linux-2.6.32-SLE11-SP1/drivers/scsi/libsas/sas_scsi_host.c
|
|
@@ -1029,6 +1029,8 @@ int __sas_task_abort(struct sas_task *ta
|
|
void sas_task_abort(struct sas_task *task)
|
|
{
|
|
struct scsi_cmnd *sc = task->uldd_task;
|
|
+ struct request_queue *q = sc->device->request_queue;
|
|
+ unsigned long flags;
|
|
|
|
/* Escape for libsas internal commands */
|
|
if (!sc) {
|
|
@@ -1043,7 +1045,9 @@ void sas_task_abort(struct sas_task *tas
|
|
return;
|
|
}
|
|
|
|
+ spin_lock_irqsave(q->queue_lock, flags);
|
|
blk_abort_request(sc->request);
|
|
+ spin_unlock_irqrestore(q->queue_lock, flags);
|
|
scsi_schedule_eh(sc->device->host);
|
|
}
|
|
|