From: Hannes Reinecke <hare@suse.de>
Date: Mon, 20 Apr 2015 11:37:35 +0200
Subject: [PATCH 2/2] ch: fixup refcounting imbalance for SCSI devices
References: bsc#1124235
Patch-Mainline: submitted linux-scsi 2019/03/20
The SCSI device is required to be present during 'ch_probe'
and ch_open(), but as we cannot known whether ch_release()
or ch_remove() will be called first we should blank out the
pointer to the SCSI device in ch_destroy(), not in ch_release().
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/ch.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 8f426903d7e4..08acd896d4e2 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -568,6 +568,7 @@ static void ch_destroy(struct kref *ref)
{
scsi_changer *ch = container_of(ref, scsi_changer, ref);
+ ch->device = NULL;
kfree(ch->dt);
kfree(ch);
}
@@ -579,7 +580,6 @@ ch_release(struct inode *inode, struct file *file)
mutex_lock(&ch_mutex);
scsi_device_put(ch->device);
- ch->device = NULL;
file->private_data = NULL;
mutex_unlock(&ch_mutex);
kref_put(&ch->ref, ch_destroy);
@@ -596,14 +596,17 @@ ch_open(struct inode *inode, struct file *file)
spin_lock(&ch_index_lock);
ch = idr_find(&ch_index_idr, minor);
- if (NULL == ch || scsi_device_get(ch->device)) {
+ if (NULL == ch || kref_get_unless_zero(&ch->ref)) {
spin_unlock(&ch_index_lock);
mutex_unlock(&ch_mutex);
return -ENXIO;
}
- kref_get(&ch->ref);
spin_unlock(&ch_index_lock);
+ if (!ch->device || scsi_device_get(ch->device)) {
+ kref_put(&ch->ref, ch_destroy);
+ return -ENXIO;
+ }
file->private_data = ch;
mutex_unlock(&ch_mutex);
return 0;
@@ -976,6 +979,7 @@ static int ch_remove(struct device *dev)
spin_lock(&ch_index_lock);
idr_remove(&ch_index_idr, ch->minor);
+ dev_set_drvdata(dev, NULL);
spin_unlock(&ch_index_lock);
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
--
2.16.4