sr: implement ->free_disk to simplify refcounting
Simplify the refcounting and remove the need to clear disk->private_data by implementing the ->free_disk method. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Link: https://lore.kernel.org/r/20220308055200.735835-9-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
9c63f7f6ff
commit
01d0c69853
@ -109,11 +109,6 @@ static DEFINE_SPINLOCK(sr_index_lock);
|
|||||||
|
|
||||||
static struct lock_class_key sr_bio_compl_lkclass;
|
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 int sr_open(struct cdrom_device_info *, int);
|
||||||
static void sr_release(struct cdrom_device_info *);
|
static void sr_release(struct cdrom_device_info *);
|
||||||
|
|
||||||
@ -143,8 +138,6 @@ static const struct cdrom_device_ops sr_dops = {
|
|||||||
.capability = SR_CAPABILITIES,
|
.capability = SR_CAPABILITIES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sr_kref_release(struct kref *kref);
|
|
||||||
|
|
||||||
static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
|
static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
return disk->private_data;
|
return disk->private_data;
|
||||||
@ -163,38 +156,6 @@ static int sr_runtime_suspend(struct device *dev)
|
|||||||
return 0;
|
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)
|
static unsigned int sr_get_events(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
u8 buf[8];
|
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)
|
static int sr_block_open(struct block_device *bdev, fmode_t mode)
|
||||||
{
|
{
|
||||||
struct scsi_cd *cd;
|
struct scsi_cd *cd = cd = scsi_cd(bdev->bd_disk);
|
||||||
struct scsi_device *sdev;
|
struct scsi_device *sdev = cd->device;
|
||||||
int ret = -ENXIO;
|
int ret = -ENXIO;
|
||||||
|
|
||||||
cd = scsi_cd_get(bdev->bd_disk);
|
if (scsi_device_get(cd->device))
|
||||||
if (!cd)
|
return -ENXIO;
|
||||||
goto out;
|
|
||||||
|
|
||||||
sdev = cd->device;
|
|
||||||
scsi_autopm_get_device(sdev);
|
scsi_autopm_get_device(sdev);
|
||||||
if (bdev_check_media_change(bdev))
|
if (bdev_check_media_change(bdev))
|
||||||
sr_revalidate_disk(cd);
|
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);
|
scsi_autopm_put_device(sdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
scsi_cd_put(cd);
|
scsi_device_put(cd->device);
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +512,7 @@ static void sr_block_release(struct gendisk *disk, fmode_t mode)
|
|||||||
cdrom_release(&cd->cdi, mode);
|
cdrom_release(&cd->cdi, mode);
|
||||||
mutex_unlock(&cd->lock);
|
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,
|
static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
@ -595,18 +552,24 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||||||
static unsigned int sr_block_check_events(struct gendisk *disk,
|
static unsigned int sr_block_check_events(struct gendisk *disk,
|
||||||
unsigned int clearing)
|
unsigned int clearing)
|
||||||
{
|
{
|
||||||
unsigned int ret = 0;
|
struct scsi_cd *cd = disk->private_data;
|
||||||
struct scsi_cd *cd;
|
|
||||||
|
|
||||||
cd = scsi_cd_get(disk);
|
if (atomic_read(&cd->device->disk_events_disable_depth))
|
||||||
if (!cd)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
return cdrom_check_events(&cd->cdi, clearing);
|
||||||
|
}
|
||||||
|
|
||||||
if (!atomic_read(&cd->device->disk_events_disable_depth))
|
static void sr_free_disk(struct gendisk *disk)
|
||||||
ret = cdrom_check_events(&cd->cdi, clearing);
|
{
|
||||||
|
struct scsi_cd *cd = disk->private_data;
|
||||||
|
|
||||||
scsi_cd_put(cd);
|
spin_lock(&sr_index_lock);
|
||||||
return ret;
|
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 =
|
static const struct block_device_operations sr_bdops =
|
||||||
@ -617,6 +580,7 @@ static const struct block_device_operations sr_bdops =
|
|||||||
.ioctl = sr_block_ioctl,
|
.ioctl = sr_block_ioctl,
|
||||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
.check_events = sr_block_check_events,
|
.check_events = sr_block_check_events,
|
||||||
|
.free_disk = sr_free_disk,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sr_open(struct cdrom_device_info *cdi, int purpose)
|
static int sr_open(struct cdrom_device_info *cdi, int purpose)
|
||||||
@ -660,8 +624,6 @@ static int sr_probe(struct device *dev)
|
|||||||
if (!cd)
|
if (!cd)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
kref_init(&cd->kref);
|
|
||||||
|
|
||||||
disk = __alloc_disk_node(sdev->request_queue, NUMA_NO_NODE,
|
disk = __alloc_disk_node(sdev->request_queue, NUMA_NO_NODE,
|
||||||
&sr_bio_compl_lkclass);
|
&sr_bio_compl_lkclass);
|
||||||
if (!disk)
|
if (!disk)
|
||||||
@ -727,10 +689,8 @@ static int sr_probe(struct device *dev)
|
|||||||
sr_revalidate_disk(cd);
|
sr_revalidate_disk(cd);
|
||||||
|
|
||||||
error = device_add_disk(&sdev->sdev_gendev, disk, NULL);
|
error = device_add_disk(&sdev->sdev_gendev, disk, NULL);
|
||||||
if (error) {
|
if (error)
|
||||||
kref_put(&cd->kref, sr_kref_release);
|
goto unregister_cdrom;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdev_printk(KERN_DEBUG, sdev,
|
sdev_printk(KERN_DEBUG, sdev,
|
||||||
"Attached scsi CD-ROM %s\n", cd->cdi.name);
|
"Attached scsi CD-ROM %s\n", cd->cdi.name);
|
||||||
@ -738,6 +698,8 @@ static int sr_probe(struct device *dev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
unregister_cdrom:
|
||||||
|
unregister_cdrom(&cd->cdi);
|
||||||
fail_minor:
|
fail_minor:
|
||||||
spin_lock(&sr_index_lock);
|
spin_lock(&sr_index_lock);
|
||||||
clear_bit(minor, sr_index_bits);
|
clear_bit(minor, sr_index_bits);
|
||||||
@ -1009,36 +971,6 @@ static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf,
|
|||||||
return ret;
|
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)
|
static int sr_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct scsi_cd *cd = dev_get_drvdata(dev);
|
struct scsi_cd *cd = dev_get_drvdata(dev);
|
||||||
@ -1046,11 +978,7 @@ static int sr_remove(struct device *dev)
|
|||||||
scsi_autopm_get_device(cd->device);
|
scsi_autopm_get_device(cd->device);
|
||||||
|
|
||||||
del_gendisk(cd->disk);
|
del_gendisk(cd->disk);
|
||||||
dev_set_drvdata(dev, NULL);
|
put_disk(cd->disk);
|
||||||
|
|
||||||
mutex_lock(&sr_ref_mutex);
|
|
||||||
kref_put(&cd->kref, sr_kref_release);
|
|
||||||
mutex_unlock(&sr_ref_mutex);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#ifndef _SR_H
|
#ifndef _SR_H
|
||||||
#define _SR_H
|
#define _SR_H
|
||||||
|
|
||||||
#include <linux/kref.h>
|
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
#define MAX_RETRIES 3
|
#define MAX_RETRIES 3
|
||||||
@ -51,9 +50,6 @@ typedef struct scsi_cd {
|
|||||||
|
|
||||||
struct cdrom_device_info cdi;
|
struct cdrom_device_info cdi;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
/* We hold gendisk and scsi_device references on probe and use
|
|
||||||
* the refs on this kref to decide when to release them */
|
|
||||||
struct kref kref;
|
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
} Scsi_CD;
|
} Scsi_CD;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user