aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-11-04 14:44:41 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2005-11-05 10:52:24 -0500
commit39b7f1e25a412b0ef31e516cfc2fa4f40235f263 (patch)
treeff9d9c44b6199624d87af0d4776f2ecfd18f2635 /drivers/scsi/sd.c
parent0ee957cb7a8f6e4fb8c6f943dbc451957bc0c6bc (diff)
[SCSI] sd: Fix refcounting
Currently the driver takes a reference only for requests coming by way of the gendisk, not for requests coming by way of the struct device or struct scsi_device. Such requests can arrive in the rescan, flush, and shutdown pathways. The patch also makes the scsi_disk keep a reference to the underlying scsi_device, and it erases the scsi_device's pointer to the scsi_disk when the scsi_device is removed (since the pointer should no longer be used). This resolves Bugzilla entry #5237. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r--drivers/scsi/sd.c99
1 files changed, 62 insertions, 37 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 9de8e186cb69..bb5b242ac6b4 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -177,24 +177,38 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
177 return container_of(disk->private_data, struct scsi_disk, driver); 177 return container_of(disk->private_data, struct scsi_disk, driver);
178} 178}
179 179
180static struct scsi_disk *scsi_disk_get(struct gendisk *disk) 180static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
181{ 181{
182 struct scsi_disk *sdkp = NULL; 182 struct scsi_disk *sdkp = NULL;
183 183
184 if (disk->private_data) {
185 sdkp = scsi_disk(disk);
186 if (scsi_device_get(sdkp->device) == 0)
187 kref_get(&sdkp->kref);
188 else
189 sdkp = NULL;
190 }
191 return sdkp;
192}
193
194static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
195{
196 struct scsi_disk *sdkp;
197
184 down(&sd_ref_sem); 198 down(&sd_ref_sem);
185 if (disk->private_data == NULL) 199 sdkp = __scsi_disk_get(disk);
186 goto out;
187 sdkp = scsi_disk(disk);
188 kref_get(&sdkp->kref);
189 if (scsi_device_get(sdkp->device))
190 goto out_put;
191 up(&sd_ref_sem); 200 up(&sd_ref_sem);
192 return sdkp; 201 return sdkp;
202}
193 203
194 out_put: 204static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev)
195 kref_put(&sdkp->kref, scsi_disk_release); 205{
196 sdkp = NULL; 206 struct scsi_disk *sdkp;
197 out: 207
208 down(&sd_ref_sem);
209 sdkp = dev_get_drvdata(dev);
210 if (sdkp)
211 sdkp = __scsi_disk_get(sdkp->disk);
198 up(&sd_ref_sem); 212 up(&sd_ref_sem);
199 return sdkp; 213 return sdkp;
200} 214}
@@ -716,16 +730,17 @@ static int sd_sync_cache(struct scsi_device *sdp)
716 730
717static int sd_issue_flush(struct device *dev, sector_t *error_sector) 731static int sd_issue_flush(struct device *dev, sector_t *error_sector)
718{ 732{
733 int ret = 0;
719 struct scsi_device *sdp = to_scsi_device(dev); 734 struct scsi_device *sdp = to_scsi_device(dev);
720 struct scsi_disk *sdkp = dev_get_drvdata(dev); 735 struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
721 736
722 if (!sdkp) 737 if (!sdkp)
723 return -ENODEV; 738 return -ENODEV;
724 739
725 if (!sdkp->WCE) 740 if (sdkp->WCE)
726 return 0; 741 ret = sd_sync_cache(sdp);
727 742 scsi_disk_put(sdkp);
728 return sd_sync_cache(sdp); 743 return ret;
729} 744}
730 745
731static void sd_end_flush(request_queue_t *q, struct request *flush_rq) 746static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
@@ -754,23 +769,30 @@ static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
754static int sd_prepare_flush(request_queue_t *q, struct request *rq) 769static int sd_prepare_flush(request_queue_t *q, struct request *rq)
755{ 770{
756 struct scsi_device *sdev = q->queuedata; 771 struct scsi_device *sdev = q->queuedata;
757 struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev); 772 struct scsi_disk *sdkp = scsi_disk_get_from_dev(&sdev->sdev_gendev);
758 773 int ret = 0;
759 if (sdkp->WCE) { 774
760 memset(rq->cmd, 0, sizeof(rq->cmd)); 775 if (sdkp) {
761 rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; 776 if (sdkp->WCE) {
762 rq->timeout = SD_TIMEOUT; 777 memset(rq->cmd, 0, sizeof(rq->cmd));
763 rq->cmd[0] = SYNCHRONIZE_CACHE; 778 rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
764 return 1; 779 rq->timeout = SD_TIMEOUT;
780 rq->cmd[0] = SYNCHRONIZE_CACHE;
781 ret = 1;
782 }
783 scsi_disk_put(sdkp);
765 } 784 }
766 785 return ret;
767 return 0;
768} 786}
769 787
770static void sd_rescan(struct device *dev) 788static void sd_rescan(struct device *dev)
771{ 789{
772 struct scsi_disk *sdkp = dev_get_drvdata(dev); 790 struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
773 sd_revalidate_disk(sdkp->disk); 791
792 if (sdkp) {
793 sd_revalidate_disk(sdkp->disk);
794 scsi_disk_put(sdkp);
795 }
774} 796}
775 797
776 798
@@ -1561,6 +1583,7 @@ static int sd_probe(struct device *dev)
1561 if (error) 1583 if (error)
1562 goto out_put; 1584 goto out_put;
1563 1585
1586 get_device(&sdp->sdev_gendev);
1564 sdkp->device = sdp; 1587 sdkp->device = sdp;
1565 sdkp->driver = &sd_template; 1588 sdkp->driver = &sd_template;
1566 sdkp->disk = gd; 1589 sdkp->disk = gd;
@@ -1637,7 +1660,9 @@ static int sd_remove(struct device *dev)
1637 1660
1638 del_gendisk(sdkp->disk); 1661 del_gendisk(sdkp->disk);
1639 sd_shutdown(dev); 1662 sd_shutdown(dev);
1663
1640 down(&sd_ref_sem); 1664 down(&sd_ref_sem);
1665 dev_set_drvdata(dev, NULL);
1641 kref_put(&sdkp->kref, scsi_disk_release); 1666 kref_put(&sdkp->kref, scsi_disk_release);
1642 up(&sd_ref_sem); 1667 up(&sd_ref_sem);
1643 1668
@@ -1663,8 +1688,8 @@ static void scsi_disk_release(struct kref *kref)
1663 spin_unlock(&sd_index_lock); 1688 spin_unlock(&sd_index_lock);
1664 1689
1665 disk->private_data = NULL; 1690 disk->private_data = NULL;
1666
1667 put_disk(disk); 1691 put_disk(disk);
1692 put_device(&sdkp->device->sdev_gendev);
1668 1693
1669 kfree(sdkp); 1694 kfree(sdkp);
1670} 1695}
@@ -1677,18 +1702,18 @@ static void scsi_disk_release(struct kref *kref)
1677static void sd_shutdown(struct device *dev) 1702static void sd_shutdown(struct device *dev)
1678{ 1703{
1679 struct scsi_device *sdp = to_scsi_device(dev); 1704 struct scsi_device *sdp = to_scsi_device(dev);
1680 struct scsi_disk *sdkp = dev_get_drvdata(dev); 1705 struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
1681 1706
1682 if (!sdkp) 1707 if (!sdkp)
1683 return; /* this can happen */ 1708 return; /* this can happen */
1684 1709
1685 if (!sdkp->WCE) 1710 if (sdkp->WCE) {
1686 return; 1711 printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
1687 1712 sdkp->disk->disk_name);
1688 printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", 1713 sd_sync_cache(sdp);
1689 sdkp->disk->disk_name); 1714 }
1690 sd_sync_cache(sdp); 1715 scsi_disk_put(sdkp);
1691} 1716}
1692 1717
1693/** 1718/**
1694 * init_sd - entry point for this driver (both when built in or when 1719 * init_sd - entry point for this driver (both when built in or when