[SCSI] 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. Reviewed-by: Lee Duncan <lduncan@suse.com> Signed-off-by: Jeff Mahoney <jeffm@suse.com> Acked-by: Kai Mäkisara <kai.makisara@kolumbus.fi> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
e3f2a9cc84
commit
6c648d95a6
|
@ -37,6 +37,7 @@ static const char *verstr = "20101219";
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/mutex.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_rdio = 1;
|
||||||
static int try_wdio = 1;
|
static int try_wdio = 1;
|
||||||
|
|
||||||
static int st_dev_max;
|
|
||||||
static int st_nr_dev;
|
|
||||||
|
|
||||||
static struct class st_sysfs_class;
|
static struct class st_sysfs_class;
|
||||||
static struct device_attribute st_dev_attrs[];
|
static struct device_attribute st_dev_attrs[];
|
||||||
|
|
||||||
|
@ -174,13 +172,9 @@ static int debugging = DEBUG;
|
||||||
24 bits) */
|
24 bits) */
|
||||||
#define SET_DENS_AND_BLK 0x10001
|
#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_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
|
||||||
static int st_max_sg_segs = ST_MAX_SG;
|
static int st_max_sg_segs = ST_MAX_SG;
|
||||||
|
|
||||||
static struct scsi_tape **scsi_tapes = NULL;
|
|
||||||
|
|
||||||
static int modes_defined;
|
static int modes_defined;
|
||||||
|
|
||||||
static int enlarge_buffer(struct st_buffer *, int, int);
|
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)
|
#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
|
||||||
|
|
||||||
static DEFINE_MUTEX(st_ref_mutex);
|
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"
|
#include "osst_detect.h"
|
||||||
|
@ -239,10 +237,9 @@ static struct scsi_tape *scsi_tape_get(int dev)
|
||||||
struct scsi_tape *STp = NULL;
|
struct scsi_tape *STp = NULL;
|
||||||
|
|
||||||
mutex_lock(&st_ref_mutex);
|
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 = idr_find(&st_index_idr, dev);
|
||||||
STp = scsi_tapes[dev];
|
|
||||||
if (!STp) goto out;
|
if (!STp) goto out;
|
||||||
|
|
||||||
kref_get(&STp->kref);
|
kref_get(&STp->kref);
|
||||||
|
@ -259,7 +256,7 @@ out_put:
|
||||||
kref_put(&STp->kref, scsi_tape_release);
|
kref_put(&STp->kref, scsi_tape_release);
|
||||||
STp = NULL;
|
STp = NULL;
|
||||||
out:
|
out:
|
||||||
write_unlock(&st_dev_arr_lock);
|
spin_unlock(&st_index_lock);
|
||||||
mutex_unlock(&st_ref_mutex);
|
mutex_unlock(&st_ref_mutex);
|
||||||
return STp;
|
return STp;
|
||||||
}
|
}
|
||||||
|
@ -1202,12 +1199,12 @@ static int st_open(struct inode *inode, struct file *filp)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock(&st_dev_arr_lock);
|
|
||||||
filp->private_data = STp;
|
filp->private_data = STp;
|
||||||
name = tape_name(STp);
|
name = tape_name(STp);
|
||||||
|
|
||||||
|
spin_lock(&st_use_lock);
|
||||||
if (STp->in_use) {
|
if (STp->in_use) {
|
||||||
write_unlock(&st_dev_arr_lock);
|
spin_unlock(&st_use_lock);
|
||||||
scsi_tape_put(STp);
|
scsi_tape_put(STp);
|
||||||
mutex_unlock(&st_mutex);
|
mutex_unlock(&st_mutex);
|
||||||
DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
|
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;
|
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;
|
STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
|
||||||
|
|
||||||
if (scsi_autopm_get_device(STp->device) < 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);
|
do_door_lock(STp, 0);
|
||||||
|
|
||||||
normalize_buffer(STp->buffer);
|
normalize_buffer(STp->buffer);
|
||||||
write_lock(&st_dev_arr_lock);
|
spin_lock(&st_use_lock);
|
||||||
STp->in_use = 0;
|
STp->in_use = 0;
|
||||||
write_unlock(&st_dev_arr_lock);
|
spin_unlock(&st_use_lock);
|
||||||
scsi_autopm_put_device(STp->device);
|
scsi_autopm_put_device(STp->device);
|
||||||
scsi_tape_put(STp);
|
scsi_tape_put(STp);
|
||||||
|
|
||||||
|
@ -4029,58 +4026,16 @@ static int st_probe(struct device *dev)
|
||||||
goto out_buffer_free;
|
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);
|
tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
|
||||||
if (tpnt == NULL) {
|
if (tpnt == NULL) {
|
||||||
write_unlock(&st_dev_arr_lock);
|
|
||||||
printk(KERN_ERR "st: Can't allocate device descriptor.\n");
|
printk(KERN_ERR "st: Can't allocate device descriptor.\n");
|
||||||
goto out_put_disk;
|
goto out_put_disk;
|
||||||
}
|
}
|
||||||
kref_init(&tpnt->kref);
|
kref_init(&tpnt->kref);
|
||||||
tpnt->disk = disk;
|
tpnt->disk = disk;
|
||||||
sprintf(disk->disk_name, "st%d", i);
|
|
||||||
disk->private_data = &tpnt->driver;
|
disk->private_data = &tpnt->driver;
|
||||||
disk->queue = SDp->request_queue;
|
disk->queue = SDp->request_queue;
|
||||||
tpnt->driver = &st_template;
|
tpnt->driver = &st_template;
|
||||||
scsi_tapes[i] = tpnt;
|
|
||||||
dev_num = i;
|
|
||||||
|
|
||||||
tpnt->device = SDp;
|
tpnt->device = SDp;
|
||||||
if (SDp->scsi_level <= 2)
|
if (SDp->scsi_level <= 2)
|
||||||
|
@ -4126,6 +4081,7 @@ static int st_probe(struct device *dev)
|
||||||
STm->default_compression = ST_DONT_TOUCH;
|
STm->default_compression = ST_DONT_TOUCH;
|
||||||
STm->default_blksize = (-1); /* No forced size */
|
STm->default_blksize = (-1); /* No forced size */
|
||||||
STm->default_density = (-1); /* No forced density */
|
STm->default_density = (-1); /* No forced density */
|
||||||
|
STm->tape = tpnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
|
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
|
||||||
|
@ -4145,8 +4101,29 @@ static int st_probe(struct device *dev)
|
||||||
tpnt->blksize_changed = 0;
|
tpnt->blksize_changed = 0;
|
||||||
mutex_init(&tpnt->lock);
|
mutex_init(&tpnt->lock);
|
||||||
|
|
||||||
st_nr_dev++;
|
if (!idr_pre_get(&st_index_idr, GFP_KERNEL)) {
|
||||||
write_unlock(&st_dev_arr_lock);
|
pr_warn("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) {
|
||||||
|
pr_warn("st: idr allocation failed: %d\n", error);
|
||||||
|
goto out_put_disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_num > ST_MAX_TAPES) {
|
||||||
|
pr_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) {
|
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
|
||||||
STm = &(tpnt->modes[mode]);
|
STm = &(tpnt->modes[mode]);
|
||||||
|
@ -4189,10 +4166,10 @@ static int st_probe(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free_tape:
|
out_free_tape:
|
||||||
|
sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
|
||||||
|
"tape");
|
||||||
for (mode=0; mode < ST_NBR_MODES; mode++) {
|
for (mode=0; mode < ST_NBR_MODES; mode++) {
|
||||||
STm = &(tpnt->modes[mode]);
|
STm = &(tpnt->modes[mode]);
|
||||||
sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
|
|
||||||
"tape");
|
|
||||||
for (j=0; j < 2; j++) {
|
for (j=0; j < 2; j++) {
|
||||||
if (STm->cdevs[j]) {
|
if (STm->cdevs[j]) {
|
||||||
device_destroy(&st_sysfs_class,
|
device_destroy(&st_sysfs_class,
|
||||||
|
@ -4202,10 +4179,10 @@ out_free_tape:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_lock(&st_dev_arr_lock);
|
out_put_index:
|
||||||
scsi_tapes[dev_num] = NULL;
|
spin_lock(&st_index_lock);
|
||||||
st_nr_dev--;
|
idr_remove(&st_index_idr, dev_num);
|
||||||
write_unlock(&st_dev_arr_lock);
|
spin_unlock(&st_index_lock);
|
||||||
out_put_disk:
|
out_put_disk:
|
||||||
put_disk(disk);
|
put_disk(disk);
|
||||||
kfree(tpnt);
|
kfree(tpnt);
|
||||||
|
@ -4218,38 +4195,32 @@ out:
|
||||||
|
|
||||||
static int st_remove(struct device *dev)
|
static int st_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct scsi_device *SDp = to_scsi_device(dev);
|
struct scsi_tape *tpnt = dev_get_drvdata(dev);
|
||||||
struct scsi_tape *tpnt;
|
int rew, mode;
|
||||||
int i, j, mode;
|
dev_t cdev_devno;
|
||||||
|
struct cdev *cdev;
|
||||||
|
int index = tpnt->index;
|
||||||
|
|
||||||
scsi_autopm_get_device(SDp);
|
scsi_autopm_get_device(to_scsi_device(dev));
|
||||||
write_lock(&st_dev_arr_lock);
|
sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape");
|
||||||
for (i = 0; i < st_dev_max; i++) {
|
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
|
||||||
tpnt = scsi_tapes[i];
|
for (rew = 0; rew < 2; rew++) {
|
||||||
if (tpnt != NULL && tpnt->device == SDp) {
|
cdev = tpnt->modes[mode].cdevs[rew];
|
||||||
scsi_tapes[i] = NULL;
|
if (!cdev)
|
||||||
st_nr_dev--;
|
continue;
|
||||||
write_unlock(&st_dev_arr_lock);
|
cdev_devno = cdev->dev;
|
||||||
sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
|
device_destroy(&st_sysfs_class, cdev_devno);
|
||||||
"tape");
|
cdev_del(tpnt->modes[mode].cdevs[rew]);
|
||||||
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
|
tpnt->modes[mode].cdevs[rew] = NULL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&st_ref_mutex);
|
|
||||||
kref_put(&tpnt->kref, scsi_tape_release);
|
|
||||||
mutex_unlock(&st_ref_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_unlock(&st_dev_arr_lock);
|
mutex_lock(&st_ref_mutex);
|
||||||
|
kref_put(&tpnt->kref, scsi_tape_release);
|
||||||
|
mutex_unlock(&st_ref_mutex);
|
||||||
|
spin_lock(&st_index_lock);
|
||||||
|
idr_remove(&st_index_idr, index);
|
||||||
|
spin_unlock(&st_index_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4336,7 +4307,6 @@ static void __exit exit_st(void)
|
||||||
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
||||||
ST_MAX_TAPE_ENTRIES);
|
ST_MAX_TAPE_ENTRIES);
|
||||||
class_unregister(&st_sysfs_class);
|
class_unregister(&st_sysfs_class);
|
||||||
kfree(scsi_tapes);
|
|
||||||
printk(KERN_INFO "st: Unloaded.\n");
|
printk(KERN_INFO "st: Unloaded.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4459,22 +4429,10 @@ static ssize_t
|
||||||
options_show(struct device *dev, struct device_attribute *attr, char *buf)
|
options_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||||
struct scsi_tape *STp;
|
struct scsi_tape *STp = STm->tape;
|
||||||
int i, j, options;
|
int options;
|
||||||
ssize_t l = 0;
|
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_buffer_writes ? MT_ST_BUFFER_WRITES : 0;
|
||||||
options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0;
|
options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0;
|
||||||
options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
|
options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0;
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct st_modedef {
|
||||||
unsigned char default_compression; /* 0 = don't touch, etc */
|
unsigned char default_compression; /* 0 = don't touch, etc */
|
||||||
short default_density; /* Forced density, -1 = no value */
|
short default_density; /* Forced density, -1 = no value */
|
||||||
int default_blksize; /* Forced blocksize, -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 */
|
struct cdev *cdevs[2]; /* Auto-rewind and non-rewind devices */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ struct scsi_tape {
|
||||||
struct mutex lock; /* For serialization */
|
struct mutex lock; /* For serialization */
|
||||||
struct completion wait; /* For SCSI commands */
|
struct completion wait; /* For SCSI commands */
|
||||||
struct st_buffer *buffer;
|
struct st_buffer *buffer;
|
||||||
|
int index;
|
||||||
|
|
||||||
/* Drive characteristics */
|
/* Drive characteristics */
|
||||||
unsigned char omit_blklims;
|
unsigned char omit_blklims;
|
||||||
|
|
Loading…
Reference in New Issue