Commit abfc22be authored by James Bottomley's avatar James Bottomley

Fix SCSI cdrom disconnection race

This fixes 

http://bugme.osdl.org/show_bug.cgi?id=2400
parent 05b649fb
......@@ -113,6 +113,28 @@ static struct cdrom_device_ops sr_dops = {
.generic_packet = sr_packet,
};
static void sr_kobject_release(struct kobject *kobj);
static struct kobj_type scsi_cdrom_kobj_type = {
.release = sr_kobject_release,
};
/*
* 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 int scsi_cd_get(struct scsi_cd *cd)
{
if (!kobject_get(&cd->kobj))
return -ENODEV;
return 0;
}
static inline void scsi_cd_put(struct scsi_cd *cd)
{
kobject_put(&cd->kobj);
}
/*
* This function checks to see if the media has been changed in the
* CDROM drive. It is possible that we have already sensed a change,
......@@ -424,8 +446,15 @@ static int sr_block_open(struct inode *inode, struct file *file)
static int sr_block_release(struct inode *inode, struct file *file)
{
int ret;
struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
return cdrom_release(&cd->cdi, file);
ret = cdrom_release(&cd->cdi, file);
if(ret)
return ret;
scsi_cd_put(cd);
return 0;
}
static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
......@@ -467,7 +496,7 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose)
struct scsi_device *sdev = cd->device;
int retval;
retval = scsi_device_get(sdev);
retval = scsi_cd_get(cd);
if (retval)
return retval;
......@@ -489,7 +518,7 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose)
return 0;
error_out:
scsi_device_put(sdev);
scsi_cd_put(cd);
return retval;
}
......@@ -500,7 +529,6 @@ static void sr_release(struct cdrom_device_info *cdi)
if (cd->device->sector_size > 2048)
sr_set_blocklength(cd, 2048);
scsi_device_put(cd->device);
}
static int sr_probe(struct device *dev)
......@@ -514,12 +542,18 @@ static int sr_probe(struct device *dev)
if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
goto fail;
if ((error = scsi_device_get(sdev)) != 0)
goto fail;
error = -ENOMEM;
cd = kmalloc(sizeof(*cd), GFP_KERNEL);
if (!cd)
goto fail;
goto fail_put_sdev;
memset(cd, 0, sizeof(*cd));
kobject_init(&cd->kobj);
cd->kobj.ktype = &scsi_cdrom_kobj_type;
disk = alloc_disk(1);
if (!disk)
goto fail_free;
......@@ -587,6 +621,8 @@ static int sr_probe(struct device *dev)
put_disk(disk);
fail_free:
kfree(cd);
fail_put_sdev:
scsi_device_put(sdev);
fail:
return error;
}
......@@ -862,20 +898,32 @@ static int sr_packet(struct cdrom_device_info *cdi,
return cgc->stat;
}
static int sr_remove(struct device *dev)
static void sr_kobject_release(struct kobject *kobj)
{
struct scsi_cd *cd = dev_get_drvdata(dev);
del_gendisk(cd->disk);
struct scsi_cd *cd = container_of(kobj, struct scsi_cd, kobj);
struct scsi_device *sdev = cd->device;
spin_lock(&sr_index_lock);
clear_bit(cd->disk->first_minor, sr_index_bits);
spin_unlock(&sr_index_lock);
put_disk(cd->disk);
unregister_cdrom(&cd->cdi);
put_disk(cd->disk);
kfree(cd);
scsi_device_put(sdev);
}
static int sr_remove(struct device *dev)
{
struct scsi_cd *cd = dev_get_drvdata(dev);
del_gendisk(cd->disk);
scsi_cd_put(cd);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment