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 /drivers/scsi/osst.c | |
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>
Diffstat (limited to 'drivers/scsi/osst.c')
-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) |