diff options
author | Tejun Heo <tj@kernel.org> | 2010-04-15 03:57:37 +0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-04-23 05:47:52 +0400 |
commit | fa41efdae7de61191a7bda3a00e88ef69afb5bb9 (patch) | |
tree | 6bd4a8d48bbf0e8be01304e0914a575916e2b9fc /drivers/ata | |
parent | c81eddb0e3728661d1585fbc564449c94165cc36 (diff) | |
download | linux-fa41efdae7de61191a7bda3a00e88ef69afb5bb9.tar.xz |
libata: fix locking around blk_abort_request()
blk_abort_request() expectes 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 <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: stable@kernel.org
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-eh.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9f6cfac0f2cc..9e18cc9be0d3 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -879,6 +879,8 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) 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); @@ -890,7 +892,9 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) * 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); } /** |