[PATCH] scsi: ch: publish changer devices after probe setup

From: Ruoyu Wang

Date: Wed Jun 17 2026 - 14:21:33 EST


ch_probe() inserts the new changer into ch_index_idr before initializing
the kref, lock and scsi_device pointer. ch_open() looks up the object
directly from the IDR by minor, so a racing open can observe a partially
initialized changer.

Reserve the minor with a NULL IDR entry, finish device setup and element
discovery, then publish the initialized changer with idr_replace().
Early opens continue to fail with -ENXIO until the object is ready.

Signed-off-by: Ruoyu Wang <ruoyuw560@xxxxxxxxx>
---
drivers/scsi/ch.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 4010fdbf813cc..12061e4681ace 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -897,6 +897,7 @@ static int ch_probe(struct scsi_device *sd)
{
struct device *dev = &sd->sdev_gendev;
struct device *class_dev;
+ void *old;
int ret;
scsi_changer *ch;

@@ -909,7 +910,7 @@ static int ch_probe(struct scsi_device *sd)

idr_preload(GFP_KERNEL);
spin_lock(&ch_index_lock);
- ret = idr_alloc(&ch_index_idr, ch, 0, CH_MAX_DEVS + 1, GFP_NOWAIT);
+ ret = idr_alloc(&ch_index_idr, NULL, 0, CH_MAX_DEVS + 1, GFP_NOWAIT);
spin_unlock(&ch_index_lock);
idr_preload_end();

@@ -951,6 +952,15 @@ static int ch_probe(struct scsi_device *sd)
ch_init_elem(ch);

mutex_unlock(&ch->lock);
+
+ spin_lock(&ch_index_lock);
+ old = idr_replace(&ch_index_idr, ch, ch->minor);
+ spin_unlock(&ch_index_lock);
+ if (IS_ERR(old)) {
+ ret = PTR_ERR(old);
+ goto destroy_dev;
+ }
+
dev_set_drvdata(dev, ch);
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);

@@ -960,7 +970,9 @@ destroy_dev:
put_device:
scsi_device_put(sd);
remove_idr:
+ spin_lock(&ch_index_lock);
idr_remove(&ch_index_idr, ch->minor);
+ spin_unlock(&ch_index_lock);
free_ch:
kfree(ch);
return ret;
--
2.51.0