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:
Родитель
db269932b9
Коммит
085e56766f
|
@ -105,6 +105,7 @@ do { \
|
|||
static struct class * ch_sysfs_class;
|
||||
|
||||
typedef struct {
|
||||
struct kref ref;
|
||||
struct list_head list;
|
||||
int minor;
|
||||
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
|
||||
ch_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
scsi_changer *ch = file->private_data;
|
||||
|
||||
scsi_device_put(ch->device);
|
||||
ch->device = NULL;
|
||||
file->private_data = NULL;
|
||||
kref_put(&ch->ref, ch_destroy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -588,6 +599,7 @@ ch_open(struct inode *inode, struct file *file)
|
|||
mutex_unlock(&ch_mutex);
|
||||
return -ENXIO;
|
||||
}
|
||||
kref_get(&ch->ref);
|
||||
spin_unlock(&ch_index_lock);
|
||||
|
||||
file->private_data = ch;
|
||||
|
@ -935,8 +947,11 @@ static int ch_probe(struct device *dev)
|
|||
}
|
||||
|
||||
mutex_init(&ch->lock);
|
||||
kref_init(&ch->ref);
|
||||
ch->device = sd;
|
||||
ch_readconfig(ch);
|
||||
ret = ch_readconfig(ch);
|
||||
if (ret)
|
||||
goto destroy_dev;
|
||||
if (init)
|
||||
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);
|
||||
|
||||
return 0;
|
||||
destroy_dev:
|
||||
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor));
|
||||
remove_idr:
|
||||
idr_remove(&ch_index_idr, ch->minor);
|
||||
free_ch:
|
||||
|
@ -960,8 +977,7 @@ static int ch_remove(struct device *dev)
|
|||
spin_unlock(&ch_index_lock);
|
||||
|
||||
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
|
||||
kfree(ch->dt);
|
||||
kfree(ch);
|
||||
kref_put(&ch->ref, ch_destroy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче