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:
Hannes Reinecke 2017-08-15 16:28:49 +02:00 committed by Martin K. Petersen
parent db269932b9
commit 085e56766f
1 changed files with 19 additions and 3 deletions

View File

@ -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;
} }