diff options
Diffstat (limited to 'drivers/scsi/sr.c')
-rw-r--r-- | drivers/scsi/sr.c | 131 |
1 files changed, 29 insertions, 102 deletions
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index aaa54ad5f035..5ba9df334968 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -109,11 +109,6 @@ static DEFINE_SPINLOCK(sr_index_lock); static struct lock_class_key sr_bio_compl_lkclass; -/* This semaphore is used to mediate the 0->1 reference get in the - * face of object destruction (i.e. we can't allow a get on an - * object after last put) */ -static DEFINE_MUTEX(sr_ref_mutex); - static int sr_open(struct cdrom_device_info *, int); static void sr_release(struct cdrom_device_info *); @@ -143,11 +138,9 @@ static const struct cdrom_device_ops sr_dops = { .capability = SR_CAPABILITIES, }; -static void sr_kref_release(struct kref *kref); - static inline struct scsi_cd *scsi_cd(struct gendisk *disk) { - return container_of(disk->private_data, struct scsi_cd, driver); + return disk->private_data; } static int sr_runtime_suspend(struct device *dev) @@ -163,38 +156,6 @@ static int sr_runtime_suspend(struct device *dev) return 0; } -/* - * The get and put routines for the struct scsi_cd. Note this entity - * has a scsi_device pointer and owns a reference to this. - */ -static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) -{ - struct scsi_cd *cd = NULL; - - mutex_lock(&sr_ref_mutex); - if (disk->private_data == NULL) - goto out; - cd = scsi_cd(disk); - kref_get(&cd->kref); - if (scsi_device_get(cd->device)) { - kref_put(&cd->kref, sr_kref_release); - cd = NULL; - } - out: - mutex_unlock(&sr_ref_mutex); - return cd; -} - -static void scsi_cd_put(struct scsi_cd *cd) -{ - struct scsi_device *sdev = cd->device; - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - scsi_device_put(sdev); - mutex_unlock(&sr_ref_mutex); -} - static unsigned int sr_get_events(struct scsi_device *sdev) { u8 buf[8]; @@ -522,15 +483,13 @@ static void sr_revalidate_disk(struct scsi_cd *cd) static int sr_block_open(struct block_device *bdev, fmode_t mode) { - struct scsi_cd *cd; - struct scsi_device *sdev; - int ret = -ENXIO; + struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + struct scsi_device *sdev = cd->device; + int ret; - cd = scsi_cd_get(bdev->bd_disk); - if (!cd) - goto out; + if (scsi_device_get(cd->device)) + return -ENXIO; - sdev = cd->device; scsi_autopm_get_device(sdev); if (bdev_check_media_change(bdev)) sr_revalidate_disk(cd); @@ -541,9 +500,7 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode) scsi_autopm_put_device(sdev); if (ret) - scsi_cd_put(cd); - -out: + scsi_device_put(cd->device); return ret; } @@ -555,7 +512,7 @@ static void sr_block_release(struct gendisk *disk, fmode_t mode) cdrom_release(&cd->cdi, mode); mutex_unlock(&cd->lock); - scsi_cd_put(cd); + scsi_device_put(cd->device); } static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, @@ -595,18 +552,24 @@ out: static unsigned int sr_block_check_events(struct gendisk *disk, unsigned int clearing) { - unsigned int ret = 0; - struct scsi_cd *cd; + struct scsi_cd *cd = disk->private_data; - cd = scsi_cd_get(disk); - if (!cd) + if (atomic_read(&cd->device->disk_events_disable_depth)) return 0; + return cdrom_check_events(&cd->cdi, clearing); +} - if (!atomic_read(&cd->device->disk_events_disable_depth)) - ret = cdrom_check_events(&cd->cdi, clearing); +static void sr_free_disk(struct gendisk *disk) +{ + struct scsi_cd *cd = disk->private_data; - scsi_cd_put(cd); - return ret; + spin_lock(&sr_index_lock); + clear_bit(MINOR(disk_devt(disk)), sr_index_bits); + spin_unlock(&sr_index_lock); + + unregister_cdrom(&cd->cdi); + mutex_destroy(&cd->lock); + kfree(cd); } static const struct block_device_operations sr_bdops = @@ -617,6 +580,7 @@ static const struct block_device_operations sr_bdops = .ioctl = sr_block_ioctl, .compat_ioctl = blkdev_compat_ptr_ioctl, .check_events = sr_block_check_events, + .free_disk = sr_free_disk, }; static int sr_open(struct cdrom_device_info *cdi, int purpose) @@ -660,8 +624,6 @@ static int sr_probe(struct device *dev) if (!cd) goto fail; - kref_init(&cd->kref); - disk = __alloc_disk_node(sdev->request_queue, NUMA_NO_NODE, &sr_bio_compl_lkclass); if (!disk) @@ -692,7 +654,6 @@ static int sr_probe(struct device *dev) cd->device = sdev; cd->disk = disk; - cd->driver = &sr_template; cd->capacity = 0x1fffff; cd->device->changed = 1; /* force recheck CD type */ cd->media_present = 1; @@ -713,7 +674,7 @@ static int sr_probe(struct device *dev) sr_vendor_init(cd); set_capacity(disk, cd->capacity); - disk->private_data = &cd->driver; + disk->private_data = cd; if (register_cdrom(disk, &cd->cdi)) goto fail_minor; @@ -728,10 +689,8 @@ static int sr_probe(struct device *dev) sr_revalidate_disk(cd); error = device_add_disk(&sdev->sdev_gendev, disk, NULL); - if (error) { - kref_put(&cd->kref, sr_kref_release); - goto fail; - } + if (error) + goto unregister_cdrom; sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); @@ -739,6 +698,8 @@ static int sr_probe(struct device *dev) return 0; +unregister_cdrom: + unregister_cdrom(&cd->cdi); fail_minor: spin_lock(&sr_index_lock); clear_bit(minor, sr_index_bits); @@ -1010,36 +971,6 @@ out_put_request: return ret; } - -/** - * sr_kref_release - Called to free the scsi_cd structure - * @kref: pointer to embedded kref - * - * sr_ref_mutex must be held entering this routine. Because it is - * called on last put, you should always use the scsi_cd_get() - * scsi_cd_put() helpers which manipulate the semaphore directly - * and never do a direct kref_put(). - **/ -static void sr_kref_release(struct kref *kref) -{ - struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref); - struct gendisk *disk = cd->disk; - - spin_lock(&sr_index_lock); - clear_bit(MINOR(disk_devt(disk)), sr_index_bits); - spin_unlock(&sr_index_lock); - - unregister_cdrom(&cd->cdi); - - disk->private_data = NULL; - - put_disk(disk); - - mutex_destroy(&cd->lock); - - kfree(cd); -} - static int sr_remove(struct device *dev) { struct scsi_cd *cd = dev_get_drvdata(dev); @@ -1047,11 +978,7 @@ static int sr_remove(struct device *dev) scsi_autopm_get_device(cd->device); del_gendisk(cd->disk); - dev_set_drvdata(dev, NULL); - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - mutex_unlock(&sr_ref_mutex); + put_disk(cd->disk); return 0; } |