[PATCH] sd.c: handling resource allocation failure

From: Arnaldo Carvalho de Melo (acme@conectiva.com.br)
Date: Wed Aug 23 2000 - 10:14:46 EST


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/



This archive was generated by hypermail 2b29 : Wed Aug 23 2000 - 21:00:09 EST