diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index f738b5ba02e065fbd202167d693b44300a3c73dc..943b0c672646934ec63599f3d4d10af4dfaccf1f 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -415,8 +415,7 @@ static struct floppy_drive_params drive_params[N_DRIVE];
 static struct floppy_drive_struct drive_state[N_DRIVE];
 static struct floppy_write_errors write_errors[N_DRIVE];
 static struct timer_list motor_off_timer[N_DRIVE];
-static struct gendisk disks[N_DRIVE];
-static char names[N_DRIVE][4];
+static struct gendisk *disks[N_DRIVE];
 static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
 
 /*
@@ -3772,7 +3771,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
 	}
 
 	UDRS->fd_device = minor(inode->i_rdev);
-	set_capacity(&disks[drive], floppy_sizes[minor(inode->i_rdev)]);
+	set_capacity(disks[drive], floppy_sizes[minor(inode->i_rdev)]);
 	if (old_dev != -1 && old_dev != minor(inode->i_rdev)) {
 		if (buffer_drive == drive)
 			buffer_track = -1;
@@ -3952,7 +3951,7 @@ static int floppy_revalidate(kdev_t dev)
 			process_fd_request();
 		}
 	}
-	set_capacity(&disks[drive], floppy_sizes[minor(dev)]);
+	set_capacity(disks[drive], floppy_sizes[minor(dev)]);
 	return res;
 }
 
@@ -4230,26 +4229,34 @@ static struct gendisk *floppy_find(int minor)
 	    !(allowed_drive_mask & (1 << drive)) ||
 	    fdc_state[FDC(drive)].version == FDC_NONE)
 		return NULL;
-	return &disks[drive];
+	return disks[drive];
 }
 
 int __init floppy_init(void)
 {
 	int i,unit,drive;
+	int err;
 
 	raw_cmd = NULL;
 
+	for (i=0; i<N_DRIVE; i++) {
+		disks[i] = alloc_disk();
+		if (!disks[i])
+			goto Enomem;
+	}
+
 	devfs_handle = devfs_mk_dir (NULL, "floppy", NULL);
 	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
 		printk("Unable to get major %d for floppy\n",MAJOR_NR);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
 	}
 
 	for (i=0; i<N_DRIVE; i++) {
-		disks[i].major = MAJOR_NR;
-		disks[i].first_minor = TOMINOR(i);
-		disks[i].fops = &floppy_fops;
-		sprintf(disks[i].disk_name, "fd%d", i);
+		disks[i]->major = MAJOR_NR;
+		disks[i]->first_minor = TOMINOR(i);
+		disks[i]->fops = &floppy_fops;
+		sprintf(disks[i]->disk_name, "fd%d", i);
 	}
 
 	blk_set_probe(MAJOR_NR, floppy_find);
@@ -4281,11 +4288,8 @@ int __init floppy_init(void)
 	use_virtual_dma = can_use_virtual_dma & 1;
 	fdc_state[0].address = FDC1;
 	if (fdc_state[0].address == -1) {
-		unregister_blkdev(MAJOR_NR,"fd");
-		del_timer(&fd_timeout);
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		blk_set_probe(MAJOR_NR, NULL);
-		return -ENODEV;
+		err = -ENODEV;
+		goto out1;
 	}
 #if N_FDC > 1
 	fdc_state[1].address = FDC2;
@@ -4293,11 +4297,8 @@ int __init floppy_init(void)
 
 	fdc = 0; /* reset fdc in case of unexpected interrupt */
 	if (floppy_grab_irq_and_dma()){
-		del_timer(&fd_timeout);
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		unregister_blkdev(MAJOR_NR,"fd");
-		blk_set_probe(MAJOR_NR, NULL);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out1;
 	}
 
 	/* initialise drive state */
@@ -4352,15 +4353,13 @@ int __init floppy_init(void)
 	current_drive = 0;
 	floppy_release_irq_and_dma();
 	initialising=0;
-	if (have_no_fdc) 
-	{
+	if (have_no_fdc) {
 		DPRINT("no floppy controllers found\n");
 		flush_scheduled_work();
 		if (usage_count)
 			floppy_release_irq_and_dma();
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		unregister_blkdev(MAJOR_NR,"fd");
-		blk_set_probe(MAJOR_NR, NULL);
+		err = have_no_fdc;
+		goto out2;
 	}
 	
 	for (drive = 0; drive < N_DRIVE; drive++) {
@@ -4370,12 +4369,27 @@ int __init floppy_init(void)
 			continue;
 		if (fdc_state[FDC(drive)].version == FDC_NONE)
 			continue;
-		add_disk(disks + drive);
+		add_disk(disks[drive]);
 	}
 
 	platform_device_register(&floppy_device);
+	return 0;
 
-	return have_no_fdc;
+out1:
+	del_timer(&fd_timeout);
+out2:
+	unregister_blkdev(MAJOR_NR,"fd");
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	blk_set_probe(MAJOR_NR, NULL);
+out:
+	for (i=0; i<N_DRIVE; i++)
+		put_disk(disks[i]);
+	return err;
+
+Enomem:
+	while (i--)
+		put_disk(disks[i]);
+	return -ENOMEM;
 }
 
 static spinlock_t floppy_usage_lock = SPIN_LOCK_UNLOCKED;
@@ -4564,7 +4578,8 @@ void cleanup_module(void)
 	for (drive = 0; drive < N_DRIVE; drive++) {
 		if ((allowed_drive_mask & (1 << drive)) &&
 		    fdc_state[FDC(drive)].version != FDC_NONE)
-			del_gendisk(disks + drive);
+			del_gendisk(disks[drive]);
+		put_disk(disks[drive]);
 	}
 
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f5585acc12f68f55fcb75779f40055ea0072e1a8..090917c43969f869bc076b0ea35fbd81ab62507b 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -83,7 +83,7 @@
 
 static int max_loop = 8;
 static struct loop_device *loop_dev;
-static struct gendisk *disks;
+static struct gendisk **disks;
 static devfs_handle_t devfs_handle;      /*  For the directory */
 
 /*
@@ -159,9 +159,7 @@ struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
 static void figure_loop_size(struct loop_device *lo)
 {
 	loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_size;
-
-	set_capacity(disks + lo->lo_number,
-		     (size - lo->lo_offset) >> 9);
+	set_capacity(disks[lo->lo_number], (size - lo->lo_offset) >> 9);
 }
 
 static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
@@ -809,7 +807,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
 	memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
 	memset(lo->lo_name, 0, LO_NAME_SIZE);
 	invalidate_bdev(bdev, 0);
-	set_capacity(disks + lo->lo_number, 0);
+	set_capacity(disks[lo->lo_number], 0);
 	filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp;
 	lo->lo_state = Lo_unbound;
 	fput(filp);
@@ -1048,20 +1046,25 @@ int __init loop_init(void)
 	if (!loop_dev)
 		return -ENOMEM;
 
-	disks = kmalloc(max_loop * sizeof(struct gendisk), GFP_KERNEL);
+	disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
 	if (!disks)
 		goto out_mem;
 
+	for (i = 0; i < max_loop; i++) {
+		disks[i] = alloc_disk();
+		if (!disks[i])
+			goto out_mem2;
+	}
+
 	for (i = 0; i < max_loop; i++) {
 		struct loop_device *lo = &loop_dev[i];
-		struct gendisk *disk = disks + i;
+		struct gendisk *disk = disks[i];
 		memset(lo, 0, sizeof(struct loop_device));
 		init_MUTEX(&lo->lo_ctl_mutex);
 		init_MUTEX_LOCKED(&lo->lo_sem);
 		init_MUTEX_LOCKED(&lo->lo_bh_mutex);
 		lo->lo_number = i;
 		spin_lock_init(&lo->lo_lock);
-		memset(disk, 0, sizeof(struct gendisk));
 		disk->major = LOOP_MAJOR;
 		disk->first_minor = i;
 		disk->fops = &lo_fops;
@@ -1074,6 +1077,9 @@ int __init loop_init(void)
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
+out_mem2:
+	while (i--)
+		put_disk(disks[i]);
 out_mem:
 	kfree(disks);
 	kfree(loop_dev);
@@ -1084,8 +1090,10 @@ int __init loop_init(void)
 void loop_exit(void) 
 {
 	int i;
-	for (i = 0; i < max_loop; i++)
-		del_gendisk(disks + i);
+	for (i = 0; i < max_loop; i++) {
+		del_gendisk(disks[i]);
+		put_disk(disks[i]);
+	}
 	devfs_unregister(devfs_handle);
 	if (unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index f6aec9fe3ef54eabc8d92918b7d24faa8e7783b3..7fdf4a3e4b2a4bc42286703889ce6135fcc0d0db 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -276,7 +276,7 @@ struct pd_unit {
 	int alt_geom;
 	int present;
 	char name[PD_NAMELEN];	/* pda, pdb, etc ... */
-	struct gendisk gd;
+	struct gendisk *gd;
 };
 
 struct pd_unit pd[PD_UNITS];
@@ -287,8 +287,6 @@ static void pd_doorlock(struct pd_unit *disk, int func);
 static int pd_check_media(kdev_t dev);
 static void pd_eject(struct pd_unit *disk);
 
-/*  'unit' must be defined in all functions - either as a local or a param */
-
 static char pd_scratch[512];	/* scratch block buffer */
 
 /* the variables below are used mainly in the I/O request engine, which
@@ -368,11 +366,8 @@ static int pd_ioctl(struct inode *inode, struct file *file,
 	 unsigned int cmd, unsigned long arg)
 {
 	struct hd_geometry *geo = (struct hd_geometry *) arg;
-	int err, unit = DEVICE_NR(inode->i_rdev);
-	struct pd_unit *disk = pd + unit;
-
-	if (!disk->present)
-		return -ENODEV;
+	struct hd_geometry g;
+	struct pd_unit *disk = pd + DEVICE_NR(inode->i_rdev);
 
 	switch (cmd) {
 	case CDROMEJECT:
@@ -380,23 +375,18 @@ static int pd_ioctl(struct inode *inode, struct file *file,
 			pd_eject(disk);
 		return 0;
 	case HDIO_GETGEO:
-		if (!geo)
-			return -EINVAL;
-		err = verify_area(VERIFY_WRITE, geo, sizeof (*geo));
-		if (err)
-			return err;
-
 		if (disk->alt_geom) {
-			put_user(disk->capacity / (PD_LOG_HEADS * PD_LOG_SECTS),
-				 (short *) &geo->cylinders);
-			put_user(PD_LOG_HEADS, (char *) &geo->heads);
-			put_user(PD_LOG_SECTS, (char *) &geo->sectors);
+			g.heads = PD_LOG_HEADS;
+			g.sectors = PD_LOG_SECTS;
+			g.cylinders = disk->capacity / (g.heads * g.sectors);
 		} else {
-			put_user(disk->cylinders, (short *) &geo->cylinders);
-			put_user(disk->heads, (char *) &geo->heads);
-			put_user(disk->sectors, (char *) &geo->sectors);
+			g.heads = disk->heads;
+			g.sectors = disk->sectors;
+			g.cylinders = disk->cylinders;
 		}
-		put_user(get_start_sect(inode->i_bdev), (long *) &geo->start);
+		g.start = get_start_sect(inode->i_bdev);
+		if (copy_to_user(geo, &g, sizeof(struct hd_geometry)))
+			return -EFAULT;
 		return 0;
 	default:
 		return -EINVAL;
@@ -418,8 +408,6 @@ static int pd_check_media(kdev_t dev)
 {
 	int r, unit = DEVICE_NR(dev);
 	struct pd_unit *disk = pd + unit;
-	if (unit >= PD_UNITS || (!disk->present))
-		return -ENODEV;
 	if (!disk->removable)
 		return 0;
 	pd_media_check(disk);
@@ -432,12 +420,10 @@ static int pd_revalidate(kdev_t dev)
 {
 	int unit = DEVICE_NR(dev);
 	struct pd_unit *disk = pd + unit;
-	if (unit >= PD_UNITS || !disk->present)
-		return -ENODEV;
 	if (pd_identify(disk))
-		set_capacity(&disk->gd, disk->capacity);
+		set_capacity(disk->gd, disk->capacity);
 	else
-		set_capacity(&disk->gd, 0);
+		set_capacity(disk->gd, 0);
 	return 0;
 }
 
@@ -717,13 +703,20 @@ static int pd_detect(void)
 	}
 	for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
 		if (disk->present) {
-			strcpy(disk->gd.disk_name, disk->name);
-			disk->gd.minor_shift = PD_BITS;
-			disk->gd.fops = &pd_fops;
-			disk->gd.major = major;
-			disk->gd.first_minor = unit << PD_BITS;
-			set_capacity(&disk->gd, disk->capacity);
-			add_disk(&disk->gd);
+			struct gendisk *p = alloc_disk();
+			if (!p) {
+				disk->present = 0;
+				k--;
+				continue;
+			}
+			strcpy(p->disk_name, disk->name);
+			p->minor_shift = PD_BITS;
+			p->fops = &pd_fops;
+			p->major = major;
+			p->first_minor = unit << PD_BITS;
+			set_capacity(p, disk->capacity);
+			disk->gd = p;
+			add_disk(p);
 		}
 	}
 	if (k)
@@ -760,7 +753,7 @@ static void do_pd_request(request_queue_t * q)
 	pd_run = pd_req->nr_sectors;
 	pd_count = pd_req->current_nr_sectors;
 	pd_current = pd + unit;
-	if (pd_block + pd_count > get_capacity(&pd_current->gd)) {
+	if (pd_block + pd_count > get_capacity(pd_current->gd)) {
 		end_request(pd_req, 0);
 		goto repeat;
 	}
@@ -942,7 +935,10 @@ static void __exit pd_exit(void)
 	unregister_blkdev(MAJOR_NR, name);
 	for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
 		if (disk->present) {
-			del_gendisk(&disk->gd);
+			struct gendisk *p = disk->gd;
+			disk->gd = NULL;
+			del_gendisk(p);
+			put_disk(p);
 			pi_release(disk->pi);
 		}
 	}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 6e7ffb54f016a28901e8adef1fdde18153d8d8cb..4ebb02d724ee592774e57069644e29b997962b8c 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -77,7 +77,7 @@ int initrd_below_start_ok;
  */
 
 static unsigned long rd_length[NUM_RAMDISKS];	/* Size of RAM disks in bytes   */
-static struct gendisk rd_disks[NUM_RAMDISKS];
+static struct gendisk *rd_disks[NUM_RAMDISKS];
 static devfs_handle_t devfs_handle;
 static struct block_device *rd_bdev[NUM_RAMDISKS];/* Protected device data */
 
@@ -310,13 +310,7 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
 #ifdef CONFIG_BLK_DEV_INITRD
 
 static struct block_device_operations rd_bd_op;
-static struct gendisk initrd_disk = {
-	.major = MAJOR_NR,
-	.first_minor = INITRD_MINOR,
-	.minor_shift = 0,
-	.fops = &rd_bd_op,	
-	.disk_name = "initrd"
-};
+static struct gendisk *initrd_disk;
 
 static ssize_t initrd_read(struct file *file, char *buf,
 			   size_t count, loff_t *ppos)
@@ -340,7 +334,7 @@ static int initrd_release(struct inode *inode,struct file *file)
 	spin_lock(&initrd_users_lock);
 	if (!--initrd_users) {
 		spin_unlock(&initrd_users_lock);
-		del_gendisk(&initrd_disk);
+		del_gendisk(initrd_disk);
 		free_initrd_mem(initrd_start, initrd_end);
 		initrd_start = 0;
 	} else {
@@ -412,8 +406,12 @@ static void __exit rd_cleanup (void)
 			invalidate_bdev(bdev, 1);
 			blkdev_put(bdev, BDEV_FILE);
 		}
-		del_gendisk(rd_disks + i);
+		del_gendisk(rd_disks[i]);
+		put_disk(rd_disks[i]);
 	}
+#ifdef CONFIG_BLK_DEV_INITRD
+	put_disk(initrd_disk);
+#endif
 
 	devfs_unregister (devfs_handle);
 	unregister_blkdev( MAJOR_NR, "ramdisk" );
@@ -423,6 +421,7 @@ static void __exit rd_cleanup (void)
 static int __init rd_init (void)
 {
 	int i;
+	int err = -ENOMEM;
 
 	if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
 	    (rd_blocksize & (rd_blocksize-1))) {
@@ -431,15 +430,32 @@ static int __init rd_init (void)
 		rd_blocksize = BLOCK_SIZE;
 	}
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_disk = alloc_disk();
+	if (!initrd_disk)
+		return -ENOMEM;
+	initrd_disk->major = MAJOR_NR;
+	initrd_disk->first_minor = INITRD_MINOR;
+	initrd_disk->minor_shift = 0;
+	initrd_disk->fops = &rd_bd_op;	
+	sprintf(initrd_disk->disk_name, "initrd");
+#endif
+	for (i = 0; i < NUM_RAMDISKS; i++) {
+		rd_disks[i] = alloc_disk();
+		if (!rd_disks[i])
+			goto out;
+	}
+
 	if (register_blkdev(MAJOR_NR, "ramdisk", &rd_bd_op)) {
 		printk("RAMDISK: Could not get major %d", MAJOR_NR);
-		return -EIO;
+		err = -EIO;
+		goto out;
 	}
 
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_make_request);
 
 	for (i = 0; i < NUM_RAMDISKS; i++) {
-		struct gendisk *disk = rd_disks + i;
+		struct gendisk *disk = rd_disks[i];
 		/* rd_size is given in kB */
 		rd_length[i] = rd_size << 10;
 		disk->major = MAJOR_NR;
@@ -456,11 +472,11 @@ static int __init rd_init (void)
 			       &rd_bd_op, NULL);
 
 	for (i = 0; i < NUM_RAMDISKS; i++)
-		add_disk(rd_disks + i);
+		add_disk(rd_disks[i]);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* We ought to separate initrd operations here */
-	add_disk(&initrd_disk);
+	add_disk(initrd_disk);
 	devfs_register(devfs_handle, "initrd", DEVFS_FL_DEFAULT, MAJOR_NR,
 			INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL);
 #endif
@@ -471,6 +487,13 @@ static int __init rd_init (void)
 	       NUM_RAMDISKS, rd_size, rd_blocksize);
 
 	return 0;
+out:
+	while (i--)
+		put_disk(rd_disks[i]);
+#ifdef CONFIG_BLK_DEV_INITRD
+	put_disk(initrd_disk);
+#endif
+	return err;
 }
 
 module_init(rd_init);
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index 59148c11e1f7be76b914cfadf4b1e4cb4c9f7786..53f8fe2bafe2062c621259606a617671ee353166 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1690,13 +1690,7 @@ static int aztcd_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static struct gendisk azt_disk = {
-	.major = MAJOR_NR,
-	.first_minor = 0,
-	.minor_shift = 0,
-	.fops = &azt_fops,
-	.disk_name = "aztcd"
-};
+static struct gendisk *azt_disk;
 
 /*
  * Test for presence of drive and initialize it.  Called at boot time.
@@ -1844,6 +1838,7 @@ static int __init aztcd_init(void)
 				for (count = 0; count < AZT_TIMEOUT;
 				     count++)
 					barrier();	/* Stop gcc 2.96 being smart */
+				/* use udelay(), damnit -- AV */
 
 				if ((st = getAztStatus()) == -1) {
 					printk(KERN_WARNING "aztcd: Drive Status"
@@ -1913,21 +1908,33 @@ static int __init aztcd_init(void)
 	}
 	devfs_register(NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
 		       S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
+	azt_disk = alloc_disk();
+	if (!azt_disk)
+		goto err_out2;
 	if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) {
 		printk(KERN_WARNING "aztcd: Unable to get major %d for Aztech"
 		       " CD-ROM\n", MAJOR_NR);
 		ret = -EIO;
-		goto err_out;
+		goto err_out3;
 	}
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_aztcd_request, &aztSpin);
 	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
-	add_disk(&azt_disk);
+	azt_disk->major = MAJOR_NR;
+	azt_disk->first_minor = 0;
+	azt_disk->minor_shift = 0;
+	azt_disk->fops = &azt_fops;
+	sprintf(azt_disk->disk_name, "aztcd");
+	add_disk(azt_disk);
 
 	azt_invalidate_buffers();
 	aztPresent = 1;
 	aztCloseDoor();
 	return (0);
- err_out:
+err_out3:
+	put_disk(azt_disk);
+err_out2:
+	devfs_find_and_unregister(NULL, "aztcd", 0, 0, DEVFS_SPECIAL_BLK, 0);
+err_out:
 	if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
 		SWITCH_IDE_MASTER;
 		release_region(azt_port, 8);	/*IDE-interface */
@@ -1940,7 +1947,8 @@ static int __init aztcd_init(void)
 static void __exit aztcd_exit(void)
 {
 	devfs_find_and_unregister(NULL, "aztcd", 0, 0, DEVFS_SPECIAL_BLK, 0);
-	del_gendisk(&azt_disk);
+	del_gendisk(azt_disk);
+	put_disk(azt_disk);
 	if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) {
 		printk("What's that: can't unregister aztcd\n");
 		return;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 572af9fca9266975b3ed162c1308a01bf0398970..8863cb1254de7631333fb98f9763088d7892f868 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -3188,14 +3188,7 @@ static struct cdrom_device_info scd_info = {
 	.name		= "cdu31a"
 };
 
-static struct gendisk scd_gendisk = {
-	.major		= MAJOR_NR,
-	.first_minor	= 0,
-	.minor_shift	= 0,
-	.disk_name	= "cdu31a",
-	.fops		= &scd_bdops,
-	.flags		= GENHD_FL_CD,
-};
+static struct gendisk *scd_gendisk;
 
 /* The different types of disc loading mechanisms supported */
 static char *load_mech[] __initdata =
@@ -3299,7 +3292,8 @@ __setup("cdu31a=", cdu31a_setup);
 int __init cdu31a_init(void)
 {
 	struct s_sony_drive_config drive_config;
-	struct gendisk *disk = &scd_gendisk;
+	struct gendisk *disk;
+	int deficiency = 0;
 	unsigned int res_size;
 	char msg[255];
 	char buf[40];
@@ -3360,115 +3354,119 @@ int __init cdu31a_init(void)
 		}
 	}
 
-	if (drive_found) {
-		int deficiency = 0;
+	if (!drive_found)
+		goto errout3;
 
-		if (!request_region(cdu31a_port, 4, "cdu31a"))
-			goto errout3;
+	if (!request_region(cdu31a_port, 4, "cdu31a"))
+		goto errout3;
 
-		if (register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) {
-			printk("Unable to get major %d for CDU-31a\n",
-			       MAJOR_NR);
-			goto errout2;
-		}
+	if (register_blkdev(MAJOR_NR, "cdu31a", &scd_bdops)) {
+		printk("Unable to get major %d for CDU-31a\n",
+		       MAJOR_NR);
+		goto errout2;
+	}
 
-		if (SONY_HWC_DOUBLE_SPEED(drive_config)) {
-			is_double_speed = 1;
-		}
+	disk = alloc_disk();
+	if (!disk)
+		goto errout1;
+	disk->major = MAJOR_NR;
+	disk->first_minor = 0;
+	disk->minor_shift = 0;
+	sprintf(disk->disk_name, "cdu31a");
+	disk->fops = &scd_bdops;
+	disk->flags = GENHD_FL_CD;
 
-		tmp_irq = cdu31a_irq;	/* Need IRQ 0 because we can't sleep here. */
-		cdu31a_irq = 0;
+	if (SONY_HWC_DOUBLE_SPEED(drive_config))
+		is_double_speed = 1;
 
-		set_drive_params(sony_speed);
+	tmp_irq = cdu31a_irq;	/* Need IRQ 0 because we can't sleep here. */
+	cdu31a_irq = 0;
 
-		cdu31a_irq = tmp_irq;
+	set_drive_params(sony_speed);
 
-		if (cdu31a_irq > 0) {
-			if (request_irq
-			    (cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT,
-			     "cdu31a", NULL)) {
-				printk
-				    ("Unable to grab IRQ%d for the CDU31A driver\n",
-				     cdu31a_irq);
-				cdu31a_irq = 0;
-			}
-		}
+	cdu31a_irq = tmp_irq;
 
-		sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
-			drive_config.vendor_id,
-			drive_config.product_id,
-			drive_config.product_rev_level);
-		sprintf(buf, "  Capabilities: %s",
-			load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
-		strcat(msg, buf);
-		if (SONY_HWC_AUDIO_PLAYBACK(drive_config)) {
-			strcat(msg, ", audio");
-		} else
-			deficiency |= CDC_PLAY_AUDIO;
-		if (SONY_HWC_EJECT(drive_config)) {
-			strcat(msg, ", eject");
-		} else
-			deficiency |= CDC_OPEN_TRAY;
-		if (SONY_HWC_LED_SUPPORT(drive_config)) {
-			strcat(msg, ", LED");
-		}
-		if (SONY_HWC_ELECTRIC_VOLUME(drive_config)) {
-			strcat(msg, ", elec. Vol");
-		}
-		if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config)) {
-			strcat(msg, ", sep. Vol");
-		}
-		if (is_double_speed) {
-			strcat(msg, ", double speed");
-		} else
-			deficiency |= CDC_SELECT_SPEED;
-		if (cdu31a_irq > 0) {
-			sprintf(buf, ", irq %d", cdu31a_irq);
-			strcat(msg, buf);
+	if (cdu31a_irq > 0) {
+		if (request_irq
+		    (cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT,
+		     "cdu31a", NULL)) {
+			printk
+			    ("Unable to grab IRQ%d for the CDU31A driver\n",
+			     cdu31a_irq);
+			cdu31a_irq = 0;
 		}
-		strcat(msg, "\n");
+	}
 
-		is_a_cdu31a =
-		    strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
+	sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n",
+		drive_config.vendor_id,
+		drive_config.product_id,
+		drive_config.product_rev_level);
+	sprintf(buf, "  Capabilities: %s",
+		load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]);
+	strcat(msg, buf);
+	if (SONY_HWC_AUDIO_PLAYBACK(drive_config))
+		strcat(msg, ", audio");
+	else
+		deficiency |= CDC_PLAY_AUDIO;
+	if (SONY_HWC_EJECT(drive_config))
+		strcat(msg, ", eject");
+	else
+		deficiency |= CDC_OPEN_TRAY;
+	if (SONY_HWC_LED_SUPPORT(drive_config))
+		strcat(msg, ", LED");
+	if (SONY_HWC_ELECTRIC_VOLUME(drive_config))
+		strcat(msg, ", elec. Vol");
+	if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config))
+		strcat(msg, ", sep. Vol");
+	if (is_double_speed)
+		strcat(msg, ", double speed");
+	else
+		deficiency |= CDC_SELECT_SPEED;
+	if (cdu31a_irq > 0) {
+		sprintf(buf, ", irq %d", cdu31a_irq);
+		strcat(msg, buf);
+	}
+	strcat(msg, "\n");
 
-		blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
-			       do_cdu31a_request,
-			       &cdu31a_lock);
+	is_a_cdu31a =
+	    strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
 
-		init_timer(&cdu31a_abort_timer);
-		cdu31a_abort_timer.function = handle_abort_timeout;
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
+		       do_cdu31a_request,
+		       &cdu31a_lock);
 
-		scd_info.dev = mk_kdev(MAJOR_NR, 0);
-		scd_info.mask = deficiency;
-		if (register_cdrom(&scd_info))
-			goto errout0;
-		add_disk(disk);
-	}
+	init_timer(&cdu31a_abort_timer);
+	cdu31a_abort_timer.function = handle_abort_timeout;
 
+	scd_info.dev = mk_kdev(MAJOR_NR, 0);
+	scd_info.mask = deficiency;
+	scd_gendisk = disk;
+	if (register_cdrom(&scd_info))
+		goto errout0;
+	add_disk(disk);
 
 	disk_changed = 1;
+	return (0);
 
-	if (drive_found) {
-		return (0);
-	} else {
-		goto errout3;
-	}
-      errout0:
+errout0:
 	printk("Unable to register CDU-31a with Uniform cdrom driver\n");
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	put_disk(disk);
+errout1:
 	if (unregister_blkdev(MAJOR_NR, "cdu31a")) {
 		printk("Can't unregister block device for cdu31a\n");
 	}
-      errout2:
+errout2:
 	release_region(cdu31a_port, 4);
-      errout3:
+errout3:
 	return -EIO;
 }
 
 
 void __exit cdu31a_exit(void)
 {
-	del_gendisk(&scd_gendisk);
+	del_gendisk(scd_gendisk);
+	put_disk(scd_gendisk);
 	if (unregister_cdrom(&scd_info)) {
 		printk
 		    ("Can't unregister cdu31a from Uniform cdrom driver\n");
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index c1074b4149143d25d120af9c7ff19aaab9dfe254..0da8b3bcdf30f2d0208ddc290eb2d3ff29e448f2 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1357,14 +1357,7 @@ static struct cdrom_device_info cm206_info = {
 	.name		= "cm206",
 };
 
-static struct gendisk cm206_gendisk = {
-	.major		= MAJOR_NR,
-	.first_minor	= 0,
-	.minor_shift	= 0,
-	.disk_name	= "cm206",
-	.fops		= &cm206_bdops,
-	.flags		= GENHD_FL_CD,
-};
+static struct gendisk *cm206_gendisk;
 
 /* This function probes for the adapter card. It returns the base
    address if it has found the adapter card. One can specify a base 
@@ -1419,7 +1412,7 @@ int __init cm206_init(void)
 {
 	uch e = 0;
 	long int size = sizeof(struct cm206_struct);
-	struct gendisk *disk = &cm206_gendisk;
+	struct gendisk *disk;
 
 	printk(KERN_INFO "cm206 cdrom driver " REVISION);
 	cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
@@ -1477,6 +1470,16 @@ int __init cm206_init(void)
 		printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR);
 		goto out_blkdev;
 	}
+	disk = alloc_disk();
+	if (!disk)
+		goto out_disk;
+	disk->major = MAJOR_NR;
+	disk->first_minor = 0;
+	disk->minor_shift = 0;
+	sprintf(disk->disk_name, "cm206");
+	disk->fops = &cm206_bdops;
+	disk->flags = GENHD_FL_CD;
+	cm206_gendisk = disk;
 	cm206_info.dev = mk_kdev(MAJOR_NR, 0);
 	if (register_cdrom(&cm206_info) != 0) {
 		printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR);
@@ -1498,6 +1501,8 @@ int __init cm206_init(void)
 	return 0;
 
 out_cdrom:
+	put_disk(disk);
+out_disk:
 	unregister_blkdev(MAJOR_NR, "cm206");
 out_blkdev:
 	free_irq(cm206_irq, NULL);
@@ -1536,7 +1541,8 @@ int __cm206_init(void)
 
 void __exit cm206_exit(void)
 {
-	del_gendisk(&cm206_gendisk);
+	del_gendisk(cm206_gendisk);
+	put_disk(cm206_gendisk);
 	if (unregister_cdrom(&cm206_info)) {
 		printk("Can't unregister cdrom cm206\n");
 		return;
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index c80cd3ca77351ce8539bbffa8f887202bcbe0534..9e8a14ce9374fc4b56c99b5b2b722a57f2c07467 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -898,20 +898,15 @@ static void update_state(void)
 }
 #endif
 
-static struct gendisk gscd_disk = {
-	.major = MAJOR_NR,
-	.first_minor = 0,
-	.minor_shift = 0,
-	.fops = &gscd_fops,
-	.disk_name = "gscd"
-};
+static struct gendisk *gscd_disk;
 
 static void __exit gscd_exit(void)
 {
 	CLEAR_TIMER;
 
 	devfs_find_and_unregister(NULL, "gscd", 0, 0, DEVFS_SPECIAL_BLK, 0);
-	del_gendisk(&gscd_disk);
+	del_gendisk(gscd_disk);
+	put_disk(gscd_disk);
 	if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
 		printk("What's that: can't unregister GoldStar-module\n");
 		return;
@@ -977,11 +972,20 @@ static int __init gscd_init(void)
 		i++;
 	}
 
+	gscd_disk = alloc_disk();
+	if (!gscd_disk)
+		goto err_out1;
+	gscd_disk->major = MAJOR_NR;
+	gscd_disk->first_minor = 0;
+	gscd_disk->minor_shift = 0;
+	gscd_disk->fops = &gscd_fops;
+	sprintf(gscd_disk->disk_name, "gscd");
+
 	if (register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0) {
 		printk(KERN_WARNING "GSCD: Unable to get major %d for GoldStar "
 		       "CD-ROM\n", MAJOR_NR);
 		ret = -EIO;
-		goto err_out1;
+		goto err_out2;
 	}
 	devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
 		       S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL);
@@ -991,10 +995,13 @@ static int __init gscd_init(void)
 	disk_state = 0;
 	gscdPresent = 1;
 
-	add_disk(&gscd_disk);
+	add_disk(gscd_disk);
 
 	printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
 	return 0;
+
+err_out2:
+	put_disk(gscd_disk);
 err_out1:
 	release_region(gscd_port, GSCD_IO_EXTENT);
 	return ret;
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index 1b2a958968b0344c0631ed5d88f12fc6cf0c2587..39eff9436cbfee5b2869ff9f67d470a57cd444b1 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -221,14 +221,7 @@ static struct cdrom_device_info mcd_info = {
 	.name		= "mcd",
 };
 
-static struct gendisk mcd_gendisk = {
-	.major		= MAJOR_NR,
-	.first_minor	= 0,
-	.minor_shift	= 0,
-	.disk_name	= "mcd",
-	.fops		= &mcd_bdops,
-	.flags		= GENHD_FL_CD,
-};
+static struct gendisk *mcd_gendisk;
 
 #ifndef MODULE
 static int __init mcd_setup(char *str)
@@ -1038,18 +1031,23 @@ static void mcd_release(struct cdrom_device_info *cdi)
 
 int __init mcd_init(void)
 {
-	struct gendisk *disk = &mcd_gendisk;
+	struct gendisk *disk = alloc_disk();
 	int count;
 	unsigned char result[3];
 	char msg[80];
 
+	if (!disk) {
+		printk(KERN_INFO "mcd: can't allocated disk.\n");
+		return -ENOMEM;
+	}
 	if (mcd_port <= 0 || mcd_irq <= 0) {
 		printk(KERN_INFO "mcd: not probing.\n");
+		put_disk(disk);
 		return -EIO;
 	}
-
 	if (register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) {
 		printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);
+		put_disk(disk);
 		return -EIO;
 	}
 	if (!request_region(mcd_port, 4, "mcd")) {
@@ -1124,6 +1122,13 @@ int __init mcd_init(void)
 	mcd_invalidate_buffers();
 	mcdPresent = 1;
 
+	disk->major = MAJOR_NR;
+	disk->first_minor = 0;
+	disk->minor_shift = 0;
+	sprintf(disk->disk_name, "mcd");
+	disk->fops = &mcd_bdops;
+	disk->flags = GENHD_FL_CD;
+	mcd_gendisk = disk;
 	mcd_info.dev = mk_kdev(MAJOR_NR, 0);
 
 	if (register_cdrom(&mcd_info) != 0) {
@@ -1141,6 +1146,7 @@ int __init mcd_init(void)
 out_region:
 	unregister_blkdev(MAJOR_NR, "mcd");
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	put_disk(disk);
 	return -EIO;
 }
 
@@ -1506,7 +1512,8 @@ static int GetToc(void)
 
 void __exit mcd_exit(void)
 {
-	del_gendisk(&mcd_gendisk);
+	del_gendisk(mcd_gendisk);
+	put_disk(mcd_gendisk);
 	if (unregister_cdrom(&mcd_info)) {
 		printk(KERN_WARNING "Can't unregister cdrom mcd\n");
 		return;
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 85eeb621ba0c8e423de0724f50bae986d4414563..7b6aaace0be1db6bda0e627eb63a5c8bc1a572e6 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -206,7 +206,7 @@ struct s_drive_stuff {
 	int status;		/* last operation's error / status */
 	int readerrs;		/* # of blocks read w/o error */
 	struct cdrom_device_info info;
-	struct gendisk disk;
+	struct gendisk *disk;
 };
 
 
@@ -1021,11 +1021,12 @@ void __exit mcdx_exit(void)
 		struct s_drive_stuff *stuffp = mcdx_stuffp[i];
 		if (!stuffp)
 			continue;
-		del_gendisk(&stuffp->disk);
+		del_gendisk(stuffp->disk);
 		if (unregister_cdrom(&stuffp->info)) {
 			printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
-			return;
+			continue;
 		}
+		put_disk(stuffp->disk);
 		release_region((unsigned long) stuffp->wreg_data,
 			       MCDX_IO_SIZE);
 		free_irq(stuffp->irq, NULL);
@@ -1075,6 +1076,13 @@ int __init mcdx_init_drive(int drive)
 		return 1;
 	}
 
+	disk = alloc_disk();
+	if (!disk) {
+		xwarn("init() malloc failed\n");
+		kfree(stuffp);
+		return 1;
+	}
+
 	xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
 	       sizeof(*stuffp), stuffp);
 
@@ -1106,6 +1114,7 @@ int __init mcdx_init_drive(int drive)
 		      stuffp->wreg_data + MCDX_IO_SIZE - 1);
 		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
 		kfree(stuffp);
+		put_disk(disk);
 		xtrace(INIT, "init() continue at next drive\n");
 		return 0;	/* next drive */
 	}
@@ -1124,6 +1133,7 @@ int __init mcdx_init_drive(int drive)
 		      MCDX, stuffp->wreg_data, stuffp->irq);
 		xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
 		kfree(stuffp);
+		put_disk(disk);
 		xtrace(INIT, "init() continue at next drive\n");
 		return 0;
 	}
@@ -1154,6 +1164,7 @@ int __init mcdx_init_drive(int drive)
 		xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
 		      MCDX, stuffp->wreg_data, stuffp->irq);
 		kfree(stuffp);
+		put_disk(disk);
 		return 0;	/* next drive */
 	}
 
@@ -1164,6 +1175,7 @@ int __init mcdx_init_drive(int drive)
 		xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
 		      MCDX, stuffp->wreg_data, stuffp->irq, MAJOR_NR);
 		kfree(stuffp);
+		put_disk(disk);
 		return 1;
 	}
 
@@ -1180,6 +1192,7 @@ int __init mcdx_init_drive(int drive)
 		stuffp->irq = 0;
 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 		kfree(stuffp);
+		put_disk(disk);
 		return 0;
 	}
 
@@ -1206,13 +1219,13 @@ int __init mcdx_init_drive(int drive)
 	stuffp->info.handle = stuffp;
 	sprintf(stuffp->info.name, "mcdx%d", drive);
 	stuffp->info.dev = mk_kdev(MAJOR_NR, drive);
-	disk = &stuffp->disk;
 	disk->major = MAJOR_NR;
 	disk->first_minor = drive;
 	disk->minor_shift = 0;
 	strcpy(disk->disk_name, stuffp->info.name);
 	disk->fops = &mcdx_bdops;
 	disk->flags = GENHD_FL_CD;
+	stuffp->disk = disk;
 
 	sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
 		" (Firmware version %c %x)\n",
@@ -1225,6 +1238,7 @@ int __init mcdx_init_drive(int drive)
 			       MCDX_IO_SIZE);
 		free_irq(stuffp->irq, NULL);
 		kfree(stuffp);
+		put_disk(disk);
 		if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
 			xwarn("cleanup() unregister_blkdev() failed\n");
 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 8b1da1b5b5f9298e14c3b9e8ad7c536d494e53c6..baf39fd6f7080f89c9ffdbea94c03d02c974d90b 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -1997,13 +1997,7 @@ __setup("optcd=", optcd_setup);
 
 #endif /* MODULE */
 
-static struct gendisk optcd_disk = {
-	.major = MAJOR_NR,
-	.first_minor = 0,
-	.minor_shift = 0,
-	.fops = &opt_fops,
-	.disk_name = "optcd"
-};
+static struct gendisk *optcd_disk;
 
 /* Test for presence of drive and initialize it. Called at boot time
    or during module initialisation. */
@@ -2016,20 +2010,33 @@ static int __init optcd_init(void)
 			"optcd: no Optics Storage CDROM Initialization\n");
 		return -EIO;
 	}
+	optcd_disk = alloc_disk();
+	if (!optcd_disk) {
+		printk(KERN_ERR "optcd: can't allocate disk\n");
+		return -ENOMEM;
+	}
+	optcd_disk->major = MAJOR_NR;
+	optcd_disk->first_minor = 0;
+	optcd_disk->minor_shift = 0;
+	optcd_disk->fops = &opt_fops;
+	sprintf(optcd_disk->disk_name, "optcd");
 	if (!request_region(optcd_port, 4, "optcd")) {
 		printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
 			optcd_port);
+		put_disk(optcd_disk);
 		return -EIO;
 	}
 
 	if (!reset_drive()) {
 		printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
 		release_region(optcd_port, 4);
+		put_disk(optcd_disk);
 		return -EIO;
 	}
 	if (!version_ok()) {
 		printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
 		release_region(optcd_port, 4);
+		put_disk(optcd_disk);
 		return -EIO;
 	}
 	status = exec_cmd(COMINITDOUBLE);
@@ -2037,11 +2044,13 @@ static int __init optcd_init(void)
 		printk(KERN_ERR "optcd: cannot init double speed mode\n");
 		release_region(optcd_port, 4);
 		DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
+		put_disk(optcd_disk);
 		return -EIO;
 	}
 	if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0) {
 		printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
 		release_region(optcd_port, 4);
+		put_disk(optcd_disk);
 		return -EIO;
 	}
 	devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
@@ -2049,7 +2058,7 @@ static int __init optcd_init(void)
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_optcd_request,
 		       &optcd_lock);
 	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
-	add_disk(&optcd_disk);
+	add_disk(optcd_disk);
 
 	printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
 	return 0;
@@ -2059,7 +2068,8 @@ static int __init optcd_init(void)
 static void __exit optcd_exit(void)
 {
 	devfs_find_and_unregister(NULL, "optcd", 0, 0, DEVFS_SPECIAL_BLK, 0);
-	del_gendisk(&optcd_disk);
+	del_gendisk(optcd_disk);
+	put_disk(optcd_disk);
 	if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
 		printk(KERN_ERR "optcd: what's that: can't unregister\n");
 		return;
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 37c1e773fb04e9de7fe3163f91237d14609d1815..409aea0c4f0fca3d30215568b6aa4c13f9102f0f 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -722,7 +722,7 @@ static struct sbpcd_drive {
 	u_char mode_xb_8;
 	u_char delay;
 	struct cdrom_device_info *sbpcd_infop;
-	struct gendisk disk;
+	struct gendisk *disk;
 } D_S[NR_SBPCD];
 
 static struct sbpcd_drive *current_drive = D_S;
@@ -5609,6 +5609,7 @@ static int __init config_spea(void)
 
 static devfs_handle_t devfs_handle;
 
+/* FIXME: cleanups after failed allocations are too ugly for words */
 #ifdef MODULE
 int __init __sbpcd_init(void)
 #else
@@ -5830,7 +5831,7 @@ int __init sbpcd_init(void)
 		sbpcd_infop->dev = mk_kdev(MAJOR_NR, j);
 		sbpcd_infop->handle = p;
 		p->sbpcd_infop = sbpcd_infop;
-		disk = &p->disk;
+		disk = alloc_disk();
 		disk->major = MAJOR_NR;
 		disk->first_minor = j;
 		disk->minor_shift = 0;
@@ -5839,6 +5840,7 @@ int __init sbpcd_init(void)
 		disk->flags = GENHD_FL_CD;
 		sprintf(nbuff, "c0t%d", p->drv_id);
 		disk->de = devfs_mk_dir(devfs_handle, nbuff, NULL);
+		p->disk = disk;
 		if (register_cdrom(sbpcd_infop))
 		{
 			printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n");
@@ -5869,7 +5871,8 @@ void sbpcd_exit(void)
 	for (j=0;j<NR_SBPCD;j++)
 	{
 		if (D_S[j].drv_id==-1) continue;
-		del_gendisk(&D_S[j].disk);
+		del_gendisk(D_S[j].disk);
+		put_disk(D_S[j].disk);
 		vfree(D_S[j].sbp_buf);
 		if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf);
 		devfs_unregister(D_S[j].disk.de);
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index edceb3a3dc856edd3ce05c0e2d101e26fc006ec5..c0464754862503eac818a1bae5b51a12cf4bdd0a 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -159,8 +159,6 @@ static struct timer_list sjcd_delay_timer;
 
 #define CLEAR_TIMER del_timer( &sjcd_delay_timer )
 
-static int sjcd_cleanup(void);
-
 /*
  * Set up device, i.e., use command line data to set
  * base address.
@@ -1664,14 +1662,7 @@ static struct {
 	unsigned char major, minor;
 } sjcd_version;
 
-static struct gendisk sjcd_disk =
-{
-	.major = MAJOR_NR,
-	.first_minor = 0,
-	.minor_shift = 0,
-	.fops = &sjcd_fops,
-	.disk_name = "sjcd"
-};
+static struct gendisk *sjcd_disk;
 
 /*
  * Test for presence of drive and initialize it. Called at boot time.
@@ -1698,12 +1689,22 @@ static int __init sjcd_init(void)
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock);
 	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 
+	sjcd_disk = alloc_disk();
+	if (!sjcd_disk) {
+		printk(KERN_ERR "SJCD: can't allocate disk");
+		goto out1;
+	}
+	sjcd_disk->major = MAJOR_NR,
+	sjcd_disk->first_minor = 0,
+	sjcd_disk->minor_shift = 0,
+	sjcd_disk->fops = &sjcd_fops,
+	sprintf(sjcd_disk->disk_name, "sjcd");
+
 	if (check_region(sjcd_base, 4)) {
 		printk
 		    ("SJCD: Init failed, I/O port (%X) is already in use\n",
 		     sjcd_base);
-		sjcd_cleanup();
-		return (-EIO);
+		goto out2;
 	}
 
 	/*
@@ -1725,8 +1726,7 @@ static int __init sjcd_init(void)
 	}
 	if (i == 0 || sjcd_command_failed) {
 		printk(" reset failed, no drive found.\n");
-		sjcd_cleanup();
-		return (-EIO);
+		goto out3;
 	} else
 		printk("\n");
 
@@ -1748,8 +1748,7 @@ static int __init sjcd_init(void)
 	}
 	if (i == 0 || sjcd_command_failed) {
 		printk(" get version failed, no drive found.\n");
-		sjcd_cleanup();
-		return (-EIO);
+		goto out3;
 	}
 
 	if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) {
@@ -1757,8 +1756,7 @@ static int __init sjcd_init(void)
 		       (int) sjcd_version.minor);
 	} else {
 		printk(" read version failed, no drive found.\n");
-		sjcd_cleanup();
-		return (-EIO);
+		goto out3;
 	}
 
 	/*
@@ -1781,8 +1779,7 @@ static int __init sjcd_init(void)
 		}
 		if (i == 0 || sjcd_command_failed) {
 			printk(" get status failed, no drive found.\n");
-			sjcd_cleanup();
-			return (-EIO);
+			goto out3;
 		} else
 			printk("\n");
 	}
@@ -1790,33 +1787,32 @@ static int __init sjcd_init(void)
 	printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
 	devfs_register(NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
 		       S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL);
-	add_disk(&sjcd_disk);
+	add_disk(sjcd_disk);
 
 	sjcd_present++;
 	return (0);
-}
-
-static int sjcd_cleanup(void)
-{
+out3:
+	release_region(sjcd_base, 4);
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+out2:
+	put_disk(sjcd_disk);
+out1:
 	if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL))
 		printk("SJCD: cannot unregister device.\n");
-	else {
-		release_region(sjcd_base, 4);
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-	}
-
-	return (0);
+	return (-EIO);
 }
 
-
 static void __exit sjcd_exit(void)
 {
 	devfs_find_and_unregister(NULL, "sjcd", 0, 0, DEVFS_SPECIAL_BLK, 0);
-	del_gendisk(&sjcd_disk);
-	if (sjcd_cleanup())
-		printk("SJCD: module: cannot be removed.\n");
-	else
-		printk(KERN_INFO "SJCD: module: removed.\n");
+	del_gendisk(sjcd_disk);
+	put_disk(sjcd_disk);
+	release_region(sjcd_base, 4);
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL))
+		printk("SJCD: cannot unregister device.\n");
+	printk(KERN_INFO "SJCD: module: removed.\n");
+	return (0);
 }
 
 module_init(sjcd_init);
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index cd28b4f1b3d26ab4815bed6581a126ca56d8abed..d73013c02bada67391d3effb4bf1d68d7bd9fd59 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1454,14 +1454,7 @@ static struct block_device_operations cdu_fops =
 	.check_media_change	= cdu535_check_media_change,
 };
 
-static struct gendisk cdu_disk =
-{
-	.major = MAJOR_NR,
-	.first_minor = 0,
-	.minor_shift = 0,
-	.fops = &cdu_fops,
-	.disk_name = "cdu",
-};
+static struct gendisk *cdu_disk;
 
 /*
  * Initialize the driver.
@@ -1477,6 +1470,7 @@ static int __init sony535_init(void)
 	int  tmp_irq;
 	int  i;
 	devfs_handle_t sony_devfs_handle;
+	int err;
 
 	/* Setting the base I/O address to 0 will disable it. */
 	if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0))
@@ -1518,145 +1512,142 @@ static int __init sony535_init(void)
 		sony_sleep();
 	}
 
-	if (got_result && (check_drive_status() != TIME_OUT)) {
-		/* CD-ROM drive responded --  get the drive configuration */
-		cmd_buff[0] = SONY535_INQUIRY;
-		if (do_sony_cmd(cmd_buff, 1, status,
-						(Byte *)&drive_config, 28, 1) == 0) {
-			/* was able to get the configuration,
-			 * set drive mode as rest of init
-			 */
+	if (!got_result || check_drive_status() == TIME_OUT)
+		goto Enodev;
+
+	/* CD-ROM drive responded --  get the drive configuration */
+	cmd_buff[0] = SONY535_INQUIRY;
+	if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0)
+		goto Enodev;
+
+	/* was able to get the configuration,
+	 * set drive mode as rest of init
+	 */
 #if DEBUG > 0
-			/* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
-			if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
-				printk(CDU535_MESSAGE_NAME
-						"Inquiry command returned status = 0x%x\n", status[0]);
+	/* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
+	if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
+		printk(CDU535_MESSAGE_NAME
+				"Inquiry command returned status = 0x%x\n", status[0]);
 #endif
-			/* now ready to use interrupts, if available */
-			sony535_irq_used = tmp_irq;
+	/* now ready to use interrupts, if available */
+	sony535_irq_used = tmp_irq;
 
-			/* A negative sony535_irq_used will attempt an autoirq. */
-			if (sony535_irq_used < 0) {
-				unsigned long irq_mask, delay;
+	/* A negative sony535_irq_used will attempt an autoirq. */
+	if (sony535_irq_used < 0) {
+		unsigned long irq_mask, delay;
 
-				irq_mask = probe_irq_on();
-				enable_interrupts();
-				outb(0, read_status_reg);	/* does a reset? */
-				delay = jiffies + HZ/10;
-				while (time_before(jiffies, delay)) ;
+		irq_mask = probe_irq_on();
+		enable_interrupts();
+		outb(0, read_status_reg);	/* does a reset? */
+		delay = jiffies + HZ/10;
+		while (time_before(jiffies, delay)) ;
 
-				sony535_irq_used = probe_irq_off(irq_mask);
-				disable_interrupts();
-			}
-			if (sony535_irq_used > 0) {
-			    if (request_irq(sony535_irq_used, cdu535_interrupt,
-								SA_INTERRUPT, CDU535_HANDLE, NULL)) {
-					printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
-							" driver; polling instead.\n", sony535_irq_used);
-					sony535_irq_used = 0;
-				}
-			}
-			cmd_buff[0] = SONY535_SET_DRIVE_MODE;
-			cmd_buff[1] = 0x0;	/* default audio */
-			if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) == 0) {
-				/* set the drive mode successful, we are set! */
-				sony_buffer_size = SONY535_BUFFER_SIZE;
-				sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE;
-
-				printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
-					   drive_config.vendor_id,
-					   drive_config.product_id,
-					   drive_config.product_rev_level);
-				printk("  base address %03X, ", sony535_cd_base_io);
-				if (tmp_irq > 0)
-					printk("IRQ%d, ", tmp_irq);
-				printk("using %d byte buffer\n", sony_buffer_size);
-
-				sony_devfs_handle = devfs_register (NULL, CDU535_HANDLE,
-								DEVFS_FL_DEFAULT,
-								MAJOR_NR, 0,
-								S_IFBLK | S_IRUGO | S_IWUGO,
-								&cdu_fops, NULL);
-				if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
-					printk("Unable to get major %d for %s\n",
-							MAJOR_NR, CDU535_MESSAGE_NAME);
-					return -EIO;
-				}
-				blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR),
-						do_cdu535_request,
-						&sonycd535_lock);
-				blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CDU535_BLOCK_SIZE);
-				sony_toc = (struct s535_sony_toc *)
-					kmalloc(sizeof *sony_toc, GFP_KERNEL);
-				if (sony_toc == NULL) {
-					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-					unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-					devfs_unregister(sony_devfs_handle);
-					return -ENOMEM;
-				}
-				last_sony_subcode = (struct s535_sony_subcode *)
-					kmalloc(sizeof *last_sony_subcode, GFP_KERNEL);
-				if (last_sony_subcode == NULL) {
-					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-					kfree(sony_toc);
-					unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-					devfs_unregister(sony_devfs_handle);
-					return -ENOMEM;
-				}
-				sony_buffer = (Byte **)
-					kmalloc(4 * sony_buffer_sectors, GFP_KERNEL);
-				if (sony_buffer == NULL) {
-					blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-					kfree(sony_toc);
-					kfree(last_sony_subcode);
-					unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-					devfs_unregister(sony_devfs_handle);
-					return -ENOMEM;
-				}
-				for (i = 0; i < sony_buffer_sectors; i++) {
-					sony_buffer[i] =
-								(Byte *)kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL);
-					if (sony_buffer[i] == NULL) {
-						while (--i>=0)
-							kfree(sony_buffer[i]);
-						blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-						kfree(sony_buffer);
-						kfree(sony_toc);
-						kfree(last_sony_subcode);
-						unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-						devfs_unregister(sony_devfs_handle);
-						return -ENOMEM;
-					}
-				}
-				initialized = 1;
-			}
+		sony535_irq_used = probe_irq_off(irq_mask);
+		disable_interrupts();
+	}
+	if (sony535_irq_used > 0) {
+	    if (request_irq(sony535_irq_used, cdu535_interrupt,
+						SA_INTERRUPT, CDU535_HANDLE, NULL)) {
+			printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
+					" driver; polling instead.\n", sony535_irq_used);
+			sony535_irq_used = 0;
 		}
 	}
-
-	if (!initialized) {
-		printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
-		return -EIO;
+	cmd_buff[0] = SONY535_SET_DRIVE_MODE;
+	cmd_buff[1] = 0x0;	/* default audio */
+	if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0)
+		goto Enodev_irq;
+
+	/* set the drive mode successful, we are set! */
+	sony_buffer_size = SONY535_BUFFER_SIZE;
+	sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE;
+
+	printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
+		   drive_config.vendor_id,
+		   drive_config.product_id,
+		   drive_config.product_rev_level);
+	printk("  base address %03X, ", sony535_cd_base_io);
+	if (tmp_irq > 0)
+		printk("IRQ%d, ", tmp_irq);
+	printk("using %d byte buffer\n", sony_buffer_size);
+
+	sony_devfs_handle = devfs_register (NULL, CDU535_HANDLE,
+					DEVFS_FL_DEFAULT,
+					MAJOR_NR, 0,
+					S_IFBLK | S_IRUGO | S_IWUGO,
+					&cdu_fops, NULL);
+	if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
+		printk("Unable to get major %d for %s\n",
+				MAJOR_NR, CDU535_MESSAGE_NAME);
+		err = -EIO;
+		goto out1;
 	}
-	if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE))
-		{
-		printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
-			sony535_cd_base_io);
-		for (i = 0; i < sony_buffer_sectors; i++)
-			if (sony_buffer[i]) 
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_cdu535_request,
+			&sonycd535_lock);
+	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), CDU535_BLOCK_SIZE);
+	sony_toc = kamlloc(sizeof(struct s535_sony_toc), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!sony_toc)
+		goto out2;
+	last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL);
+	if (!last_sony_subcode)
+		goto out3;
+	sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL);
+	if (!sony_buffer)
+		goto out4;
+	for (i = 0; i < sony_buffer_sectors; i++) {
+		sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL);
+		if (!sony_buffer[i]) {
+			while (--i>=0)
 				kfree(sony_buffer[i]);
-		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-		kfree(sony_buffer);
-		kfree(sony_toc);
-		kfree(last_sony_subcode);
-		unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
-		devfs_unregister(sony_devfs_handle);
-		if (sony535_irq_used)
-			free_irq(sony535_irq_used, NULL);
-
-		return -EIO;
+			goto out5;
 		}
-	add_disk(&cdu_disk);
+	}
+	initialized = 1;
+
+	cdu_disk = alloc_disk();
+	if (!cdu_disk)
+		goto out6;
+	cdu_disk->major = MAJOR_NR;
+	cdu_disk->first_minor = 0;
+	cdu_disk->minor_shift = 0;
+	cdu_disk->fops = &cdu_fops;
+	sprintf(cdu_disk->disk_name, "cdu");
+
+	if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) {
+		printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
+			sony535_cd_base_io);
+		goto out7;
+	}
+	add_disk(cdu_disk);
 	return 0;
+
+out7:
+	put_disk(cdu_disk);
+out6:
+	for (i = 0; i < sony_buffer_sectors; i++)
+		if (sony_buffer[i]) 
+			kfree(sony_buffer[i]);
+out5:
+	kfree(sony_buffer);
+out4:
+	kfree(last_sony_subcode);
+out3:
+	kfree(sony_toc);
+out2:
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	unregister_blkdev(MAJOR_NR, CDU535_HANDLE);
+out1:
+	devfs_unregister(sony_devfs_handle);
+	if (sony535_irq_used)
+		free_irq(sony535_irq_used, NULL);
+	return err;
+Enodev_irq:
+	if (sony535_irq_used)
+		free_irq(sony535_irq_used, NULL);
+Enodev:
+	printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
+	return -EIO;
 }
 
 #ifndef MODULE
@@ -1707,7 +1698,8 @@ static sony535_exit(void)
 	kfree(sony_toc);
 	devfs_find_and_unregister(NULL, CDU535_HANDLE, 0, 0,
 				  DEVFS_SPECIAL_BLK, 0);
-	del_gendisk(&cdu_disk);
+	del_gendisk(cdu_disk);
+	put_disk(cdu_disk);
 	if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
 		printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
 	else
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 48614c3cebd7586a715841dae4f311eccb3f948a..b8d75434b316c00a273e8ded2e28f57d7c91ab80 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -138,6 +138,8 @@ static struct hd_i_struct hd_info[MAX_HD];
 static int NR_HD;
 #endif
 
+static struct gendisk *hd_gendisk[MAX_HD];
+
 static struct timer_list device_timer;
 
 #define TIMEOUT_VALUE (6*HZ)
@@ -590,14 +592,15 @@ static void hd_request(void)
 	dev = DEVICE_NR(CURRENT->rq_dev);
 	block = CURRENT->sector;
 	nsect = CURRENT->nr_sectors;
-	if (dev >= NR_HD || block >= get_capacity(hd_gendisk+dev) ||
-	    ((block+nsect) > get_capacity(hd_gendisk+unit))) {
-		if (dev >= NR_HD)
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				dev+'a', block, nsect);
+	if (dev >= NR_HD) {
+		printk("hd: bad disk number: %d\n", dev);
+		end_request(CURRENT, 0);
+		goto repeat;
+	}
+	if (block >= get_capacity(hd_gendisk[dev]) ||
+	    ((block+nsect) > get_capacity(hd_gendisk[dev]))) {
+		printk("%s: bad access: block=%d, count=%d\n",
+			hd_gendisk[dev]->disk_name, block, nsect);
 		end_request(CURRENT, 0);
 		goto repeat;
 	}
@@ -691,22 +694,6 @@ static int hd_open(struct inode * inode, struct file * filp)
 
 extern struct block_device_operations hd_fops;
 
-static struct gendisk hd_gendisk[2] = {
-{
-	.major =	MAJOR_NR,
-	.first_minor =	0,
-	.disk_name =	"hda",
-	.minor_shift =	6,
-	.fops =		&hd_fops,
-},{
-	.major =	MAJOR_NR,
-	.first_minor =	64,
-	.disk_name =	"hdb",
-	.minor_shift =	6,
-	.fops =		&hd_fops,
-}
-};
-	
 static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	void (*handler)(void) = do_hd;
@@ -733,10 +720,18 @@ static struct block_device_operations hd_fops = {
  * We enable interrupts in some of the routines after making sure it's
  * safe.
  */
-static void __init hd_geninit(void)
+
+static int __init hd_init(void)
 {
 	int drive;
-
+	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+		return -1;
+	}
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
+	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
 	blk_queue_hardsect_size(QUEUE, 512);
 
 #ifdef __i386__
@@ -805,57 +800,68 @@ static void __init hd_geninit(void)
 			" on kernel command line\n");
 	}
 #endif
+	if (!NR_HD)
+		goto out;
 
+	for (drive=0 ; drive < NR_HD ; drive++) {
+		struct gendisk *disk = alloc_disk();
+		if (!disk)
+			goto Enomem;
+		disk->major = MAJOR_NR;
+		disk->first_minor = drive << 6;
+		disk->minor_shift = 6;
+		disk->fops = &hd_fops;
+		sprintf(disk->disk_name, "hd%c", 'a'+drive);
+		hd_gendisk[drive] = disk;
+	}
 	for (drive=0 ; drive < NR_HD ; drive++) {
 		sector_t size = hd_info[drive].head *
 			hd_info[drive].sect * hd_info[drive].cyl;
-		set_capacity(hd_gendisk + drive, size);
-		printk ("%s: %ldMB, CHS=%d/%d/%d\n", hd_gendisk[drive].disk_name,
+		set_capacity(hd_gendisk[drive], size);
+		printk ("%s: %ldMB, CHS=%d/%d/%d\n",
+			hd_gendisk[drive]->disk_name,
 			size / 2048, hd_info[drive].cyl,
 			hd_info[drive].head, hd_info[drive].sect);
 	}
-	if (!NR_HD)
-		return;
 
 	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
 		printk("hd: unable to get IRQ%d for the hard disk driver\n",
 			HD_IRQ);
-		NR_HD = 0;
-		return;
+		goto out1;
 	}
 	if (!request_region(HD_DATA, 8, "hd")) {
 		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
-		NR_HD = 0;
-		free_irq(HD_IRQ, NULL);
-		return;
+		goto out2;
 	}
 	if (!request_region(HD_CMD, 1, "hd(cmd)")) {
 		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
-		NR_HD = 0;
-		free_irq(HD_IRQ, NULL);
-		release_region(HD_DATA, 8);
-		return;
+		goto out3;
 	}
 
 	for(drive=0; drive < NR_HD; drive++) {
 		struct hd_i_struct *p = hd_info + drive;
-		set_capacity(hd_gendisk + drive, p->head * p->sect * p->cyl);
-		add_disk(hd_gendisk + drive);
+		set_capacity(hd_gendisk[drive], p->head * p->sect * p->cyl);
+		add_disk(hd_gendisk[drive]);
 	}
-}
-
-static int __init hd_init(void)
-{
-	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
-		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
-		return -1;
-	}
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
-	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
 	return 0;
+
+out3:
+	release_region(HD_DATA, 8);
+out2:
+	free_irq(HD_IRQ, NULL);
+out1:
+	for (drive = 0; drive < NR_HD; drive++)
+		put_disk(hd_gendisk[drive]);
+	NR_HD = 0;
+out:
+	del_timer(&device_timer);
+	unregister_blkdev(MAJOR_NR,"hd");
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	return -1;
+Enomem:
+	while (drive--)
+		put_disk(hd_gendisk[drive]);
+	goto out;
 }
 
 static int parse_hd_setup (char *line) {
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3038454374ded3af12a59765f4c6226c5e33950e..b5bf141935d0cf4b48c173ec03e5821febc7f119 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1389,10 +1389,9 @@ static int do_md_run(mddev_t * mddev)
 #endif
 	}
 
-	disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+	disk = alloc_disk();
 	if (!disk)
 		return -ENOMEM;
-	memset(disk, 0, sizeof(struct gendisk));
 	disk->major = MD_MAJOR;
 	disk->first_minor = mdidx(mddev);
 	disk->minor_shift = 0;
@@ -1408,7 +1407,7 @@ static int do_md_run(mddev_t * mddev)
 	if (err) {
 		printk(KERN_ERR "md: pers->run() failed ...\n");
 		mddev->pers = NULL;
-		kfree(disk);
+		put_disk(disk);
 		return -EINVAL;
 	}
 
@@ -1538,7 +1537,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
 
 		if (disk) {
 			del_gendisk(disk);
-			kfree(disk);
+			put_disk(disk);
 		}
 
 	} else
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index c1536e9416ab798a130c7deb8fa7e20a6e027b65..341ad2252885b40df5efa2e466789d805d5799ee 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1223,18 +1223,17 @@ static void ftl_notify_add(struct mtd_info *mtd)
 	}
 
 	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-	disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+	disk = alloc_disk();
 		
 	if (!partition||!disk) {
 		printk(KERN_WARNING "No memory to scan for FTL on %s\n",
 			mtd->name);
 		kfree(partition);
-		kfree(disk);
+		put_disk(disk);
 		return;
 	}    
 
 	memset(partition, 0, sizeof(partition_t));
-	memset(disk, 0, sizeof(struct gendisk));
 	sprintf(disk->disk_name, "ftl%c", 'a' + device);
 	disk->major = FTL_MAJOR;
 	disk->first_minor = device << 4;
@@ -1255,7 +1254,7 @@ static void ftl_notify_add(struct mtd_info *mtd)
 #endif
 	} else {
 		kfree(partition);
-		kfree(disk);
+		put_disk(disk);
 	}
 }
 
@@ -1281,7 +1280,7 @@ static void ftl_notify_remove(struct mtd_info *mtd)
 			
 			myparts[i]->state = 0;
 			del_gendisk(myparts[i]->disk);
-			kfree(myparts[i]->disk);
+			put_disk(myparts[i]->disk);
 			kfree(myparts[i]);
 			myparts[i] = NULL;
 		}
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 9ceb545791b2bcf19b0eab7688c818c45914f9c4..1ad148bd3364f1f49e22e0f4282242764b51f57a 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -42,7 +42,7 @@ static struct mtdblk_dev {
 	unsigned long cache_offset;
 	unsigned int cache_size;
 	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
-	struct gendisk disk;
+	struct gendisk *disk;
 } *mtdblks[MAX_MTD_DEVICES];
 
 static spinlock_t mtdblks_lock;
@@ -263,6 +263,7 @@ static int mtdblock_open(struct inode *inode, struct file *file)
 	struct mtdblk_dev *mtdblk;
 	struct mtd_info *mtd;
 	int dev = minor(inode->i_rdev);
+	struct gendisk *disk;
 
 	DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
 
@@ -294,10 +295,9 @@ static int mtdblock_open(struct inode *inode, struct file *file)
 	spin_unlock(&mtdblks_lock);
 
 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-	if (!mtdblk) {
-		put_mtd_device(mtd);
-		return -ENOMEM;
-	}
+	disk = alloc_disk();
+	if (!mtdblk || !disk)
+		goto Enomem;
 	memset(mtdblk, 0, sizeof(*mtdblk));
 	mtdblk->count = 1;
 	mtdblk->mtd = mtd;
@@ -308,17 +308,15 @@ static int mtdblock_open(struct inode *inode, struct file *file)
 	    mtdblk->mtd->erasesize) {
 		mtdblk->cache_size = mtdblk->mtd->erasesize;
 		mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-		if (!mtdblk->cache_data) {
-			put_mtd_device(mtdblk->mtd);
-			kfree(mtdblk);
-			return -ENOMEM;
-		}
+		if (!mtdblk->cache_data)
+			goto Enomem;
 	}
-	mtdblk->disk.major = MAJOR_NR;
-	mtdblk->disk.first_minor = dev;
-	mtdblk->disk.minor_shift = 0;
-	mtdblk->disk.fops = &mtd_fops;
-	sprintf(mtdblk->disk.disk_name, "mtd%d", dev);
+	disk->major = MAJOR_NR;
+	disk->first_minor = dev;
+	disk->minor_shift = 0;
+	disk->fops = &mtd_fops;
+	sprintf(disk->disk_name, "mtd%d", dev);
+	mtdblk->disk = disk;
 
 	/* OK, we've created a new one. Add it to the list. */
 
@@ -331,19 +329,25 @@ static int mtdblock_open(struct inode *inode, struct file *file)
 		put_mtd_device(mtdblk->mtd);
 		vfree(mtdblk->cache_data);
 		kfree(mtdblk);
+		put_disk(disk);
 		return 0;
 	}
 
 	mtdblks[dev] = mtdblk;
-	set_capacity(&mtdblk->disk, mtdblk->mtd->size/512);
-	add_disk(&mtdblk->disk);
+	set_capacity(disk, mtdblk->mtd->size/512);
+	add_disk(disk);
 	set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
-	
+
 	spin_unlock(&mtdblks_lock);
-	
+
 	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
 	return 0;
+Enomem:
+	put_mtd_device(mtd);
+	put_disk(disk);
+	kfree(mtdblk);
+	return -ENOMEM;
 }
 
 static release_t mtdblock_release(struct inode *inode, struct file *file)
@@ -367,7 +371,8 @@ static release_t mtdblock_release(struct inode *inode, struct file *file)
 		/* It was the last usage. Free the device */
 		mtdblks[dev] = NULL;
 		spin_unlock(&mtdblks_lock);
-		del_gendisk(&mtdblk->disk);
+		del_gendisk(mtdblk->disk);
+		put_disk(mtdblk->disk);
 		if (mtdblk->mtd->sync)
 			mtdblk->mtd->sync(mtdblk->mtd);
 		put_mtd_device(mtdblk->mtd);
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index a3de7d77ebd70d74f95355007695598c53ddf687..81b4daf4889cb443b179195d1073b4238871e1ba 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -29,13 +29,13 @@ static int debug = MTDBLOCK_DEBUG;
 MODULE_PARM(debug, "i");
 #endif
 
-static struct gendisk mtd_disks[MAX_MTD_DEVICES];
+static struct gendisk *mtd_disks[MAX_MTD_DEVICES];
 
 static int mtdblock_open(struct inode *inode, struct file *file)
 {
 	struct mtd_info *mtd = NULL;
 	int dev = minor(inode->i_rdev);
-	struct gendisk *disk = mtd_disks + dev;
+	struct gendisk *disk = mtd_disks[dev];
 
 	DEBUG(1,"mtdblock_open\n");
 
@@ -73,7 +73,7 @@ static release_t mtdblock_release(struct inode *inode, struct file *file)
 		release_return(-ENODEV);
 	}
 
-	del_gendisk(mtd_disks + dev);
+	del_gendisk(mtd_disks[dev]);
 	
 	if (mtd->sync)
 		mtd->sync(mtd);
@@ -218,30 +218,42 @@ static struct block_device_operations mtd_fops =
 
 int __init init_mtdblock(void)
 {
+	int err = -ENOMEM;
 	int i;
 
-	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
-		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
-		       MTD_BLOCK_MAJOR);
-		return -EAGAIN;
-	}
-
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
-
 	for (i = 0; i < MAX_MTD_DEVICES; i++) {
-		struct gendisk *disk = mtd_disks + i;
+		struct gendisk *disk = alloc_disk();
+		if (!disk)
+			goto out;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
 		sprintf(disk->disk_name, "mtdblock%d", i);
 		disk->fops = &mtd_fops;
+		mtd_disks[i] = disk;
 	}
+
+	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
+		printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
+		       MTD_BLOCK_MAJOR);
+		err = -EAGAIN;
+		goto out;
+	}
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
 	return 0;
+out:
+	while (i--)
+		put_disk(mtd_disks[i]);
+	return err;
 }
 
 static void __exit cleanup_mtdblock(void)
 {
+	int i;
 	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	for (i = 0; i < MAX_MTD_DEVICES; i++)
+		put_disk(mtd_disks[i]);
 }
 
 module_init(init_mtdblock);
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index f60f79f5f0ecd4978d924765f62bf70a19e9c04e..d886b917c852e7527bcf74511c70566675c8fe4b 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -74,10 +74,10 @@ static void NFTL_setup(struct mtd_info *mtd)
         }
 
 	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-	gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+	gd = alloc_disk();
 	if (!nftl || !gd) {
 		kfree(nftl);
-		kfree(gd);
+		put_disk(gd);
 		printk(KERN_WARNING "Out of memory for NFTL data structures\n");
 		return;
 	}
@@ -92,7 +92,7 @@ static void NFTL_setup(struct mtd_info *mtd)
         if (NFTL_mount(nftl) < 0) {
 		printk(KERN_WARNING "Could not mount NFTL device\n");
 		kfree(nftl);
-		kfree(gd);
+		put_disk(gd);
 		return;
         }
 
@@ -129,7 +129,6 @@ static void NFTL_setup(struct mtd_info *mtd)
 		/* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
 	}
 	NFTLs[firstfree] = nftl;
-	memset(gd, 0, sizeof(struct gendisk));
 	sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
 	gd->major = MAJOR_NR;
 	gd->first_minor = firstfree << NFTL_PARTN_BITS;
@@ -152,7 +151,7 @@ static void NFTL_unsetup(int i)
 	if (nftl->EUNtable)
 		kfree(nftl->EUNtable);
 	del_gendisk(nftl->disk);
-	kfree(nftl->disk);
+	put_disk(nftl->disk);
 	kfree(nftl);
 }