| From a1c531477e91b2d12b66d436571b67707783f565 Mon Sep 17 00:00:00 2001 |
| From: Bart Van Assche <bvanassche@acm.org> |
| Date: Fri, 29 Jun 2012 15:34:26 +0000 |
| Subject: [PATCH] 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| drivers/scsi/scsi_lib.c | 11 +++++++++++ |
| 1 file changed, 11 insertions(+) |
| |
| diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c |
| index 6712297407bb..a7e6572940ef 100644 |
| --- a/drivers/scsi/scsi_lib.c |
| +++ b/drivers/scsi/scsi_lib.c |
| @@ -484,15 +484,26 @@ static void scsi_run_queue(struct request_queue *q) |
| */ |
| 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) |
| -- |
| 1.8.5.2 |
| |