Commit 3f41fa2f authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] split "gendisk" to be per-disk, part 2

we are starting to split gendisks - now we can do that.  Done for
ide, sd, pd, hd and mfm

It's in transit - what we are aiming at is getting ->nr_real to 1 for
all gendisks.  Once that will be done we will be able to simplify a lot
stuff and remove ad-hackery.  First thing that will happen after that
is death of ->nr_real, obviouslye.  Then we
	(a) will merge ->major and ->first_minor into ->dev
	(b) strip one level of indirection from  ->driverfs_dev_arr, ->de_arr
and ->flags - they turn into single-element arrays and we will simply pull
the (only) element into struct gendisk.  Kills a lot of ad-hackery in splitup
code (fewer things to allocate).
	(c) replace ->major_name with ->disk_name; kills most of the crap in
disk_name(9) - it only has to care about adding partition number to the name.
parent d7536161
......@@ -1253,11 +1253,20 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
}
}
static struct gendisk mfm_gendisk = {
static struct gendisk mfm_gendisk[2] = {
{
major: MAJOR_NR,
first_minor: 0,
major_name: "mfm",
minor_shift: 6,
part: mfm,
},
{
major: MAJOR_NR,
first_minor: 64,
major_name: "mfm",
minor_shift: 6,
part: mfm + 64,
};
static struct block_device_operations mfm_fops =
......@@ -1275,8 +1284,6 @@ static void mfm_geninit (void)
printk("mfm: detected %d hard drive%s\n", mfm_drives,
mfm_drives == 1 ? "" : "s");
mfm_gendisk.nr_real = mfm_drives;
if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL))
printk("mfm: unable to get IRQ%d\n", mfm_irq);
......@@ -1284,8 +1291,10 @@ static void mfm_geninit (void)
outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */
for (i = 0; i < mfm_drives; i++) {
mfm_gendisk[i].nr_real = 1;
add_gendisk(mfm_gendisk + i);
mfm_geometry (i);
register_disk(&mfm_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6,
register_disk(mfm_gendisk + i, mk_kdev(MAJOR_NR,i<<6), 1<<6,
&mfm_fops,
mfm_info[i].cylinders * mfm_info[i].heads *
mfm_info[i].sectors / 2);
......@@ -1380,8 +1389,6 @@ int mfm_init (void)
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mfm_request);
add_gendisk(&mfm_gendisk);
Busy = 0;
lastspecifieddrive = -1;
......@@ -1419,11 +1426,13 @@ int init_module(void)
void cleanup_module(void)
{
int i;
if (ecs && mfm_irqenable)
outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */
free_irq(mfm_irq, NULL);
unregister_blkdev(MAJOR_NR, "mfm");
del_gendisk(&mfm_gendisk);
for (i = 0; i < mfm_drives; i++)
del_gendisk(mfm_gendisk + i);
if (ecs)
ecard_release(ecs);
if (mfm_addr)
......
......@@ -55,8 +55,8 @@ add_gendisk(struct gendisk *gp)
{
if (sgp == gp)
{
// printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
// sgp->major)
printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
sgp->major)
goto out;
}
}
......
......@@ -291,6 +291,7 @@ struct pd_unit {
int alt_geom;
int present;
char name[PD_NAMELEN]; /* pda, pdb, etc ... */
struct gendisk gd;
};
struct pd_unit pd[PD_UNITS];
......@@ -330,8 +331,8 @@ static struct gendisk pd_gendisk = {
major: PD_MAJOR,
major_name: PD_NAME,
minor_shift: PD_BITS,
part: pd_hd,
fops: &pd_fops,
nr_real: 1,
};
static struct block_device_operations pd_fops = {
......@@ -680,8 +681,8 @@ static int pd_probe_drive( int unit )
}
static int pd_detect( void )
{ int k, unit;
{
int k, unit;
k = 0;
if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
......@@ -703,18 +704,19 @@ static int pd_detect( void )
k = unit+1;
} else pi_release(PI);
}
for (unit=0;unit<PD_UNITS;unit++)
register_disk(&pd_gendisk,mk_kdev(MAJOR_NR,unit<<PD_BITS),
PD_PARTNS,&pd_fops,
PD.present?PD.capacity:0);
/* We lie about the number of drives found, as the generic partition
scanner assumes that the drives are numbered sequentially from 0.
This can result in some bogus error messages if non-sequential
drive numbers are used.
*/
for (unit=0;unit<PD_UNITS;unit++) {
if (PD.present) {
PD.gd = pd_gendisk;
PD.gd.first_minor = unit << PD_BITS;
PD.gd.part = pd_hd + (unit << PD_BITS);
add_gendisk(&PD.gd);
register_disk(&PD.gd,mk_kdev(MAJOR_NR,unit<<PD_BITS),
PD_PARTNS,&pd_fops,
PD.capacity);
}
}
if (k)
return k;
return 1;
printk("%s: no valid drive found\n",name);
return 0;
}
......@@ -935,8 +937,6 @@ static void do_pd_write_done( void )
static int __init pd_init(void)
{
request_queue_t * q;
int unit;
if (disable) return -1;
if (register_blkdev(MAJOR_NR,name,&pd_fops)) {
printk("%s: unable to get major number %d\n",
......@@ -949,18 +949,11 @@ static int __init pd_init(void)
pd_gendisk.major = major;
pd_gendisk.major_name = name;
add_gendisk(&pd_gendisk);
printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
name,name,PD_VERSION,major,cluster,nice);
pd_init_units();
pd_gendisk.nr_real = pd_detect();
if (!pd_gendisk.nr_real) {
if (!pd_detect()) {
unregister_blkdev(MAJOR_NR, name);
del_gendisk(&pd_gendisk);
for (unit=0; unit<PD_UNITS; unit++)
if (PD.present)
pi_release(PI);
return -1;
}
return 0;
......@@ -970,10 +963,11 @@ static void __exit pd_exit(void)
{
int unit;
unregister_blkdev(MAJOR_NR, name);
del_gendisk(&pd_gendisk);
for (unit=0; unit<PD_UNITS; unit++)
if (PD.present)
if (PD.present) {
del_gendisk(&PD.gd);
pi_release(PI);
}
}
MODULE_LICENSE("GPL");
......
......@@ -708,12 +708,22 @@ static int hd_open(struct inode * inode, struct file * filp)
extern struct block_device_operations hd_fops;
static struct gendisk hd_gendisk = {
static struct gendisk hd_gendisk[2] = {
{
.major = MAJOR_NR,
.first_minor = 0,
.major_name = "hd",
.minor_shift = 6,
.part = hd,
.fops = &hd_fops,
},{
.major = MAJOR_NR,
.first_minor = 64,
.major_name = "hd",
.minor_shift = 6,
.part = hd + 64,
.fops = &hd_fops,
}
};
static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -845,12 +855,14 @@ static void __init hd_geninit(void)
return;
}
hd_gendisk.nr_real = NR_HD;
for(drive=0; drive < NR_HD; drive++)
register_disk(&hd_gendisk, mk_kdev(MAJOR_NR,drive<<6), 1<<6,
for(drive=0; drive < NR_HD; drive++) {
hd_gendisk[i].nr_real = 1;
add_gendisk(hd_gendisk + drive);
register_disk(hd_gendisk + drive,
mk_kdev(MAJOR_NR,drive<<6), 1<<6,
&hd_fops, hd_info[drive].head * hd_info[drive].sect *
hd_info[drive].cyl);
}
}
int __init hd_init(void)
......@@ -861,7 +873,6 @@ int __init hd_init(void)
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
add_gendisk(&hd_gendisk);
init_timer(&device_timer);
device_timer.function = hd_times_out;
hd_geninit();
......
......@@ -1064,9 +1064,9 @@ static void idedisk_setup(struct ata_device *drive)
if (drive != &ch->drives[i])
continue;
drvid = i;
ch->gd->de_arr[i] = drive->de;
ch->gd[i]->de_arr[0] = drive->de;
if (drive->removable)
ch->gd->flags[i] |= GENHD_FL_REMOVABLE;
ch->gd[i]->flags[0] |= GENHD_FL_REMOVABLE;
break;
}
......
......@@ -1712,9 +1712,9 @@ static void idefloppy_setup(struct ata_device *drive, idefloppy_floppy_t *floppy
struct ata_channel *hwif = drive->channel;
if (drive != &hwif->drives[i]) continue;
hwif->gd->de_arr[i] = drive->de;
hwif->gd[i]->de_arr[0] = drive->de;
if (drive->removable)
hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
hwif->gd[i]->flags[0] |= GENHD_FL_REMOVABLE;
break;
}
}
......
......@@ -488,16 +488,19 @@ void ide_unregister(struct ata_channel *ch)
blk_dev[ch->major].data = NULL;
blk_dev[ch->major].queue = NULL;
blk_clear(ch->major);
gd = ch->gd;
gd = ch->gd[0];
if (gd) {
del_gendisk(gd);
int i;
for (i = 0; i < MAX_DRIVES; i++)
del_gendisk(gd + i);
kfree(gd->part);
if (gd->de_arr)
kfree (gd->de_arr);
if (gd->flags)
kfree (gd->flags);
kfree(gd);
ch->gd = NULL;
for (i = 0; i < MAX_DRIVES; i++)
ch->gd[i] = NULL;
}
/*
......
......@@ -1043,6 +1043,9 @@ static request_queue_t *ata_get_queue(kdev_t dev)
static void channel_init(struct ata_channel *ch)
{
struct gendisk *gd;
struct hd_struct *part;
devfs_handle_t *de_arr;
char *flags;
unsigned int unit;
extern devfs_handle_t ide_devfs_handle;
......@@ -1103,39 +1106,42 @@ static void channel_init(struct ata_channel *ch)
/* Initialize partition and global device data.
*/
gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
gd = kmalloc (MAX_DRIVES * sizeof(struct gendisk), GFP_KERNEL);
if (!gd)
goto err_kmalloc_gd;
memset(gd, 0, sizeof(struct gendisk));
memset(gd, 0, MAX_DRIVES * sizeof(struct gendisk));
gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL);
if (!gd->part)
part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL);
if (!part)
goto err_kmalloc_gd_part;
memset(gd->part, 0, ATA_MINORS * sizeof(struct hd_struct));
memset(part, 0, ATA_MINORS * sizeof(struct hd_struct));
gd->de_arr = kmalloc (sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
if (!gd->de_arr)
de_arr = kmalloc (sizeof(devfs_handle_t) * MAX_DRIVES, GFP_KERNEL);
if (!de_arr)
goto err_kmalloc_gd_de_arr;
memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
memset(de_arr, 0, sizeof(devfs_handle_t) * MAX_DRIVES);
gd->flags = kmalloc (sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
if (!gd->flags)
flags = kmalloc (sizeof(char) * MAX_DRIVES, GFP_KERNEL);
if (!flags)
goto err_kmalloc_gd_flags;
memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
memset(flags, 0, sizeof(char) * MAX_DRIVES);
for (unit = 0; unit < MAX_DRIVES; ++unit)
ch->drives[unit].part = &gd->part[unit << PARTN_BITS];
gd->major = ch->major; /* our major device number */
gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */
gd->minor_shift = PARTN_BITS; /* num bits for partitions */
gd->nr_real = MAX_DRIVES; /* current num real drives */
gd->next = NULL; /* linked list of major devs */
gd->fops = ide_fops; /* file operations */
ch->gd = gd;
add_gendisk(gd);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
gd[unit].part = part + (unit << PARTN_BITS);
gd[unit].de_arr = de_arr + unit;
gd[unit].flags = flags + unit;
ch->drives[unit].part = gd[unit].part;
gd[unit].major = ch->major;
gd[unit].first_minor = unit << PARTN_BITS;
/* treated special in genhd.c */
gd[unit].major_name = IDE_MAJOR_NAME;
gd[unit].minor_shift = PARTN_BITS;
gd[unit].nr_real = 1;
gd[unit].fops = ide_fops;
ch->gd[unit] = gd + unit;
add_gendisk(gd + unit);
}
for (unit = 0; unit < MAX_DRIVES; ++unit) {
char name[80];
......@@ -1156,9 +1162,9 @@ static void channel_init(struct ata_channel *ch)
return;
err_kmalloc_gd_flags:
kfree(gd->de_arr);
kfree(de_arr);
err_kmalloc_gd_de_arr:
kfree(gd->part);
kfree(part);
err_kmalloc_gd_part:
kfree(gd);
err_kmalloc_gd:
......
......@@ -90,8 +90,6 @@ struct hd_struct *sd;
static Scsi_Disk ** sd_dsk_arr;
static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED;
static int *sd_max_sectors;
static int check_scsidisk_media_change(kdev_t);
static int fop_revalidate_scsidisk(kdev_t);
......@@ -605,22 +603,7 @@ static struct block_device_operations sd_fops =
revalidate: fop_revalidate_scsidisk
};
/*
* If we need more than one SCSI disk major (i.e. more than
* 16 SCSI disks), we'll have to vmalloc() more gendisks later.
*/
static struct gendisk sd_gendisk =
{
major: SCSI_DISK0_MAJOR,
major_name: "sd",
minor_shift: 4,
fops: &sd_fops,
};
static struct gendisk *sd_gendisks = &sd_gendisk;
#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
static struct gendisk **sd_disks;
/**
* sd_rw_intr - bottom half handler: called when the lower level
......@@ -1224,62 +1207,23 @@ static int sd_init()
sd_dsk_arr[k] = sdkp;
}
}
init_mem_lth(sd_disks, sd_template.dev_max);
if (sd_disks)
zero_mem_lth(sd_disks, sd_template.dev_max);
init_mem_lth(sd, maxparts);
init_mem_lth(sd_gendisks, N_USED_SD_MAJORS);
init_mem_lth(sd_max_sectors, sd_template.dev_max << 4);
if (!sd_dsk_arr || !sd || !sd_gendisks)
if (!sd_dsk_arr || !sd || !sd_disks)
goto cleanup_mem;
zero_mem_lth(sd, maxparts);
for (k = 0; k < maxparts; k++) {
/*
* Allow lowlevel device drivers to generate 512k large scsi
* commands if they know what they're doing and they ask for it
* explicitly via the SHpnt->max_sectors API.
*/
sd_max_sectors[k] = MAX_PHYS_SEGMENTS*8;
}
for (k = 0; k < N_USED_SD_MAJORS; k++) {
int N = SCSI_DISKS_PER_MAJOR;
sd_gendisks[k] = sd_gendisk;
init_mem_lth(sd_gendisks[k].de_arr, N);
init_mem_lth(sd_gendisks[k].flags, N);
init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags ||
!sd_gendisks[k].driverfs_dev_arr)
goto cleanup_gendisks;
zero_mem_lth(sd_gendisks[k].de_arr, N);
zero_mem_lth(sd_gendisks[k].flags, N);
zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
sd_gendisks[k].major = SD_MAJOR(k);
sd_gendisks[k].major_name = "sd";
sd_gendisks[k].minor_shift = 4;
sd_gendisks[k].part = sd + k * (N << 4);
sd_gendisks[k].nr_real = 0;
}
return 0;
#undef init_mem_lth
#undef zero_mem_lth
cleanup_gendisks:
/* vfree can handle NULL, so no test is required here */
for (k = 0; k < N_USED_SD_MAJORS; k++) {
vfree(sd_gendisks[k].de_arr);
vfree(sd_gendisks[k].flags);
vfree(sd_gendisks[k].driverfs_dev_arr);
}
cleanup_mem:
vfree(sd_gendisks);
sd_gendisks = NULL;
vfree(sd_disks);
sd_disks = NULL;
vfree(sd);
sd = NULL;
if (sd_dsk_arr) {
......@@ -1310,17 +1254,16 @@ static void sd_finish()
Scsi_Disk * sdkp;
SCSI_LOG_HLQUEUE(3, printk("sd_finish: \n"));
for (k = 0; k < N_USED_SD_MAJORS; k++) {
for (k = 0; k < N_USED_SD_MAJORS; k++)
blk_dev[SD_MAJOR(k)].queue = sd_find_queue;
add_gendisk(&(sd_gendisks[k]));
}
for (k = 0; k < sd_template.dev_max; ++k) {
sdkp = sd_get_sdisk(k);
if (sdkp && (0 == sdkp->capacity) && sdkp->device) {
sd_init_onedisk(sdkp, k);
if (!sdkp->has_been_registered) {
register_disk(&SD_GENDISK(k), MKDEV_SD(k),
add_gendisk(sd_disks[k]);
register_disk(sd_disks[k], MKDEV_SD(k),
1<<4, &sd_fops,
sdkp->capacity);
sdkp->has_been_registered = 1;
......@@ -1366,21 +1309,36 @@ static int sd_detect(Scsi_Device * sdp)
**/
static int sd_attach(Scsi_Device * sdp)
{
unsigned int devnum;
Scsi_Disk *sdkp;
int dsk_nr;
char diskname[6];
unsigned long iflags;
struct {
struct gendisk disk;
devfs_handle_t de;
struct device *dev;
char flags;
} *p;
struct gendisk *gd;
if ((NULL == sdp) ||
((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
return 0;
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return 1;
gd = &p->disk;
gd->de_arr = &p->de;
gd->flags = &p->flags;
gd->driverfs_dev_arr = &p->dev;
SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
if (sd_template.nr_dev >= sd_template.dev_max) {
sdp->attached--;
printk(KERN_ERR "sd_init: no more room for device\n");
kfree(p);
return 1;
}
......@@ -1400,17 +1358,23 @@ static int sd_attach(Scsi_Device * sdp)
if (dsk_nr >= sd_template.dev_max) {
/* panic("scsi_devices corrupt (sd)"); overkill */
printk(KERN_ERR "sd_init: sd_dsk_arr corrupted\n");
kfree(p);
return 1;
}
sd_template.nr_dev++;
SD_GENDISK(dsk_nr).nr_real++;
devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] =
&sdp->sdev_driverfs_dev;
gd->nr_real = 1;
gd->de_arr[0] = sdp->de;
gd->driverfs_dev_arr[0] = &sdp->sdev_driverfs_dev;
gd->major = SD_MAJOR(dsk_nr>>4);
gd->first_minor = (dsk_nr & 15)<<4;
gd->major_name = "sd";
gd->minor_shift = 4;
gd->part = sd + (dsk_nr << 4);
gd->fops = &sd_fops;
if (sdp->removable)
SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
gd->flags[0] |= GENHD_FL_REMOVABLE;
sd_disks[dsk_nr] = gd;
sd_dskname(dsk_nr, diskname);
printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
"id %d, lun %d\n", sdp->removable ? "removable " : "",
......@@ -1480,8 +1444,6 @@ static void sd_detach(Scsi_Device * sdp)
Scsi_Disk *sdkp = NULL;
kdev_t dev;
int dsk_nr;
int max_p;
int start;
unsigned long iflags;
SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n",
......@@ -1491,7 +1453,6 @@ static void sd_detach(Scsi_Device * sdp)
for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
sdkp = sd_dsk_arr[dsk_nr];
if (sdkp->device == sdp) {
sdkp->has_been_registered = 0;
sdkp->device = NULL;
sdkp->capacity = 0;
/* sdkp->detaching = 1; */
......@@ -1502,19 +1463,20 @@ static void sd_detach(Scsi_Device * sdp)
if (dsk_nr >= sd_template.dev_max)
return;
max_p = 1 << sd_gendisk.minor_shift;
start = dsk_nr << sd_gendisk.minor_shift;
dev = MKDEV_SD_PARTITION(start);
driverfs_remove_partitions(&SD_GENDISK (dsk_nr),
SD_MINOR_NUMBER (start));
wipe_partitions(dev);
devfs_register_partitions (&SD_GENDISK (dsk_nr),
SD_MINOR_NUMBER (start), 1);
/* unregister_disk() */
if (sdkp->has_been_registered) {
sdkp->has_been_registered = 0;
dev = MKDEV_SD(dsk_nr);
driverfs_remove_partitions(sd_disks[dsk_nr], minor(dev));
wipe_partitions(dev);
devfs_register_partitions (sd_disks[dsk_nr], minor(dev), 1);
/* unregister_disk() */
del_gendisk(sd_disks[dsk_nr]);
}
sdp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
SD_GENDISK(dsk_nr).nr_real--;
kfree(sd_disks[dsk_nr]);
sd_disks[dsk_nr] = NULL;
}
/**
......@@ -1560,12 +1522,9 @@ static void __exit exit_sd(void)
vfree((char *) sd);
for (k = 0; k < N_USED_SD_MAJORS; k++) {
blk_dev[SD_MAJOR(k)].queue = NULL;
del_gendisk(&(sd_gendisks[k]));
blk_clear(SD_MAJOR(k));
}
sd_template.dev_max = 0;
if (sd_gendisks != &sd_gendisk)
vfree(sd_gendisks);
remove_driver(&sd_template.scsi_driverfs_driver);
}
......
......@@ -894,7 +894,7 @@ struct ata_channel {
struct pci_dev *pci_dev; /* for pci chipsets */
#endif
struct ata_device drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
struct gendisk *gd[MAX_DRIVES]; /* gendisk structure */
/*
* Routines to tune PIO and DMA mode for drives.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment