Messages in this thread Patch in this message |  | | Date | Wed, 23 Aug 2000 12:14:46 -0300 | From | Arnaldo Carvalho de Melo <> | Subject | [PATCH] sd.c: handling resource allocation failure |
| |
Hi,
Please take a look and consider applying. If I made some mistake, I'm eager to get comments to keep on trying to help cleaning these resource allocations bugs, that with hot swapping devices popping up will lead to problems.
- Arnaldo
--- linux-2.4.0-test7-pre7/drivers/scsi/sd.c Sat Jul 8 23:33:40 2000 +++ linux-2.4.0-test7-pre7.acme/drivers/scsi/sd.c Wed Aug 23 09:31:35 2000 @@ -19,6 +19,9 @@ * scsi disks using eight major numbers. * * Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs. + * + * Modified by Arnaldo Carvalho de Melo <acme@conectiva.com.br> to + * check resource allocation in sd_init - 2000/08/22 */ #include <linux/config.h> @@ -522,26 +525,7 @@ revalidate: fop_revalidate_scsidisk }; -/* - * If we need more than one SCSI disk major (i.e. more than - * 16 SCSI disks), we'll have to kmalloc() more gendisks later. - */ - -static struct gendisk sd_gendisk = -{ - SCSI_DISK0_MAJOR, /* Major number */ - "sd", /* Major name */ - 4, /* Bits to shift to get real from partition */ - 1 << 4, /* Number of partitions per real */ - NULL, /* hd struct */ - NULL, /* block sizes */ - 0, /* number */ - NULL, /* internal */ - NULL, /* next */ - &sd_fops, /* file operations */ -}; - -static struct gendisk *sd_gendisks = &sd_gendisk; +static struct gendisk *sd_gendisks = NULL; #define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] #define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1] @@ -1035,14 +1019,22 @@ rscsi_disks = (Scsi_Disk *) kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); + if (!rscsi_disks) + goto cleanup_devfs; memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); /* for every (necessary) major: */ sd_sizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + if (!sd_sizes) + goto cleanup_rscsi_disks; memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); sd_blocksizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + if (!sd_blocksizes) + goto cleanup_sd_sizes; sd_hardsizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + if (!sd_hardsizes) + goto cleanup_sd_blocksizes; for (i = 0; i < sd_template.dev_max << 4; i++) { sd_blocksizes[i] = 1024; @@ -1056,19 +1048,25 @@ sd = (struct hd_struct *) kmalloc((sd_template.dev_max << 4) * sizeof(struct hd_struct), GFP_ATOMIC); + if (!sd) + goto cleanup_sd_hardsizes; memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); - if (N_USED_SD_MAJORS > 1) - sd_gendisks = (struct gendisk *) + sd_gendisks = (struct gendisk *) kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); + if (!sd_gendisks) + goto cleanup_sd; + memset(sd_gendisks, 0, N_USED_SD_MAJORS * sizeof(struct gendisk)); + for (i = 0; i < N_USED_SD_MAJORS; i++) { - sd_gendisks[i] = sd_gendisk; sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr, GFP_ATOMIC); - memset (sd_gendisks[i].de_arr, 0, - SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr); sd_gendisks[i].flags = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags, GFP_ATOMIC); + if (!sd_gendisks[i].de_arr || !sd_gendisks[i].flags) + goto cleanup_sd_gendisks; + memset (sd_gendisks[i].de_arr, 0, + SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr); memset (sd_gendisks[i].flags, 0, SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags); sd_gendisks[i].major = SD_MAJOR(i); @@ -1085,6 +1083,36 @@ LAST_SD_GENDISK.next = NULL; return 0; + +cleanup_sd_gendisks: + do { + if (sd_gendisks[i].de_arr) { + kfree(sd_gendisks[i].de_arr); + sd_gendisks[i].de_arr = NULL; + } + if (sd_gendisks[i].flags) { + kfree(sd_gendisks[i].flags); + sd_gendisks[i].flags = NULL; + } + } while(i--); + + kfree(sd_gendisks); +cleanup_sd: + kfree(sd); +cleanup_sd_hardsizes: + kfree(sd_hardsizes); +cleanup_sd_blocksizes: + kfree(sd_blocksizes); +cleanup_sd_sizes: + kfree(sd_sizes); +cleanup_rscsi_disks: + kfree(rscsi_disks); +cleanup_devfs: + for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) + devfs_unregister_blkdev(SD_MAJOR(i), "sd"); + + sd_registered--; + return 1; } @@ -1256,8 +1284,8 @@ /* If we are disconnecting a disk driver, sync and invalidate * everything */ - max_p = sd_gendisk.max_p; - start = i << sd_gendisk.minor_shift; + max_p = sd_gendisks->max_p; + start = i << sd_gendisks->minor_shift; for (j = max_p - 1; j >= 0; j--) { int index = start + j; @@ -1337,8 +1365,7 @@ read_ahead[SD_MAJOR(i)] = 0; } sd_template.dev_max = 0; - if (sd_gendisks != &sd_gendisk) - kfree(sd_gendisks); + kfree(sd_gendisks); } #endif /* MODULE */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
|  |