diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-10-04 09:32:54 (GMT) |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-10-04 18:14:16 (GMT) |
commit | 5e4009ba3d5af40f5615fdb4304cc4a9947cca0a (patch) | |
tree | a6dd31cd9f6dfa1c85b3b5fefcded5b74d0ac2f5 /drivers/scsi/sd.c | |
parent | 37e0333c68ca9cbddfc0108e1889556287563df0 (diff) | |
download | linux-5e4009ba3d5af40f5615fdb4304cc4a9947cca0a.tar.xz |
[SCSI] SCSI sd: fix module init/exit error handling
- Properly handle and unwind errors in init_sd(). Fixes leaks on error,
if class_register() or scsi_register_driver() failed.
- Ensure that exit_sd() execution order is the perfect inverse of
initialization order.
FIXME: If some-but-not-all register_blkdev() calls fail, we wind up
calling unregister_blkdev() for block devices we did not register.
This was a pre-existing bug.
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 638cff4..7a9d552 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1795,7 +1795,7 @@ static void sd_shutdown(struct device *dev) **/ static int __init init_sd(void) { - int majors = 0, i; + int majors = 0, i, err; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); @@ -1806,9 +1806,22 @@ static int __init init_sd(void) if (!majors) return -ENODEV; - class_register(&sd_disk_class); + err = class_register(&sd_disk_class); + if (err) + goto err_out; - return scsi_register_driver(&sd_template.gendrv); + err = scsi_register_driver(&sd_template.gendrv); + if (err) + goto err_out_class; + + return 0; + +err_out_class: + class_unregister(&sd_disk_class); +err_out: + for (i = 0; i < SD_MAJORS; i++) + unregister_blkdev(sd_major(i), "sd"); + return err; } /** @@ -1823,10 +1836,10 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); scsi_unregister_driver(&sd_template.gendrv); + class_unregister(&sd_disk_class); + for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); - - class_unregister(&sd_disk_class); } module_init(init_sd); |