diff options
| author | Jeff Garzik <jeff@garzik.org> | 2006-10-04 05:23:04 -0400 |
|---|---|---|
| committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-10-04 14:12:44 -0400 |
| commit | 37e0333c68ca9cbddfc0108e1889556287563df0 (patch) | |
| tree | 2f6b27aff5b6d8e737c9a8f8bccdd8d3a3c25b9a | |
| parent | de77aaff5f0178f44867f131deb5e2cb1610fe6b (diff) | |
[SCSI] SCSI osst: add error handling to module init, sysfs
- check all sysfs-related return codes, and propagate them back to callers
- properly unwind errors in osst_probe(), init_osst(). This fixes a
leak that occured if scsi driver registration failed, and fixes an
oops if sysfs creation returned an error.
(unrelated)
- kzalloc() cleanup in new_tape_buf()
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
| -rw-r--r-- | drivers/scsi/osst.c | 131 |
1 files changed, 91 insertions, 40 deletions
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 9ecb323ebae8..824fe080d1dc 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c | |||
| @@ -5206,12 +5206,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d | |||
| 5206 | priority = GFP_KERNEL; | 5206 | priority = GFP_KERNEL; |
| 5207 | 5207 | ||
| 5208 | i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); | 5208 | i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); |
| 5209 | tb = (struct osst_buffer *)kmalloc(i, priority); | 5209 | tb = kzalloc(i, priority); |
| 5210 | if (!tb) { | 5210 | if (!tb) { |
| 5211 | printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); | 5211 | printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); |
| 5212 | return NULL; | 5212 | return NULL; |
| 5213 | } | 5213 | } |
| 5214 | memset(tb, 0, i); | 5214 | |
| 5215 | tb->sg_segs = tb->orig_sg_segs = 0; | 5215 | tb->sg_segs = tb->orig_sg_segs = 0; |
| 5216 | tb->use_sg = max_sg; | 5216 | tb->use_sg = max_sg; |
| 5217 | tb->in_use = 1; | 5217 | tb->in_use = 1; |
| @@ -5574,9 +5574,9 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf) | |||
| 5574 | 5574 | ||
| 5575 | static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); | 5575 | static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); |
| 5576 | 5576 | ||
| 5577 | static void osst_create_driverfs_files(struct device_driver *driverfs) | 5577 | static int osst_create_driverfs_files(struct device_driver *driverfs) |
| 5578 | { | 5578 | { |
| 5579 | driver_create_file(driverfs, &driver_attr_version); | 5579 | return driver_create_file(driverfs, &driver_attr_version); |
| 5580 | } | 5580 | } |
| 5581 | 5581 | ||
| 5582 | static void osst_remove_driverfs_files(struct device_driver *driverfs) | 5582 | static void osst_remove_driverfs_files(struct device_driver *driverfs) |
| @@ -5662,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); | |||
| 5662 | 5662 | ||
| 5663 | static struct class *osst_sysfs_class; | 5663 | static struct class *osst_sysfs_class; |
| 5664 | 5664 | ||
| 5665 | static int osst_sysfs_valid = 0; | 5665 | static int osst_sysfs_init(void) |
| 5666 | |||
| 5667 | static void osst_sysfs_init(void) | ||
| 5668 | { | 5666 | { |
| 5669 | osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); | 5667 | osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); |
| 5670 | if ( IS_ERR(osst_sysfs_class) ) | 5668 | if (IS_ERR(osst_sysfs_class)) { |
| 5671 | printk(KERN_WARNING "osst :W: Unable to register sysfs class\n"); | 5669 | printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); |
| 5672 | else | 5670 | return PTR_ERR(osst_sysfs_class); |
| 5673 | osst_sysfs_valid = 1; | 5671 | } |
| 5672 | |||
| 5673 | return 0; | ||
| 5674 | } | 5674 | } |
| 5675 | 5675 | ||
| 5676 | static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) | 5676 | static void osst_sysfs_destroy(dev_t dev) |
| 5677 | { | 5677 | { |
| 5678 | struct class_device *osst_class_member; | 5678 | class_device_destroy(osst_sysfs_class, dev); |
| 5679 | } | ||
| 5679 | 5680 | ||
| 5680 | if (!osst_sysfs_valid) return; | 5681 | static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) |
| 5682 | { | ||
| 5683 | struct class_device *osst_class_member; | ||
| 5684 | int err; | ||
| 5681 | 5685 | ||
| 5682 | osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name); | 5686 | osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, |
| 5687 | device, "%s", name); | ||
| 5683 | if (IS_ERR(osst_class_member)) { | 5688 | if (IS_ERR(osst_class_member)) { |
| 5684 | printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); | 5689 | printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); |
| 5685 | return; | 5690 | return PTR_ERR(osst_class_member); |
| 5686 | } | 5691 | } |
| 5692 | |||
| 5687 | class_set_devdata(osst_class_member, STp); | 5693 | class_set_devdata(osst_class_member, STp); |
| 5688 | class_device_create_file(osst_class_member, &class_device_attr_ADR_rev); | 5694 | err = class_device_create_file(osst_class_member, |
| 5689 | class_device_create_file(osst_class_member, &class_device_attr_media_version); | 5695 | &class_device_attr_ADR_rev); |
| 5690 | class_device_create_file(osst_class_member, &class_device_attr_capacity); | 5696 | if (err) |
| 5691 | class_device_create_file(osst_class_member, &class_device_attr_BOT_frame); | 5697 | goto err_out; |
| 5692 | class_device_create_file(osst_class_member, &class_device_attr_EOD_frame); | 5698 | err = class_device_create_file(osst_class_member, |
| 5693 | class_device_create_file(osst_class_member, &class_device_attr_file_count); | 5699 | &class_device_attr_media_version); |
| 5694 | } | 5700 | if (err) |
| 5701 | goto err_out; | ||
| 5702 | err = class_device_create_file(osst_class_member, | ||
| 5703 | &class_device_attr_capacity); | ||
| 5704 | if (err) | ||
| 5705 | goto err_out; | ||
| 5706 | err = class_device_create_file(osst_class_member, | ||
| 5707 | &class_device_attr_BOT_frame); | ||
| 5708 | if (err) | ||
| 5709 | goto err_out; | ||
| 5710 | err = class_device_create_file(osst_class_member, | ||
| 5711 | &class_device_attr_EOD_frame); | ||
| 5712 | if (err) | ||
| 5713 | goto err_out; | ||
| 5714 | err = class_device_create_file(osst_class_member, | ||
| 5715 | &class_device_attr_file_count); | ||
| 5716 | if (err) | ||
| 5717 | goto err_out; | ||
| 5695 | 5718 | ||
| 5696 | static void osst_sysfs_destroy(dev_t dev) | 5719 | return 0; |
| 5697 | { | ||
| 5698 | if (!osst_sysfs_valid) return; | ||
| 5699 | 5720 | ||
| 5700 | class_device_destroy(osst_sysfs_class, dev); | 5721 | err_out: |
| 5722 | osst_sysfs_destroy(dev); | ||
| 5723 | return err; | ||
| 5701 | } | 5724 | } |
| 5702 | 5725 | ||
| 5703 | static void osst_sysfs_cleanup(void) | 5726 | static void osst_sysfs_cleanup(void) |
| 5704 | { | 5727 | { |
| 5705 | if (osst_sysfs_valid) { | 5728 | class_destroy(osst_sysfs_class); |
| 5706 | class_destroy(osst_sysfs_class); | ||
| 5707 | osst_sysfs_valid = 0; | ||
| 5708 | } | ||
| 5709 | } | 5729 | } |
| 5710 | 5730 | ||
| 5711 | /* | 5731 | /* |
| @@ -5720,7 +5740,7 @@ static int osst_probe(struct device *dev) | |||
| 5720 | struct st_partstat * STps; | 5740 | struct st_partstat * STps; |
| 5721 | struct osst_buffer * buffer; | 5741 | struct osst_buffer * buffer; |
| 5722 | struct gendisk * drive; | 5742 | struct gendisk * drive; |
| 5723 | int i, dev_num; | 5743 | int i, dev_num, err = -ENODEV; |
| 5724 | 5744 | ||
| 5725 | if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) | 5745 | if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) |
| 5726 | return -ENODEV; | 5746 | return -ENODEV; |
| @@ -5848,13 +5868,20 @@ static int osst_probe(struct device *dev) | |||
| 5848 | init_MUTEX(&tpnt->lock); | 5868 | init_MUTEX(&tpnt->lock); |
| 5849 | osst_nr_dev++; | 5869 | osst_nr_dev++; |
| 5850 | write_unlock(&os_scsi_tapes_lock); | 5870 | write_unlock(&os_scsi_tapes_lock); |
| 5871 | |||
| 5851 | { | 5872 | { |
| 5852 | char name[8]; | 5873 | char name[8]; |
| 5874 | |||
| 5853 | /* Rewind entry */ | 5875 | /* Rewind entry */ |
| 5854 | osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); | 5876 | err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); |
| 5877 | if (err) | ||
| 5878 | goto out_free_buffer; | ||
| 5879 | |||
| 5855 | /* No-rewind entry */ | 5880 | /* No-rewind entry */ |
| 5856 | snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); | 5881 | snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); |
| 5857 | osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); | 5882 | err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); |
| 5883 | if (err) | ||
| 5884 | goto out_free_sysfs1; | ||
| 5858 | } | 5885 | } |
| 5859 | 5886 | ||
| 5860 | sdev_printk(KERN_INFO, SDp, | 5887 | sdev_printk(KERN_INFO, SDp, |
| @@ -5863,9 +5890,13 @@ static int osst_probe(struct device *dev) | |||
| 5863 | 5890 | ||
| 5864 | return 0; | 5891 | return 0; |
| 5865 | 5892 | ||
| 5893 | out_free_sysfs1: | ||
| 5894 | osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); | ||
| 5895 | out_free_buffer: | ||
| 5896 | kfree(buffer); | ||
| 5866 | out_put_disk: | 5897 | out_put_disk: |
| 5867 | put_disk(drive); | 5898 | put_disk(drive); |
| 5868 | return -ENODEV; | 5899 | return err; |
| 5869 | }; | 5900 | }; |
| 5870 | 5901 | ||
| 5871 | static int osst_remove(struct device *dev) | 5902 | static int osst_remove(struct device *dev) |
| @@ -5902,19 +5933,39 @@ static int osst_remove(struct device *dev) | |||
| 5902 | 5933 | ||
| 5903 | static int __init init_osst(void) | 5934 | static int __init init_osst(void) |
| 5904 | { | 5935 | { |
| 5936 | int err; | ||
| 5937 | |||
| 5905 | printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); | 5938 | printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); |
| 5906 | 5939 | ||
| 5907 | validate_options(); | 5940 | validate_options(); |
| 5908 | osst_sysfs_init(); | ||
| 5909 | 5941 | ||
| 5910 | if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) { | 5942 | err = osst_sysfs_init(); |
| 5943 | if (err) | ||
| 5944 | return err; | ||
| 5945 | |||
| 5946 | err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); | ||
| 5947 | if (err < 0) { | ||
| 5911 | printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); | 5948 | printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); |
| 5912 | osst_sysfs_cleanup(); | 5949 | goto err_out; |
| 5913 | return 1; | ||
| 5914 | } | 5950 | } |
| 5915 | osst_create_driverfs_files(&osst_template.gendrv); | 5951 | |
| 5952 | err = scsi_register_driver(&osst_template.gendrv); | ||
| 5953 | if (err) | ||
| 5954 | goto err_out_chrdev; | ||
| 5955 | |||
| 5956 | err = osst_create_driverfs_files(&osst_template.gendrv); | ||
| 5957 | if (err) | ||
| 5958 | goto err_out_scsidrv; | ||
| 5916 | 5959 | ||
| 5917 | return 0; | 5960 | return 0; |
| 5961 | |||
| 5962 | err_out_scsidrv: | ||
| 5963 | scsi_unregister_driver(&osst_template.gendrv); | ||
| 5964 | err_out_chrdev: | ||
| 5965 | unregister_chrdev(OSST_MAJOR, "osst"); | ||
| 5966 | err_out: | ||
| 5967 | osst_sysfs_cleanup(); | ||
| 5968 | return err; | ||
| 5918 | } | 5969 | } |
| 5919 | 5970 | ||
| 5920 | static void __exit exit_osst (void) | 5971 | static void __exit exit_osst (void) |
