st: get rid of scsi_tapes array
Subsystems (2)
PATCH 3/5 st: get rid of scsi_tapes array
st currently allocates an array to store pointers to all of the scsi_tape objects. It's used to discover available indexes to use as the base for the minor number selection and later to look up scsi_tape devices for character devices.
We switch to using an IDR for minor selection and a pointer from st_modedef back to scsi_tape for the lookups.
--- drivers/scsi/st.c | 172 ++++++++++++++++++++--------------------------------- drivers/scsi/st.h | 2 + 2 files changed, 65 insertions(+), 109 deletions(-)
drivers/scsi/st.c +5 -7
@@ -37,6 +37,7 @@ static const char *verstr = "20101219";#include <linux/blkdev.h> #include <linux/moduleparam.h> #include <linux/cdev.h> +#include <linux/idr.h> #include <linux/delay.h> #include <linux/mutex.h>
@@ -81,9 +82,6 @@ static int try_direct_io = TRY_DIRECT_IO;static int try_rdio =1 ;static int try_wdio =1 ; -static int st_dev_max; -static int st_nr_dev; -extern struct class st_sysfs_class;extern struct device_attribute st_dev_attrs[];
@@ -174,13 +172,9 @@ static int debugging = DEBUG;24 bits) */ #define SET_DENS_AND_BLK 0x10001 -static DEFINE_RWLOCK (st_dev_arr_lock); -static int st_fixed_buffer_size =ST_FIXED_BUFFER_SIZE ;static int st_max_sg_segs =ST_MAX_SG ; -static struct scsi_tape **scsi_tapes =NULL ; -static int modes_defined;static int enlarge_buffer (struct st_buffer *,int ,int );
@@ -222,6 +216,10 @@ static void scsi_tape_release(struct kref *);#define to_scsi_tape (obj) container_of(obj, struct scsi_tape, kref)static DEFINE_MUTEX (st_ref_mutex); +static DEFINE_SPINLOCK (st_index_lock); +static DEFINE_SPINLOCK (st_use_lock); +static DEFINE_IDR (st_index_idr); +
#include "osst_detect.h"
@@ -239,10 +237,9 @@ static struct scsi_tape *scsi_tape_get(int dev)
struct scsi_tape *STp = NULL;
mutex_lock(&st_ref_mutex);
- write_lock(&st_dev_arr_lock);
+ spin_lock(&st_index_lock);
- if (dev < st_dev_max && scsi_tapes != NULL)
- STp = scsi_tapes[dev];
+ STp = idr_find(&st_index_idr, dev);
if (!STp) goto out;
kref_get(&STp->kref);
@@ -259,7 +256,7 @@ out_put:
kref_put(&STp->kref, scsi_tape_release);
STp = NULL;
out:
- write_unlock(&st_dev_arr_lock);
+ spin_unlock(&st_index_lock);
mutex_unlock(&st_ref_mutex);
return STp;
}
@@ -1202,12 +1199,12 @@ static int st_open(struct inode *inode, struct file *filp)
return -ENXIO;
}
- write_lock(&st_dev_arr_lock);
filp->private_data = STp;
name = tape_name(STp);
+ spin_lock(&st_use_lock);
if (STp->in_use) {
- write_unlock(&st_dev_arr_lock);
+ spin_unlock(&st_use_lock);
scsi_tape_put(STp);
mutex_unlock(&st_mutex);
DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
@@ -1215,7 +1212,7 @@ static int st_open(struct inode *inode, struct file *filp)
}
STp->in_use = 1;
- write_unlock(&st_dev_arr_lock);
+ spin_unlock(&st_use_lock);
STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
if (scsi_autopm_get_device(STp->device) < 0) {
@@ -1404,9 +1401,9 @@ static int st_release(struct inode *inode, struct file *filp)
do_door_lock(STp, 0);
normalize_buffer(STp->buffer);
- write_lock(&st_dev_arr_lock);
+ spin_lock(&st_use_lock);
STp->in_use = 0;
- write_unlock(&st_dev_arr_lock);
+ spin_unlock(&st_use_lock);
scsi_autopm_put_device(STp->device);
scsi_tape_put(STp);
@@ -4029,58 +4026,16 @@ static int st_probe(struct device *dev)
goto out_buffer_free;
}
- write_lock(&st_dev_arr_lock);
- if (st_nr_dev >= st_dev_max) {
- struct scsi_tape **tmp_da;
- int tmp_dev_max;
-
- tmp_dev_max = max(st_nr_dev * 2, 8);
- if (tmp_dev_max > ST_MAX_TAPES)
- tmp_dev_max = ST_MAX_TAPES;
- if (tmp_dev_max <= st_nr_dev) {
- write_unlock(&st_dev_arr_lock);
- printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
- ST_MAX_TAPES);
- goto out_put_disk;
- }
-
- tmp_da = kzalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC);
- if (tmp_da == NULL) {
- write_unlock(&st_dev_arr_lock);
- printk(KERN_ERR "st: Can't extend device array.\n");
- goto out_put_disk;
- }
-
- if (scsi_tapes != NULL) {
- memcpy(tmp_da, scsi_tapes,
- st_dev_max * sizeof(struct scsi_tape *));
- kfree(scsi_tapes);
- }
- scsi_tapes = tmp_da;
-
- st_dev_max = tmp_dev_max;
- }
-
- for (i = 0; i < st_dev_max; i++)
- if (scsi_tapes[i] == NULL)
- break;
- if (i >= st_dev_max)
- panic("scsi_devices corrupt (st)");
-
tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC); if (tpnt == NULL) {
- write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't allocate device descriptor.\n"); goto out_put_disk;
}
kref_init(&tpnt->kref);
tpnt->disk = disk;
- sprintf(disk->disk_name, "st%d", i);
disk->private_data = &tpnt->driver;
disk->queue = SDp->request_queue;
tpnt->driver = &st_template;
- scsi_tapes[i] = tpnt;
- dev_num = i;
tpnt->device = SDp;
if (SDp->scsi_level <= 2)
@@ -4126,6 +4081,7 @@ static int st_probe(struct device *dev)
STm->default_compression = ST_DONT_TOUCH;
STm->default_blksize = (-1); /* No forced size */
STm->default_density = (-1); /* No forced density */
+ STm->tape = tpnt;
}
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
@@ -4145,8 +4101,30 @@ static int st_probe(struct device *dev)
tpnt->blksize_changed = 0;
mutex_init(&tpnt->lock);
- st_nr_dev++;
- write_unlock(&st_dev_arr_lock);
+ if (!idr_pre_get(&st_index_idr, GFP_KERNEL)) {
+ printk(KERN_WARNING "st: idr expansion failed\n");
+ error = -ENOMEM;
+ goto out_put_disk;
+ }
+
+ spin_lock(&st_index_lock);
+ error = idr_get_new(&st_index_idr, tpnt, &dev_num);
+ spin_unlock(&st_index_lock);
+ if (error) {
+ printk(KERN_WARNING "st: idr allocation failed: %d\n", error);
+ goto out_put_disk;
+ }
+
+ if (dev_num > ST_MAX_TAPES) {
+ printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
+ ST_MAX_TAPES);
+ goto out_put_index;
+ }
+
+ tpnt->index = dev_num;
+ sprintf(disk->disk_name, "st%d", dev_num);
+
+ dev_set_drvdata(dev, tpnt);
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
STm = &(tpnt->modes[mode]);
@@ -4189,10 +4167,10 @@ static int st_probe(struct device *dev)
return 0;
out_free_tape:
+ sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
+ "tape");
for (mode=0; mode < ST_NBR_MODES; mode++) {
STm = &(tpnt->modes[mode]);
- sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
- "tape");
for (j=0; j < 2; j++) {
if (STm->cdevs[j]) {
device_destroy(&st_sysfs_class,
@@ -4202,10 +4180,8 @@ out_free_tape:
}
}
}
- write_lock(&st_dev_arr_lock);
- scsi_tapes[dev_num] = NULL;
- st_nr_dev--;
- write_unlock(&st_dev_arr_lock);
+out_put_index:
+ idr_remove(&st_index_idr, dev_num);
out_put_disk:
put_disk(disk);
kfree(tpnt);
@@ -4218,38 +4194,29 @@ out:
static int st_remove(struct device *dev)
{
- struct scsi_device *SDp = to_scsi_device(dev);
- struct scsi_tape *tpnt;
- int i, j, mode;
-
- scsi_autopm_get_device(SDp);
- write_lock(&st_dev_arr_lock);
- for (i = 0; i < st_dev_max; i++) {
- tpnt = scsi_tapes[i];
- if (tpnt != NULL && tpnt->device == SDp) {
- scsi_tapes[i] = NULL;
- st_nr_dev--;
- write_unlock(&st_dev_arr_lock);
- sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
- "tape");
- for (mode = 0; mode < ST_NBR_MODES; ++mode) {
- for (j=0; j < 2; j++) {
- device_destroy(&st_sysfs_class,
- MKDEV(SCSI_TAPE_MAJOR,
- TAPE_MINOR(i, mode, j)));
- cdev_del(tpnt->modes[mode].cdevs[j]);
- tpnt->modes[mode].cdevs[j] = NULL;
- }
- }
+ struct scsi_tape *tpnt = dev_get_drvdata(dev);
+ int rew, mode;
+ dev_t cdev_devno;
+ struct cdev *cdev;
- mutex_lock(&st_ref_mutex);
- kref_put(&tpnt->kref, scsi_tape_release);
- mutex_unlock(&st_ref_mutex);
- return 0;
+ scsi_autopm_get_device(tpnt->device);
+
+ sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape");
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ for (rew=0; rew < 2; rew++) {
+ cdev = tpnt->modes[mode].cdevs[rew];
+ if (!cdev)
+ continue;
+ cdev_devno = cdev->dev;
+ device_destroy(&st_sysfs_class, cdev_devno);
+ cdev_del(tpnt->modes[mode].cdevs[rew]);
+ tpnt->modes[mode].cdevs[rew] = NULL;
}
}
- write_unlock(&st_dev_arr_lock);
+ mutex_lock(&st_ref_mutex);
+ kref_put(&tpnt->kref, scsi_tape_release);
+ mutex_unlock(&st_ref_mutex);
return 0;
}
@@ -4336,7 +4303,6 @@ static void __exit exit_st(void)
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
class_unregister(&st_sysfs_class);
- kfree(scsi_tapes);
printk(KERN_INFO "st: Unloaded.\n");
}
@@ -4459,22 +4425,10 @@ static ssize_t
options_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct st_modedef *STm = dev_get_drvdata(dev);
- struct scsi_tape *STp;
- int i, j, options;
+ struct scsi_tape *STp = STm->tape;
+ int options;
ssize_t l = 0;
- for (i=0; i < st_dev_max; i++) {
- for (j=0; j < ST_NBR_MODES; j++)
- if (&scsi_tapes[i]->modes[j] == STm)
- break;
- if (j < ST_NBR_MODES)
- break;
- }
- if (i == st_dev_max)
- return 0; /* should never happen */
-
- STp = scsi_tapes[i];
-
options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
drivers/scsi/st.h +2 -0
@@ -66,6 +66,7 @@ struct st_modedef {unsigned char default_compression;/* 0 = don't touch, etc */ short default_density;/* Forced density, -1 = no value */ int default_blksize;/* Forced blocksize, -1 = no value */ +struct scsi_tape *tape;struct cdev *cdevs[2 ];/* Auto-rewind and non-rewind devices */ };
@@ -99,6 +100,7 @@ struct scsi_tape {struct mutex lock;/* For serialization */ struct completion wait;/* For SCSI commands */ struct st_buffer *buffer; +int index;/* Drive characteristics */ unsigned char omit_blklims;
Signature · 1 line
1.7.9.2
James Bottomley
maintainerQuoted 10 lines · Lee Duncan
st currently allocates an array to store pointers to all of the
scsi_tapeobjects. It's used to discover available indexes to use as the base for the minor number selection and later to look upscsi_tapedevices for character devices.We switch to using an IDR for minor selection and a pointer from
st_modedefback toscsi_tapefor the lookups.Signed-off-by Jeff Mahoney <[email protected]>Reviewed-by Lee Duncan <[email protected]>
This can't be Reviewed-by either. The signoff chain has to follow the transmission path of the patch. If you send me Jeff's patches, you have to add a signoff because you're a direct part of the transmission path. If Jeff sends me them, then he can give you Reviewed-by because you're not then in the direct transmission path. (Signoff is supposed to imply reviewed by anyway, so the tagging is correct in either case).
James
Ok, understood.
Quoted 23 lines · James Bottomley
Quoted 10 lines · Lee Duncan
st currently allocates an array to store pointers to all of the
scsi_tapeobjects. It's used to discover available indexes to use as the base for the minor number selection and later to look upscsi_tapedevices for character devices.We switch to using an IDR for minor selection and a pointer from
st_modedefback toscsi_tapefor the lookups.Signed-off-by Jeff Mahoney <[email protected]>Reviewed-by Lee Duncan <[email protected]>This can't be Reviewed-by either. The signoff chain has to follow the transmission path of the patch. If you send me Jeff's patches, you have to add a signoff because you're a direct part of the transmission path. If Jeff sends me them, then he can give you Reviewed-by because you're not then in the direct transmission path. (Signoff is supposed to imply reviewed by anyway, so the tagging is correct in either case).
James
Signature · 1 line
Lee Duncan