scsi: ch: add refcounting
struct scsi_changer needs refcounting as the device might be removed while the fd is still open. [mkp: whitespace] Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
db269932b9
commit
085e56766f
|
@ -105,6 +105,7 @@ do { \
|
||||||
static struct class * ch_sysfs_class;
|
static struct class * ch_sysfs_class;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
struct kref ref;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int minor;
|
int minor;
|
||||||
char name[8];
|
char name[8];
|
||||||
|
@ -563,13 +564,23 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void ch_destroy(struct kref *ref)
|
||||||
|
{
|
||||||
|
scsi_changer *ch = container_of(ref, scsi_changer, ref);
|
||||||
|
|
||||||
|
kfree(ch->dt);
|
||||||
|
kfree(ch);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ch_release(struct inode *inode, struct file *file)
|
ch_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
scsi_changer *ch = file->private_data;
|
scsi_changer *ch = file->private_data;
|
||||||
|
|
||||||
scsi_device_put(ch->device);
|
scsi_device_put(ch->device);
|
||||||
|
ch->device = NULL;
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
|
kref_put(&ch->ref, ch_destroy);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,6 +599,7 @@ ch_open(struct inode *inode, struct file *file)
|
||||||
mutex_unlock(&ch_mutex);
|
mutex_unlock(&ch_mutex);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
kref_get(&ch->ref);
|
||||||
spin_unlock(&ch_index_lock);
|
spin_unlock(&ch_index_lock);
|
||||||
|
|
||||||
file->private_data = ch;
|
file->private_data = ch;
|
||||||
|
@ -935,8 +947,11 @@ static int ch_probe(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&ch->lock);
|
mutex_init(&ch->lock);
|
||||||
|
kref_init(&ch->ref);
|
||||||
ch->device = sd;
|
ch->device = sd;
|
||||||
ch_readconfig(ch);
|
ret = ch_readconfig(ch);
|
||||||
|
if (ret)
|
||||||
|
goto destroy_dev;
|
||||||
if (init)
|
if (init)
|
||||||
ch_init_elem(ch);
|
ch_init_elem(ch);
|
||||||
|
|
||||||
|
@ -944,6 +959,8 @@ static int ch_probe(struct device *dev)
|
||||||
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
|
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
destroy_dev:
|
||||||
|
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor));
|
||||||
remove_idr:
|
remove_idr:
|
||||||
idr_remove(&ch_index_idr, ch->minor);
|
idr_remove(&ch_index_idr, ch->minor);
|
||||||
free_ch:
|
free_ch:
|
||||||
|
@ -960,8 +977,7 @@ static int ch_remove(struct device *dev)
|
||||||
spin_unlock(&ch_index_lock);
|
spin_unlock(&ch_index_lock);
|
||||||
|
|
||||||
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
|
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
|
||||||
kfree(ch->dt);
|
kref_put(&ch->ref, ch_destroy);
|
||||||
kfree(ch);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue