lkml.org 
[lkml]   [2000]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
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/
\
 
 \ /
  Last update: 2005-03-22 12:38    [W:0.072 / U:1.204 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site