hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/drivers/scsi/ch.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * SCSI Media Changer device driver for Linux 2.6
34 *
....@@ -43,7 +44,6 @@
4344 MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
4445 MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER);
4546
46
-static DEFINE_MUTEX(ch_mutex);
4747 static int init = 1;
4848 module_param(init, int, 0444);
4949 MODULE_PARM_DESC(init, \
....@@ -568,6 +568,7 @@
568568 {
569569 scsi_changer *ch = container_of(ref, scsi_changer, ref);
570570
571
+ ch->device = NULL;
571572 kfree(ch->dt);
572573 kfree(ch);
573574 }
....@@ -589,20 +590,22 @@
589590 scsi_changer *ch;
590591 int minor = iminor(inode);
591592
592
- mutex_lock(&ch_mutex);
593593 spin_lock(&ch_index_lock);
594594 ch = idr_find(&ch_index_idr, minor);
595595
596
- if (NULL == ch || scsi_device_get(ch->device)) {
596
+ if (ch == NULL || !kref_get_unless_zero(&ch->ref)) {
597597 spin_unlock(&ch_index_lock);
598
- mutex_unlock(&ch_mutex);
599598 return -ENXIO;
600599 }
601
- kref_get(&ch->ref);
602600 spin_unlock(&ch_index_lock);
603
-
601
+ if (scsi_device_get(ch->device)) {
602
+ kref_put(&ch->ref, ch_destroy);
603
+ return -ENXIO;
604
+ }
605
+ /* Synchronize with ch_probe() */
606
+ mutex_lock(&ch->lock);
604607 file->private_data = ch;
605
- mutex_unlock(&ch_mutex);
608
+ mutex_unlock(&ch->lock);
606609 return 0;
607610 }
608611
....@@ -871,6 +874,10 @@
871874 unsigned int cmd, unsigned long arg)
872875 {
873876 scsi_changer *ch = file->private_data;
877
+ int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
878
+ file->f_flags & O_NDELAY);
879
+ if (retval)
880
+ return retval;
874881
875882 switch (cmd) {
876883 case CHIOGPARAMS:
....@@ -882,7 +889,7 @@
882889 case CHIOINITELEM:
883890 case CHIOSVOLTAG:
884891 /* compatible */
885
- return ch_ioctl(file, cmd, arg);
892
+ return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
886893 case CHIOGSTATUS32:
887894 {
888895 struct changer_element_status32 ces32;
....@@ -897,8 +904,7 @@
897904 return ch_gstatus(ch, ces32.ces_type, data);
898905 }
899906 default:
900
- // return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
901
- return -ENOIOCTLCMD;
907
+ return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
902908
903909 }
904910 }
....@@ -934,7 +940,16 @@
934940
935941 ch->minor = ret;
936942 sprintf(ch->name,"ch%d",ch->minor);
943
+ ret = scsi_device_get(sd);
944
+ if (ret) {
945
+ sdev_printk(KERN_WARNING, sd, "ch%d: failed to get device\n",
946
+ ch->minor);
947
+ goto remove_idr;
948
+ }
937949
950
+ mutex_init(&ch->lock);
951
+ kref_init(&ch->ref);
952
+ ch->device = sd;
938953 class_dev = device_create(ch_sysfs_class, dev,
939954 MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch,
940955 "s%s", ch->name);
....@@ -942,24 +957,27 @@
942957 sdev_printk(KERN_WARNING, sd, "ch%d: device_create failed\n",
943958 ch->minor);
944959 ret = PTR_ERR(class_dev);
945
- goto remove_idr;
960
+ goto put_device;
946961 }
947962
948
- mutex_init(&ch->lock);
949
- kref_init(&ch->ref);
950
- ch->device = sd;
963
+ mutex_lock(&ch->lock);
951964 ret = ch_readconfig(ch);
952
- if (ret)
965
+ if (ret) {
966
+ mutex_unlock(&ch->lock);
953967 goto destroy_dev;
968
+ }
954969 if (init)
955970 ch_init_elem(ch);
956971
972
+ mutex_unlock(&ch->lock);
957973 dev_set_drvdata(dev, ch);
958974 sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
959975
960976 return 0;
961977 destroy_dev:
962978 device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor));
979
+put_device:
980
+ scsi_device_put(sd);
963981 remove_idr:
964982 idr_remove(&ch_index_idr, ch->minor);
965983 free_ch:
....@@ -973,9 +991,11 @@
973991
974992 spin_lock(&ch_index_lock);
975993 idr_remove(&ch_index_idr, ch->minor);
994
+ dev_set_drvdata(dev, NULL);
976995 spin_unlock(&ch_index_lock);
977996
978997 device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
998
+ scsi_device_put(ch->device);
979999 kref_put(&ch->ref, ch_destroy);
9801000 return 0;
9811001 }