aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2012-06-29 15:34:26 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-09 08:27:34 -0700
commit8add44b313360a3940e6734b96c636c8c8edc5f8 (patch)
tree21c4fcf0cfe7a86881f9560ac46305b4a76b5d2e /drivers/scsi
parent8fff2f802f32cbb0ed253117cc01586762c22ae9 (diff)
downloadkernel_samsung_smdk4412-8add44b313360a3940e6734b96c636c8c8edc5f8.tar.gz
kernel_samsung_smdk4412-8add44b313360a3940e6734b96c636c8c8edc5f8.tar.bz2
kernel_samsung_smdk4412-8add44b313360a3940e6734b96c636c8c8edc5f8.zip
SCSI: Avoid dangling pointer in scsi_requeue_command()
commit 940f5d47e2f2e1fa00443921a0abf4822335b54d upstream. When we call scsi_unprep_request() the command associated with the request gets destroyed and therefore drops its reference on the device. If this was the only reference, the device may get released and we end up with a NULL pointer deref when we call blk_requeue_request. Reported-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Reviewed-by: Tejun Heo <tj@kernel.org> [jejb: enhance commend and add commit log for stable] Signed-off-by: James Bottomley <JBottomley@Parallels.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_lib.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 99fc45bb72d..dd454c4f99a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -481,15 +481,26 @@ void scsi_requeue_run_queue(struct work_struct *work)
*/
static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
{
+ struct scsi_device *sdev = cmd->device;
struct request *req = cmd->request;
unsigned long flags;
+ /*
+ * We need to hold a reference on the device to avoid the queue being
+ * killed after the unlock and before scsi_run_queue is invoked which
+ * may happen because scsi_unprep_request() puts the command which
+ * releases its reference on the device.
+ */
+ get_device(&sdev->sdev_gendev);
+
spin_lock_irqsave(q->queue_lock, flags);
scsi_unprep_request(req);
blk_requeue_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
scsi_run_queue(q);
+
+ put_device(&sdev->sdev_gendev);
}
void scsi_next_command(struct scsi_cmnd *cmd)