diff options
| author | Mike Snitzer <snitzer@redhat.com> | 2011-04-08 15:05:36 -0400 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2011-04-24 12:02:09 -0400 |
| commit | 0b8393578c70bc1f09790eeae7d918f38da2e010 (patch) | |
| tree | 0d1ba0f9e3470800e69753e5f228b733af7205ed | |
| parent | a1f74ae82d133ebb2aabb19d181944b4e83e9960 (diff) | |
[SCSI] scsi_dh: fix reference counting in scsi_dh_activate error path
Commit db422318cbca55168cf965f655471dbf8be82433 ([SCSI] scsi_dh:
propagate SCSI device deletion) introduced a regression where the device
reference is not dropped prior to scsi_dh_activate's early return from
the error path.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@kernel.org # 2.6.38
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
| -rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 564e6ecd17c2..0119b8147797 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
| @@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) | |||
| 394 | unsigned long flags; | 394 | unsigned long flags; |
| 395 | struct scsi_device *sdev; | 395 | struct scsi_device *sdev; |
| 396 | struct scsi_device_handler *scsi_dh = NULL; | 396 | struct scsi_device_handler *scsi_dh = NULL; |
| 397 | struct device *dev = NULL; | ||
| 397 | 398 | ||
| 398 | spin_lock_irqsave(q->queue_lock, flags); | 399 | spin_lock_irqsave(q->queue_lock, flags); |
| 399 | sdev = q->queuedata; | 400 | sdev = q->queuedata; |
| 400 | if (sdev && sdev->scsi_dh_data) | 401 | if (sdev && sdev->scsi_dh_data) |
| 401 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | 402 | scsi_dh = sdev->scsi_dh_data->scsi_dh; |
| 402 | if (!scsi_dh || !get_device(&sdev->sdev_gendev) || | 403 | dev = get_device(&sdev->sdev_gendev); |
| 404 | if (!scsi_dh || !dev || | ||
| 403 | sdev->sdev_state == SDEV_CANCEL || | 405 | sdev->sdev_state == SDEV_CANCEL || |
| 404 | sdev->sdev_state == SDEV_DEL) | 406 | sdev->sdev_state == SDEV_DEL) |
| 405 | err = SCSI_DH_NOSYS; | 407 | err = SCSI_DH_NOSYS; |
| @@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) | |||
| 410 | if (err) { | 412 | if (err) { |
| 411 | if (fn) | 413 | if (fn) |
| 412 | fn(data, err); | 414 | fn(data, err); |
| 413 | return err; | 415 | goto out; |
| 414 | } | 416 | } |
| 415 | 417 | ||
| 416 | if (scsi_dh->activate) | 418 | if (scsi_dh->activate) |
| 417 | err = scsi_dh->activate(sdev, fn, data); | 419 | err = scsi_dh->activate(sdev, fn, data); |
| 418 | put_device(&sdev->sdev_gendev); | 420 | out: |
| 421 | put_device(dev); | ||
| 419 | return err; | 422 | return err; |
| 420 | } | 423 | } |
| 421 | EXPORT_SYMBOL_GPL(scsi_dh_activate); | 424 | EXPORT_SYMBOL_GPL(scsi_dh_activate); |
