diff options
author | Jeff Mahoney <jeffm@suse.de> | 2012-08-18 15:20:39 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-14 12:59:28 -0400 |
commit | 6c648d95a6af4a79241a916871df17c84c68ea20 (patch) | |
tree | 9c658ea5964dea1ecdb029ce955587d17bea6d03 /drivers/scsi/st.c | |
parent | e3f2a9cc84d35fac73c906de57ad3b3f5ff82008 (diff) |
[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>
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r-- | drivers/scsi/st.c | 178 |
1 files changed, 68 insertions, 110 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 492b53b6e51d..052622fdba02 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -37,6 +37,7 @@ static const char *verstr = "20101219"; | |||
37 | #include <linux/blkdev.h> | 37 | #include <linux/blkdev.h> |
38 | #include <linux/moduleparam.h> | 38 | #include <linux/moduleparam.h> |
39 | #include <linux/cdev.h> | 39 | #include <linux/cdev.h> |
40 | #include <linux/idr.h> | ||
40 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
41 | #include <linux/mutex.h> | 42 | #include <linux/mutex.h> |
42 | 43 | ||
@@ -81,9 +82,6 @@ static int try_direct_io = TRY_DIRECT_IO; | |||
81 | static int try_rdio = 1; | 82 | static int try_rdio = 1; |
82 | static int try_wdio = 1; | 83 | static int try_wdio = 1; |
83 | 84 | ||
84 | static int st_dev_max; | ||
85 | static int st_nr_dev; | ||
86 | |||
87 | static struct class st_sysfs_class; | 85 | static struct class st_sysfs_class; |
88 | static struct device_attribute st_dev_attrs[]; | 86 | static struct device_attribute st_dev_attrs[]; |
89 | 87 | ||
@@ -174,13 +172,9 @@ static int debugging = DEBUG; | |||
174 | 24 bits) */ | 172 | 24 bits) */ |
175 | #define SET_DENS_AND_BLK 0x10001 | 173 | #define SET_DENS_AND_BLK 0x10001 |
176 | 174 | ||
177 | static DEFINE_RWLOCK(st_dev_arr_lock); | ||
178 | |||
179 | static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; | 175 | static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; |
180 | static int st_max_sg_segs = ST_MAX_SG; | 176 | static int st_max_sg_segs = ST_MAX_SG; |
181 | 177 | ||
182 | static struct scsi_tape **scsi_tapes = NULL; | ||
183 | |||
184 | static int modes_defined; | 178 | static int modes_defined; |
185 | 179 | ||
186 | static int enlarge_buffer(struct st_buffer *, int, int); | 180 | static int enlarge_buffer(struct st_buffer *, int, int); |
@@ -222,6 +216,10 @@ static void scsi_tape_release(struct kref *); | |||
222 | #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) | 216 | #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) |
223 | 217 | ||
224 | static DEFINE_MUTEX(st_ref_mutex); | 218 | static DEFINE_MUTEX(st_ref_mutex); |
219 | static DEFINE_SPINLOCK(st_index_lock); | ||
220 | static DEFINE_SPINLOCK(st_use_lock); | ||
221 | static DEFINE_IDR(st_index_idr); | ||
222 | |||
225 | 223 | ||
226 | 224 | ||
227 | #include "osst_detect.h" | 225 | #include "osst_detect.h" |
@@ -239,10 +237,9 @@ static struct scsi_tape *scsi_tape_get(int dev) | |||
239 | struct scsi_tape *STp = NULL; | 237 | struct scsi_tape *STp = NULL; |
240 | 238 | ||
241 | mutex_lock(&st_ref_mutex); | 239 | mutex_lock(&st_ref_mutex); |
242 | write_lock(&st_dev_arr_lock); | 240 | spin_lock(&st_index_lock); |
243 | 241 | ||
244 | if (dev < st_dev_max && scsi_tapes != NULL) | 242 | STp = idr_find(&st_index_idr, dev); |
245 | STp = scsi_tapes[dev]; | ||
246 | if (!STp) goto out; | 243 | if (!STp) goto out; |
247 | 244 | ||
248 | kref_get(&STp->kref); | 245 | kref_get(&STp->kref); |
@@ -259,7 +256,7 @@ out_put: | |||
259 | kref_put(&STp->kref, scsi_tape_release); | 256 | kref_put(&STp->kref, scsi_tape_release); |
260 | STp = NULL; | 257 | STp = NULL; |
261 | out: | 258 | out: |
262 | write_unlock(&st_dev_arr_lock); | 259 | spin_unlock(&st_index_lock); |
263 | mutex_unlock(&st_ref_mutex); | 260 | mutex_unlock(&st_ref_mutex); |
264 | return STp; | 261 | return STp; |
265 | } | 262 | } |
@@ -1202,12 +1199,12 @@ static int st_open(struct inode *inode, struct file *filp) | |||
1202 | return -ENXIO; | 1199 | return -ENXIO; |
1203 | } | 1200 | } |
1204 | 1201 | ||
1205 | write_lock(&st_dev_arr_lock); | ||
1206 | filp->private_data = STp; | 1202 | filp->private_data = STp; |
1207 | name = tape_name(STp); | 1203 | name = tape_name(STp); |
1208 | 1204 | ||
1205 | spin_lock(&st_use_lock); | ||
1209 | if (STp->in_use) { | 1206 | if (STp->in_use) { |
1210 | write_unlock(&st_dev_arr_lock); | 1207 | spin_unlock(&st_use_lock); |
1211 | scsi_tape_put(STp); | 1208 | scsi_tape_put(STp); |
1212 | mutex_unlock(&st_mutex); | 1209 | mutex_unlock(&st_mutex); |
1213 | DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) | 1210 | 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) | |||
1215 | } | 1212 | } |
1216 | 1213 | ||
1217 | STp->in_use = 1; | 1214 | STp->in_use = 1; |
1218 | write_unlock(&st_dev_arr_lock); | 1215 | spin_unlock(&st_use_lock); |
1219 | STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; | 1216 | STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; |
1220 | 1217 | ||
1221 | if (scsi_autopm_get_device(STp->device) < 0) { | 1218 | if (scsi_autopm_get_device(STp->device) < 0) { |
@@ -1404,9 +1401,9 @@ static int st_release(struct inode *inode, struct file *filp) | |||
1404 | do_door_lock(STp, 0); | 1401 | do_door_lock(STp, 0); |
1405 | 1402 | ||
1406 | normalize_buffer(STp->buffer); | 1403 | normalize_buffer(STp->buffer); |
1407 | write_lock(&st_dev_arr_lock); | 1404 | spin_lock(&st_use_lock); |
1408 | STp->in_use = 0; | 1405 | STp->in_use = 0; |
1409 | write_unlock(&st_dev_arr_lock); | 1406 | spin_unlock(&st_use_lock); |
1410 | scsi_autopm_put_device(STp->device); | 1407 | scsi_autopm_put_device(STp->device); |
1411 | scsi_tape_put(STp); | 1408 | scsi_tape_put(STp); |
1412 | 1409 | ||
@@ -4029,58 +4026,16 @@ static int st_probe(struct device *dev) | |||
4029 | goto out_buffer_free; | 4026 | goto out_buffer_free; |
4030 | } | 4027 | } |
4031 | 4028 | ||
4032 | write_lock(&st_dev_arr_lock); | ||
4033 | if (st_nr_dev >= st_dev_max) { | ||
4034 | struct scsi_tape **tmp_da; | ||
4035 | int tmp_dev_max; | ||
4036 | |||
4037 | tmp_dev_max = max(st_nr_dev * 2, 8); | ||
4038 | if (tmp_dev_max > ST_MAX_TAPES) | ||
4039 | tmp_dev_max = ST_MAX_TAPES; | ||
4040 | if (tmp_dev_max <= st_nr_dev) { | ||
4041 | write_unlock(&st_dev_arr_lock); | ||
4042 | printk(KERN_ERR "st: Too many tape devices (max. %d).\n", | ||
4043 | ST_MAX_TAPES); | ||
4044 | goto out_put_disk; | ||
4045 | } | ||
4046 | |||
4047 | tmp_da = kzalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC); | ||
4048 | if (tmp_da == NULL) { | ||
4049 | write_unlock(&st_dev_arr_lock); | ||
4050 | printk(KERN_ERR "st: Can't extend device array.\n"); | ||
4051 | goto out_put_disk; | ||
4052 | } | ||
4053 | |||
4054 | if (scsi_tapes != NULL) { | ||
4055 | memcpy(tmp_da, scsi_tapes, | ||
4056 | st_dev_max * sizeof(struct scsi_tape *)); | ||
4057 | kfree(scsi_tapes); | ||
4058 | } | ||
4059 | scsi_tapes = tmp_da; | ||
4060 | |||
4061 | st_dev_max = tmp_dev_max; | ||
4062 | } | ||
4063 | |||
4064 | for (i = 0; i < st_dev_max; i++) | ||
4065 | if (scsi_tapes[i] == NULL) | ||
4066 | break; | ||
4067 | if (i >= st_dev_max) | ||
4068 | panic("scsi_devices corrupt (st)"); | ||
4069 | |||
4070 | tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC); | 4029 | tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC); |
4071 | if (tpnt == NULL) { | 4030 | if (tpnt == NULL) { |
4072 | write_unlock(&st_dev_arr_lock); | ||
4073 | printk(KERN_ERR "st: Can't allocate device descriptor.\n"); | 4031 | printk(KERN_ERR "st: Can't allocate device descriptor.\n"); |
4074 | goto out_put_disk; | 4032 | goto out_put_disk; |
4075 | } | 4033 | } |
4076 | kref_init(&tpnt->kref); | 4034 | kref_init(&tpnt->kref); |
4077 | tpnt->disk = disk; | 4035 | tpnt->disk = disk; |
4078 | sprintf(disk->disk_name, "st%d", i); | ||
4079 | disk->private_data = &tpnt->driver; | 4036 | disk->private_data = &tpnt->driver; |
4080 | disk->queue = SDp->request_queue; | 4037 | disk->queue = SDp->request_queue; |
4081 | tpnt->driver = &st_template; | 4038 | tpnt->driver = &st_template; |
4082 | scsi_tapes[i] = tpnt; | ||
4083 | dev_num = i; | ||
4084 | 4039 | ||
4085 | tpnt->device = SDp; | 4040 | tpnt->device = SDp; |
4086 | if (SDp->scsi_level <= 2) | 4041 | if (SDp->scsi_level <= 2) |
@@ -4126,6 +4081,7 @@ static int st_probe(struct device *dev) | |||
4126 | STm->default_compression = ST_DONT_TOUCH; | 4081 | STm->default_compression = ST_DONT_TOUCH; |
4127 | STm->default_blksize = (-1); /* No forced size */ | 4082 | STm->default_blksize = (-1); /* No forced size */ |
4128 | STm->default_density = (-1); /* No forced density */ | 4083 | STm->default_density = (-1); /* No forced density */ |
4084 | STm->tape = tpnt; | ||
4129 | } | 4085 | } |
4130 | 4086 | ||
4131 | for (i = 0; i < ST_NBR_PARTITIONS; i++) { | 4087 | for (i = 0; i < ST_NBR_PARTITIONS; i++) { |
@@ -4145,8 +4101,29 @@ static int st_probe(struct device *dev) | |||
4145 | tpnt->blksize_changed = 0; | 4101 | tpnt->blksize_changed = 0; |
4146 | mutex_init(&tpnt->lock); | 4102 | mutex_init(&tpnt->lock); |
4147 | 4103 | ||
4148 | st_nr_dev++; | 4104 | if (!idr_pre_get(&st_index_idr, GFP_KERNEL)) { |
4149 | write_unlock(&st_dev_arr_lock); | 4105 | pr_warn("st: idr expansion failed\n"); |
4106 | error = -ENOMEM; | ||
4107 | goto out_put_disk; | ||
4108 | } | ||
4109 | |||
4110 | spin_lock(&st_index_lock); | ||
4111 | error = idr_get_new(&st_index_idr, tpnt, &dev_num); | ||
4112 | spin_unlock(&st_index_lock); | ||
4113 | if (error) { | ||
4114 | pr_warn("st: idr allocation failed: %d\n", error); | ||
4115 | goto out_put_disk; | ||
4116 | } | ||
4117 | |||
4118 | if (dev_num > ST_MAX_TAPES) { | ||
4119 | pr_err("st: Too many tape devices (max. %d).\n", ST_MAX_TAPES); | ||
4120 | goto out_put_index; | ||
4121 | } | ||
4122 | |||
4123 | tpnt->index = dev_num; | ||
4124 | sprintf(disk->disk_name, "st%d", dev_num); | ||
4125 | |||
4126 | dev_set_drvdata(dev, tpnt); | ||
4150 | 4127 | ||
4151 | for (mode = 0; mode < ST_NBR_MODES; ++mode) { | 4128 | for (mode = 0; mode < ST_NBR_MODES; ++mode) { |
4152 | STm = &(tpnt->modes[mode]); | 4129 | STm = &(tpnt->modes[mode]); |
@@ -4189,10 +4166,10 @@ static int st_probe(struct device *dev) | |||
4189 | return 0; | 4166 | return 0; |
4190 | 4167 | ||
4191 | out_free_tape: | 4168 | out_free_tape: |
4169 | sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, | ||
4170 | "tape"); | ||
4192 | for (mode=0; mode < ST_NBR_MODES; mode++) { | 4171 | for (mode=0; mode < ST_NBR_MODES; mode++) { |
4193 | STm = &(tpnt->modes[mode]); | 4172 | STm = &(tpnt->modes[mode]); |
4194 | sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, | ||
4195 | "tape"); | ||
4196 | for (j=0; j < 2; j++) { | 4173 | for (j=0; j < 2; j++) { |
4197 | if (STm->cdevs[j]) { | 4174 | if (STm->cdevs[j]) { |
4198 | device_destroy(&st_sysfs_class, | 4175 | device_destroy(&st_sysfs_class, |
@@ -4202,10 +4179,10 @@ out_free_tape: | |||
4202 | } | 4179 | } |
4203 | } | 4180 | } |
4204 | } | 4181 | } |
4205 | write_lock(&st_dev_arr_lock); | 4182 | out_put_index: |
4206 | scsi_tapes[dev_num] = NULL; | 4183 | spin_lock(&st_index_lock); |
4207 | st_nr_dev--; | 4184 | idr_remove(&st_index_idr, dev_num); |
4208 | write_unlock(&st_dev_arr_lock); | 4185 | spin_unlock(&st_index_lock); |
4209 | out_put_disk: | 4186 | out_put_disk: |
4210 | put_disk(disk); | 4187 | put_disk(disk); |
4211 | kfree(tpnt); | 4188 | kfree(tpnt); |
@@ -4218,38 +4195,32 @@ out: | |||
4218 | 4195 | ||
4219 | static int st_remove(struct device *dev) | 4196 | static int st_remove(struct device *dev) |
4220 | { | 4197 | { |
4221 | struct scsi_device *SDp = to_scsi_device(dev); | 4198 | struct scsi_tape *tpnt = dev_get_drvdata(dev); |
4222 | struct scsi_tape *tpnt; | 4199 | int rew, mode; |
4223 | int i, j, mode; | 4200 | dev_t cdev_devno; |
4224 | 4201 | struct cdev *cdev; | |
4225 | scsi_autopm_get_device(SDp); | 4202 | int index = tpnt->index; |
4226 | write_lock(&st_dev_arr_lock); | 4203 | |
4227 | for (i = 0; i < st_dev_max; i++) { | 4204 | scsi_autopm_get_device(to_scsi_device(dev)); |
4228 | tpnt = scsi_tapes[i]; | 4205 | sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape"); |
4229 | if (tpnt != NULL && tpnt->device == SDp) { | 4206 | for (mode = 0; mode < ST_NBR_MODES; ++mode) { |
4230 | scsi_tapes[i] = NULL; | 4207 | for (rew = 0; rew < 2; rew++) { |
4231 | st_nr_dev--; | 4208 | cdev = tpnt->modes[mode].cdevs[rew]; |
4232 | write_unlock(&st_dev_arr_lock); | 4209 | if (!cdev) |
4233 | sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, | 4210 | continue; |
4234 | "tape"); | 4211 | cdev_devno = cdev->dev; |
4235 | for (mode = 0; mode < ST_NBR_MODES; ++mode) { | 4212 | device_destroy(&st_sysfs_class, cdev_devno); |
4236 | for (j=0; j < 2; j++) { | 4213 | cdev_del(tpnt->modes[mode].cdevs[rew]); |
4237 | device_destroy(&st_sysfs_class, | 4214 | tpnt->modes[mode].cdevs[rew] = NULL; |
4238 | MKDEV(SCSI_TAPE_MAJOR, | ||
4239 | TAPE_MINOR(i, mode, j))); | ||
4240 | cdev_del(tpnt->modes[mode].cdevs[j]); | ||
4241 | tpnt->modes[mode].cdevs[j] = NULL; | ||
4242 | } | ||
4243 | } | ||
4244 | |||
4245 | mutex_lock(&st_ref_mutex); | ||
4246 | kref_put(&tpnt->kref, scsi_tape_release); | ||
4247 | mutex_unlock(&st_ref_mutex); | ||
4248 | return 0; | ||
4249 | } | 4215 | } |
4250 | } | 4216 | } |
4251 | 4217 | ||
4252 | write_unlock(&st_dev_arr_lock); | 4218 | mutex_lock(&st_ref_mutex); |
4219 | kref_put(&tpnt->kref, scsi_tape_release); | ||
4220 | mutex_unlock(&st_ref_mutex); | ||
4221 | spin_lock(&st_index_lock); | ||
4222 | idr_remove(&st_index_idr, index); | ||
4223 | spin_unlock(&st_index_lock); | ||
4253 | return 0; | 4224 | return 0; |
4254 | } | 4225 | } |
4255 | 4226 | ||
@@ -4336,7 +4307,6 @@ static void __exit exit_st(void) | |||
4336 | unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), | 4307 | unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), |
4337 | ST_MAX_TAPE_ENTRIES); | 4308 | ST_MAX_TAPE_ENTRIES); |
4338 | class_unregister(&st_sysfs_class); | 4309 | class_unregister(&st_sysfs_class); |
4339 | kfree(scsi_tapes); | ||
4340 | printk(KERN_INFO "st: Unloaded.\n"); | 4310 | printk(KERN_INFO "st: Unloaded.\n"); |
4341 | } | 4311 | } |
4342 | 4312 | ||
@@ -4459,22 +4429,10 @@ static ssize_t | |||
4459 | options_show(struct device *dev, struct device_attribute *attr, char *buf) | 4429 | options_show(struct device *dev, struct device_attribute *attr, char *buf) |
4460 | { | 4430 | { |
4461 | struct st_modedef *STm = dev_get_drvdata(dev); | 4431 | struct st_modedef *STm = dev_get_drvdata(dev); |
4462 | struct scsi_tape *STp; | 4432 | struct scsi_tape *STp = STm->tape; |
4463 | int i, j, options; | 4433 | int options; |
4464 | ssize_t l = 0; | 4434 | ssize_t l = 0; |
4465 | 4435 | ||
4466 | for (i=0; i < st_dev_max; i++) { | ||
4467 | for (j=0; j < ST_NBR_MODES; j++) | ||
4468 | if (&scsi_tapes[i]->modes[j] == STm) | ||
4469 | break; | ||
4470 | if (j < ST_NBR_MODES) | ||
4471 | break; | ||
4472 | } | ||
4473 | if (i == st_dev_max) | ||
4474 | return 0; /* should never happen */ | ||
4475 | |||
4476 | STp = scsi_tapes[i]; | ||
4477 | |||
4478 | options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; | 4436 | options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; |
4479 | options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; | 4437 | options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; |
4480 | options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; | 4438 | options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; |