Commit 664aa7b2 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] dasd per-disk gendisks

parent bedbeab4
......@@ -290,11 +290,9 @@ dasd_state_new_to_known(dasd_device_t *device)
gdp = dasd_gendisk_from_devindex(devmap->devindex);
if (gdp == NULL)
return -ENODEV;
minor = devmap->devindex % DASD_PER_MAJOR;
/* Set kdev and the device name. */
device->kdev = mk_kdev(gdp->major, minor << DASD_PARTN_BITS);
dasd_device_name(device->name, minor, 0, gdp);
device->kdev = mk_kdev(gdp->major, gdp->first_minor);
strcpy(device->name, gdp->major_name);
/* Find a discipline for the device. */
rc = dasd_find_disc(device);
......@@ -304,7 +302,7 @@ dasd_state_new_to_known(dasd_device_t *device)
/* Add a proc directory and the dasd device entry to devfs. */
sprintf(buffer, "%04x", device->devinfo.devno);
dir = devfs_mk_dir(dasd_devfs_handle, buffer, device);
gdp->de_arr[minor(device->kdev) >> DASD_PARTN_BITS] = dir;
gdp->de_arr[0] = dir;
if (devmap->features & DASD_FEATURE_READONLY)
devfs_perm = S_IFBLK | S_IRUSR;
else
......@@ -324,19 +322,13 @@ dasd_state_new_to_known(dasd_device_t *device)
static inline void
dasd_state_known_to_new(dasd_device_t * device)
{
struct gendisk *gdp;
dasd_devmap_t *devmap;
int minor;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
gdp = dasd_gendisk_from_devindex(devmap->devindex);
dasd_devmap_t *devmap = dasd_devmap_from_devno(device->devinfo.devno);
struct gendisk *gdp = dasd_gendisk_from_devindex(devmap->devindex);
if (gdp == NULL)
return;
minor = devmap->devindex % DASD_PER_MAJOR;
/* Remove device entry and devfs directory. */
devfs_unregister(device->devfs_entry);
devfs_unregister(gdp->de_arr[minor]);
devfs_unregister(gdp->de_arr[0]);
/* Forget the discipline information. */
device->discipline = NULL;
......
......@@ -32,7 +32,12 @@ static struct list_head dasd_major_info = LIST_HEAD_INIT(dasd_major_info);
struct major_info {
struct list_head list;
struct gendisk gendisk; /* actually contains the major number */
int major;
struct gendisk disks[DASD_PER_MAJOR];
devfs_handle_t de_arr[DASD_PER_MAJOR];
char flags[DASD_PER_MAJOR];
char names[DASD_PER_MAJOR * 8];
struct hd_struct part[1<<MINORBITS];
};
/*
......@@ -64,24 +69,17 @@ static int
dasd_register_major(int major)
{
struct major_info *mi;
struct hd_struct *gd_part;
devfs_handle_t *gd_de_arr;
char *gd_flags;
int new_major, rc;
struct list_head *l;
int index;
int i;
rc = 0;
/* Allocate major info structure. */
mi = kmalloc(sizeof(struct major_info), GFP_KERNEL);
/* Allocate gendisk arrays. */
gd_de_arr = kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t),
GFP_KERNEL);
gd_flags = kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
gd_part = kmalloc(sizeof (struct hd_struct) << MINORBITS, GFP_ATOMIC);
/* Check if one of the allocations failed. */
if (mi == NULL || gd_de_arr == NULL || gd_flags == NULL ||
gd_part == NULL) {
if (mi == NULL) {
MESSAGE(KERN_WARNING, "%s",
"Cannot get memory to allocate another "
"major number");
......@@ -99,41 +97,48 @@ dasd_register_major(int major)
}
if (major != 0)
new_major = major;
/* Initialize major info structure. */
memset(mi, 0, sizeof(struct major_info));
mi->gendisk.major = new_major;
mi->gendisk.major_name = "dasd";
mi->gendisk.minor_shift = DASD_PARTN_BITS;
mi->gendisk.nr_real = DASD_PER_MAJOR;
mi->gendisk.fops = &dasd_device_operations;
mi->gendisk.de_arr = gd_de_arr;
mi->gendisk.flags = gd_flags;
mi->gendisk.part = gd_part;
/* Initialize the gendisk arrays. */
memset(gd_de_arr, 0, DASD_PER_MAJOR * sizeof(devfs_handle_t));
memset(gd_flags, 0, DASD_PER_MAJOR * sizeof (char));
memset(gd_part, 0, sizeof (struct hd_struct) << MINORBITS);
mi->major = new_major;
for (i = 0; i < DASD_PER_MAJOR; i++) {
struct gendisk *disk = mi->disks + i;
disk->major = new_major;
disk->first_minor = i << DASD_PARTN_BITS;
disk->minor_shift = DASD_PARTN_BITS;
disk->nr_real = 1;
disk->fops = &dasd_device_operations;
disk->de_arr = mi->de_arr + i;
disk->flags = mi->flags + i;
disk->part = mi->part + (i << DASD_PARTN_BITS);
}
/* Setup block device pointers for the new major. */
blk_dev[new_major].queue = dasd_get_queue;
/* Insert the new major info structure into dasd_major_info list. */
spin_lock(&dasd_major_lock);
index = 0;
list_for_each(l, &dasd_major_info)
index += DASD_PER_MAJOR;
for (i = 0; i < DASD_PER_MAJOR; i++, index++) {
char *name = mi->names + i * 8;
mi->disks[i].major_name = name;
sprintf(name, "dasd");
name += 4;
if (index > 701)
*name++ = 'a' + (((index - 702) / 676) % 26);
if (index > 25)
*name++ = 'a' + (((index - 26) / 26) % 26);
sprintf(name, "%c", 'a' + (index % 26));
}
list_add_tail(&mi->list, &dasd_major_info);
spin_unlock(&dasd_major_lock);
/* Make the gendisk known. */
add_gendisk(&mi->gendisk);
return 0;
/* Something failed. Do the cleanup and return rc. */
out_error:
/* We rely on kfree to do the != NULL check. */
kfree(gd_part);
kfree(gd_flags);
kfree(gd_de_arr);
kfree(mi);
return rc;
}
......@@ -146,16 +151,13 @@ dasd_unregister_major(struct major_info * mi)
if (mi == NULL)
return;
/* Remove gendisk information. */
del_gendisk(&mi->gendisk);
/* Delete the major info from dasd_major_info. */
spin_lock(&dasd_major_lock);
list_del(&mi->list);
spin_unlock(&dasd_major_lock);
/* Clear block device pointers. */
major = mi->gendisk.major;
major = mi->major;
blk_dev[major].queue = NULL;
blk_clear(major);
......@@ -166,9 +168,6 @@ dasd_unregister_major(struct major_info * mi)
major, rc);
/* Free memory. */
kfree(mi->gendisk.part);
kfree(mi->gendisk.flags);
kfree(mi->gendisk.de_arr);
kfree(mi);
}
......@@ -189,19 +188,19 @@ dasd_gendisk_new_major(void)
/*
* Return pointer to gendisk structure by kdev.
*/
struct gendisk *
dasd_gendisk_from_major(int major)
static struct gendisk *dasd_gendisk_by_dev(kdev_t dev)
{
struct list_head *l;
struct major_info *mi;
struct gendisk *gdp;
int major = major(dev);
spin_lock(&dasd_major_lock);
gdp = NULL;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (mi->gendisk.major == major) {
gdp = &mi->gendisk;
if (mi->major == major) {
gdp = &mi->disks[minor(dev) >> DASD_PARTN_BITS];
break;
}
}
......@@ -224,7 +223,7 @@ dasd_gendisk_from_devindex(int devindex)
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (devindex < DASD_PER_MAJOR) {
gdp = &mi->gendisk;
gdp = &mi->disks[devindex];
break;
}
devindex -= DASD_PER_MAJOR;
......@@ -247,7 +246,7 @@ int dasd_gendisk_major_index(int major)
devindex = 0;
list_for_each(l, &dasd_major_info) {
mi = list_entry(l, struct major_info, list);
if (mi->gendisk.major == major) {
if (mi->major == major) {
rc = devindex;
break;
}
......@@ -257,62 +256,19 @@ int dasd_gendisk_major_index(int major)
return rc;
}
/*
* This one is needed for naming 18000+ possible dasd devices.
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
* This function is called from the partition detection code (see disk_name)
* via the genhd_dasd_name hook. As mentioned in partition/check.c this
* is ugly...
*/
int
dasd_device_name(char *str, int index, int partition, struct gendisk *hd)
{
struct list_head *l;
int len, found;
/* Check if this is on of our gendisk structures. */
found = 0;
spin_lock(&dasd_major_lock);
list_for_each(l, &dasd_major_info) {
struct major_info *mi;
mi = list_entry(l, struct major_info, list);
if (&mi->gendisk == hd) {
found = 1;
break;
}
index += DASD_PER_MAJOR;
}
spin_unlock(&dasd_major_lock);
if (!found)
/* Not one of our structures. Can't be a dasd. */
return -EINVAL;
len = sprintf(str, "dasd");
if (index > 25) {
if (index > 701)
len += sprintf(str + len, "%c",
'a' + (((index - 702) / 676) % 26));
len += sprintf(str + len, "%c",
'a' + (((index - 26) / 26) % 26));
}
len += sprintf(str + len, "%c", 'a' + (index % 26));
if (partition > DASD_PARTN_MASK)
return -EINVAL;
if (partition)
len += sprintf(str + len, "%d", partition);
return 0;
}
/*
* Register disk to genhd. This will trigger a partition detection.
*/
void
dasd_setup_partitions(dasd_device_t * device)
{
grok_partitions(device->kdev, device->blocks << device->s2b_shift);
struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
if (disk == NULL)
return;
add_gendisk(disk);
register_disk(disk, mk_kdev(disk->major, disk->first_minor),
1<<disk->minor_shift, disk->fops,
device->blocks << device->s2b_shift);
}
/*
......@@ -322,11 +278,10 @@ dasd_setup_partitions(dasd_device_t * device)
void
dasd_destroy_partitions(dasd_device_t * device)
{
struct gendisk *gdp;
struct gendisk *disk = dasd_gendisk_by_dev(device->kdev);
int minor, i;
gdp = dasd_gendisk_from_major(major(device->kdev));
if (gdp == NULL)
if (disk == NULL)
return;
wipe_partitions(device->kdev);
......@@ -336,13 +291,10 @@ dasd_destroy_partitions(dasd_device_t * device)
* but the 1 as third parameter makes it do an unregister...
* FIXME: there must be a better way to get rid of the devfs entries
*/
devfs_register_partitions(gdp, minor(device->kdev), 1);
devfs_register_partitions(disk, minor(device->kdev), 1);
del_gendisk(disk);
}
extern int (*genhd_dasd_name)(char *, int, int, struct gendisk *);
extern int (*genhd_dasd_ioctl) (struct inode *inp, struct file *filp,
unsigned int no, unsigned long data);
int
dasd_gendisk_init(void)
{
......@@ -350,25 +302,17 @@ dasd_gendisk_init(void)
/* Register to static dasd major 94 */
rc = dasd_register_major(DASD_MAJOR);
if (rc != 0) {
if (rc != 0)
MESSAGE(KERN_WARNING,
"Couldn't register successfully to "
"major no %d", DASD_MAJOR);
return rc;
}
genhd_dasd_name = dasd_device_name;
genhd_dasd_ioctl = dasd_ioctl;
return 0;
return rc;
}
void
dasd_gendisk_exit(void)
{
struct list_head *l, *n;
genhd_dasd_ioctl = NULL;
genhd_dasd_name = NULL;
spin_lock(&dasd_major_lock);
list_for_each_safe(l, n, &dasd_major_info)
dasd_unregister_major(list_entry(l, struct major_info, list));
......
......@@ -480,9 +480,7 @@ int dasd_gendisk_init(void);
void dasd_gendisk_exit(void);
int dasd_gendisk_new_major(void);
int dasd_gendisk_major_index(int);
struct gendisk *dasd_gendisk_from_major(int);
struct gendisk *dasd_gendisk_from_devindex(int);
int dasd_device_name(char *, int, int, struct gendisk *);
void dasd_setup_partitions(dasd_device_t *);
void dasd_destroy_partitions(dasd_device_t *);
......
......@@ -173,12 +173,7 @@ dasd_devices_print(dasd_devmap_t *devmap, char *str)
minor = devmap->devindex % DASD_PER_MAJOR;
len += sprintf(str + len, " at (%3d:%3d)", gdp->major, minor);
/* Print device name. */
if (device == NULL) {
dasd_device_name(buffer, minor, 0, gdp);
substr = buffer;
} else
substr = device->name;
len += sprintf(str + len, " is %-7s", substr);
len += sprintf(str + len, " is %-7s", gdp->major_name);
/* Print devices features. */
substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
len += sprintf(str + len, "%4s: ", substr);
......
......@@ -79,22 +79,7 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) =
#endif
NULL
};
/*
* This is ucking fugly but its probably the best thing for 2.4.x
* Take it as a clear reminder that: 1) we should put the device name
* generation in the object kdev_t points to in 2.5.
* and 2) ioctls better work on half-opened devices.
*/
#ifdef CONFIG_ARCH_S390
int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
unsigned int no, unsigned long data);
EXPORT_SYMBOL(genhd_dasd_name);
EXPORT_SYMBOL(genhd_dasd_ioctl);
#endif
/*
* disk_name() is used by partition check code and the md driver.
* It formats the devicename of the indicated disk into
......@@ -119,11 +104,6 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
return buf + pos;
}
#ifdef CONFIG_ARCH_S390
if (genhd_dasd_name
&& genhd_dasd_name (buf, unit, part, hd) == 0)
return buf;
#endif
/*
* Yes, I know, ... in cases is gccism and not a pretty one.
* However, the first variant will eventually consume _all_ cases
......@@ -138,7 +118,6 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
maj = s;
break;
case I2O_MAJOR:
case DASD_MAJOR:
sprintf(s, "%s%c", hd->major_name, unit + 'a');
maj = s;
}
......
......@@ -52,39 +52,6 @@ cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
ptr->b;
}
/*
* We used to use ioctl_by_bdev in early 2.4, but it broke
* between 2.4.9 and 2.4.18 somewhere.
*/
extern int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
unsigned int no, unsigned long data);
static int
ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg)
{
int res;
mm_segment_t old_fs = get_fs();
if (genhd_dasd_ioctl == NULL)
return -ENODEV;
#if 0
lock_kernel();
if (bd_ops->owner)
__MOD_INC_USE_COUNT(bdev->bd_op->owner);
unlock_kernel();
#endif
set_fs(KERNEL_DS);
res = (*genhd_dasd_ioctl)(bdev->bd_inode, NULL, cmd, arg);
set_fs(old_fs);
#if 0
lock_kernel();
if (bd_ops->owner)
__MOD_DEV_USE_COUNT(bd_ops->owner);
unlock_kernel();
#endif
return res;
}
/*
*/
int
......@@ -106,8 +73,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
goto out_novlab;
if (ibm_ioctl_unopened(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
ibm_ioctl_unopened(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
goto out_noioctl;
if ((blocksize = bdev_hardsect_size(bdev)) <= 0)
......
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