diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-10-04 06:00:38 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-10-04 14:16:29 -0400 |
commit | 13026a6b985b9d1e19330d5656e211f15b5aca3b (patch) | |
tree | 615cd268538ced98adc5cc26b15daeea65b7221f | |
parent | 5e4009ba3d5af40f5615fdb4304cc4a9947cca0a (diff) |
[SCSI] SCSI st: fix error handling in module init, sysfs
- Notice and handle sysfs errors in module init, tape init
- Properly unwind errors in module init
- Remove bogus st_sysfs_class==NULL test, it is guaranteed !NULL at that point
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/st.c | 115 |
1 files changed, 78 insertions, 37 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7f669b600677..3babdc76b3fb 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); | |||
195 | static int st_probe(struct device *); | 195 | static int st_probe(struct device *); |
196 | static int st_remove(struct device *); | 196 | static int st_remove(struct device *); |
197 | 197 | ||
198 | static void do_create_driverfs_files(void); | 198 | static int do_create_driverfs_files(void); |
199 | static void do_remove_driverfs_files(void); | 199 | static void do_remove_driverfs_files(void); |
200 | static void do_create_class_files(struct scsi_tape *, int, int); | 200 | static int do_create_class_files(struct scsi_tape *, int, int); |
201 | 201 | ||
202 | static struct scsi_driver st_template = { | 202 | static struct scsi_driver st_template = { |
203 | .owner = THIS_MODULE, | 203 | .owner = THIS_MODULE, |
@@ -4048,7 +4048,9 @@ static int st_probe(struct device *dev) | |||
4048 | STm->cdevs[j] = cdev; | 4048 | STm->cdevs[j] = cdev; |
4049 | 4049 | ||
4050 | } | 4050 | } |
4051 | do_create_class_files(tpnt, dev_num, mode); | 4051 | error = do_create_class_files(tpnt, dev_num, mode); |
4052 | if (error) | ||
4053 | goto out_free_tape; | ||
4052 | } | 4054 | } |
4053 | 4055 | ||
4054 | sdev_printk(KERN_WARNING, SDp, | 4056 | sdev_printk(KERN_WARNING, SDp, |
@@ -4157,32 +4159,45 @@ static void scsi_tape_release(struct kref *kref) | |||
4157 | 4159 | ||
4158 | static int __init init_st(void) | 4160 | static int __init init_st(void) |
4159 | { | 4161 | { |
4162 | int err; | ||
4163 | |||
4160 | validate_options(); | 4164 | validate_options(); |
4161 | 4165 | ||
4162 | printk(KERN_INFO | 4166 | printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", |
4163 | "st: Version %s, fixed bufsize %d, s/g segs %d\n", | ||
4164 | verstr, st_fixed_buffer_size, st_max_sg_segs); | 4167 | verstr, st_fixed_buffer_size, st_max_sg_segs); |
4165 | 4168 | ||
4166 | st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); | 4169 | st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); |
4167 | if (IS_ERR(st_sysfs_class)) { | 4170 | if (IS_ERR(st_sysfs_class)) { |
4168 | st_sysfs_class = NULL; | ||
4169 | printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); | 4171 | printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); |
4170 | return 1; | 4172 | return PTR_ERR(st_sysfs_class); |
4171 | } | 4173 | } |
4172 | 4174 | ||
4173 | if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), | 4175 | err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), |
4174 | ST_MAX_TAPE_ENTRIES, "st")) { | 4176 | ST_MAX_TAPE_ENTRIES, "st"); |
4175 | if (scsi_register_driver(&st_template.gendrv) == 0) { | 4177 | if (err) { |
4176 | do_create_driverfs_files(); | 4178 | printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", |
4177 | return 0; | 4179 | SCSI_TAPE_MAJOR); |
4178 | } | 4180 | goto err_class; |
4179 | unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), | ||
4180 | ST_MAX_TAPE_ENTRIES); | ||
4181 | } | 4181 | } |
4182 | class_destroy(st_sysfs_class); | ||
4183 | 4182 | ||
4184 | printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR); | 4183 | err = scsi_register_driver(&st_template.gendrv); |
4185 | return 1; | 4184 | if (err) |
4185 | goto err_chrdev; | ||
4186 | |||
4187 | err = do_create_driverfs_files(); | ||
4188 | if (err) | ||
4189 | goto err_scsidrv; | ||
4190 | |||
4191 | return 0; | ||
4192 | |||
4193 | err_scsidrv: | ||
4194 | scsi_unregister_driver(&st_template.gendrv); | ||
4195 | err_chrdev: | ||
4196 | unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), | ||
4197 | ST_MAX_TAPE_ENTRIES); | ||
4198 | err_class: | ||
4199 | class_destroy(st_sysfs_class); | ||
4200 | return err; | ||
4186 | } | 4201 | } |
4187 | 4202 | ||
4188 | static void __exit exit_st(void) | 4203 | static void __exit exit_st(void) |
@@ -4225,14 +4240,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf) | |||
4225 | } | 4240 | } |
4226 | static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); | 4241 | static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); |
4227 | 4242 | ||
4228 | static void do_create_driverfs_files(void) | 4243 | static int do_create_driverfs_files(void) |
4229 | { | 4244 | { |
4230 | struct device_driver *driverfs = &st_template.gendrv; | 4245 | struct device_driver *driverfs = &st_template.gendrv; |
4246 | int err; | ||
4247 | |||
4248 | err = driver_create_file(driverfs, &driver_attr_try_direct_io); | ||
4249 | if (err) | ||
4250 | return err; | ||
4251 | err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size); | ||
4252 | if (err) | ||
4253 | goto err_try_direct_io; | ||
4254 | err = driver_create_file(driverfs, &driver_attr_max_sg_segs); | ||
4255 | if (err) | ||
4256 | goto err_attr_fixed_buf; | ||
4257 | err = driver_create_file(driverfs, &driver_attr_version); | ||
4258 | if (err) | ||
4259 | goto err_attr_max_sg; | ||
4231 | 4260 | ||
4232 | driver_create_file(driverfs, &driver_attr_try_direct_io); | 4261 | return 0; |
4233 | driver_create_file(driverfs, &driver_attr_fixed_buffer_size); | 4262 | |
4234 | driver_create_file(driverfs, &driver_attr_max_sg_segs); | 4263 | err_attr_max_sg: |
4235 | driver_create_file(driverfs, &driver_attr_version); | 4264 | driver_remove_file(driverfs, &driver_attr_max_sg_segs); |
4265 | err_attr_fixed_buf: | ||
4266 | driver_remove_file(driverfs, &driver_attr_fixed_buffer_size); | ||
4267 | err_try_direct_io: | ||
4268 | driver_remove_file(driverfs, &driver_attr_try_direct_io); | ||
4269 | return err; | ||
4236 | } | 4270 | } |
4237 | 4271 | ||
4238 | static void do_remove_driverfs_files(void) | 4272 | static void do_remove_driverfs_files(void) |
@@ -4293,15 +4327,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) | |||
4293 | 4327 | ||
4294 | CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); | 4328 | CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); |
4295 | 4329 | ||
4296 | static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) | 4330 | static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) |
4297 | { | 4331 | { |
4298 | int i, rew, error; | 4332 | int i, rew, error; |
4299 | char name[10]; | 4333 | char name[10]; |
4300 | struct class_device *st_class_member; | 4334 | struct class_device *st_class_member; |
4301 | 4335 | ||
4302 | if (!st_sysfs_class) | ||
4303 | return; | ||
4304 | |||
4305 | for (rew=0; rew < 2; rew++) { | 4336 | for (rew=0; rew < 2; rew++) { |
4306 | /* Make sure that the minor numbers corresponding to the four | 4337 | /* Make sure that the minor numbers corresponding to the four |
4307 | first modes always get the same names */ | 4338 | first modes always get the same names */ |
@@ -4316,18 +4347,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) | |||
4316 | if (IS_ERR(st_class_member)) { | 4347 | if (IS_ERR(st_class_member)) { |
4317 | printk(KERN_WARNING "st%d: class_device_create failed\n", | 4348 | printk(KERN_WARNING "st%d: class_device_create failed\n", |
4318 | dev_num); | 4349 | dev_num); |
4350 | error = PTR_ERR(st_class_member); | ||
4319 | goto out; | 4351 | goto out; |
4320 | } | 4352 | } |
4321 | class_set_devdata(st_class_member, &STp->modes[mode]); | 4353 | class_set_devdata(st_class_member, &STp->modes[mode]); |
4322 | 4354 | ||
4323 | class_device_create_file(st_class_member, | 4355 | error = class_device_create_file(st_class_member, |
4324 | &class_device_attr_defined); | 4356 | &class_device_attr_defined); |
4325 | class_device_create_file(st_class_member, | 4357 | if (error) goto out; |
4326 | &class_device_attr_default_blksize); | 4358 | error = class_device_create_file(st_class_member, |
4327 | class_device_create_file(st_class_member, | 4359 | &class_device_attr_default_blksize); |
4328 | &class_device_attr_default_density); | 4360 | if (error) goto out; |
4329 | class_device_create_file(st_class_member, | 4361 | error = class_device_create_file(st_class_member, |
4330 | &class_device_attr_default_compression); | 4362 | &class_device_attr_default_density); |
4363 | if (error) goto out; | ||
4364 | error = class_device_create_file(st_class_member, | ||
4365 | &class_device_attr_default_compression); | ||
4366 | if (error) goto out; | ||
4367 | |||
4331 | if (mode == 0 && rew == 0) { | 4368 | if (mode == 0 && rew == 0) { |
4332 | error = sysfs_create_link(&STp->device->sdev_gendev.kobj, | 4369 | error = sysfs_create_link(&STp->device->sdev_gendev.kobj, |
4333 | &st_class_member->kobj, | 4370 | &st_class_member->kobj, |
@@ -4336,11 +4373,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) | |||
4336 | printk(KERN_ERR | 4373 | printk(KERN_ERR |
4337 | "st%d: Can't create sysfs link from SCSI device.\n", | 4374 | "st%d: Can't create sysfs link from SCSI device.\n", |
4338 | dev_num); | 4375 | dev_num); |
4376 | goto out; | ||
4339 | } | 4377 | } |
4340 | } | 4378 | } |
4341 | } | 4379 | } |
4342 | out: | 4380 | |
4343 | return; | 4381 | return 0; |
4382 | |||
4383 | out: | ||
4384 | return error; | ||
4344 | } | 4385 | } |
4345 | 4386 | ||
4346 | /* The following functions may be useful for a larger audience. */ | 4387 | /* The following functions may be useful for a larger audience. */ |