Commit 443ac9b2 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] beginning of probe_disk() and gendisks for floppy

That's a tricky one and large part of that stuff is temporary - it will be
replaced as soon as we have gendisks for all block devices and get sane
refcounting for gendisks.
	* we add per-major lists of gendisks; get_gendisk() looks into
appropriate list instead of looking through the list of all gendisks.
	* we allow driver to override that search - it can call
blk_set_probe(major, probe) and then gendisk will call probe(minor).
blk_set_probe(major, NULL) restores the default behaviour.
	* floppy.c switched to use of gendisks; we have one gendisk per
disk and let floppy_find(minor) return the right one.
	Note that final mechanism will involve a similar construction
but floppy.c is actually the least interesting application - places
where it will really play will include stuff like loading the right
high-level driver when we open /dev/hdX, etc.  And it won't be major-based...
parent ceb1ee4c
......@@ -416,6 +416,8 @@ 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 floppy_raw_cmd *raw_cmd, default_raw_cmd;
/*
......@@ -3775,6 +3777,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)]);
if (old_dev != -1 && old_dev != minor(inode->i_rdev)) {
if (buffer_drive == drive)
buffer_track = -1;
......@@ -3952,6 +3955,7 @@ static int floppy_revalidate(kdev_t dev)
poll_drive(0, FD_RAW_NEED_DISK);
process_fd_request();
}
set_capacity(&disks[drive], floppy_sizes[minor(dev)]);
return 0;
}
......@@ -4219,6 +4223,16 @@ static struct device device_floppy = {
bus_id: "03?0",
};
static struct gendisk *floppy_find(int minor)
{
int drive = (minor&3) | ((minor&0x80) >> 5);
if (drive >= N_DRIVE ||
!(allowed_drive_mask & (1 << drive)) ||
fdc_state[FDC(drive)].version == FDC_NONE)
return NULL;
return &disks[drive];
}
int __init floppy_init(void)
{
int i,unit,drive;
......@@ -4231,13 +4245,22 @@ int __init floppy_init(void)
return -EBUSY;
}
for (i=0; i<N_DRIVE; i++) {
disks[i].major = MAJOR_NR;
disks[i].first_minor = TOMINOR(i);
disks[i].fops = &floppy_fops;
sprintf(names[i], "fd%d", i);
disks[i].major_name = names[i];
}
blk_set_probe(MAJOR_NR, floppy_find);
for (i=0; i<256; i++)
if (ITYPE(i))
floppy_sizes[i] = (floppy_type[ITYPE(i)].size+1) >> 1;
else
floppy_sizes[i] = MAX_DISK_SIZE;
blk_size[MAJOR_NR] = floppy_sizes;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &floppy_lock);
reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
config_types();
......@@ -4262,6 +4285,7 @@ int __init floppy_init(void)
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;
}
#if N_FDC > 1
......@@ -4273,6 +4297,7 @@ int __init floppy_init(void)
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;
}
......@@ -4336,6 +4361,7 @@ int __init floppy_init(void)
floppy_release_irq_and_dma();
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
unregister_blkdev(MAJOR_NR,"fd");
blk_set_probe(MAJOR_NR, NULL);
}
for (drive = 0; drive < N_DRIVE; drive++) {
......@@ -4345,9 +4371,7 @@ int __init floppy_init(void)
continue;
if (fdc_state[FDC(drive)].version == FDC_NONE)
continue;
for (i = 0; i<NUMBER(floppy_type); i++)
register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4),
1, &floppy_fops, 0);
add_disk(disks + drive);
}
register_sys_device(&device_floppy);
......@@ -4532,15 +4556,21 @@ int init_module(void)
void cleanup_module(void)
{
int dummy;
int i;
unregister_sys_device(&device_floppy);
devfs_unregister (devfs_handle);
unregister_blkdev(MAJOR_NR, "fd");
blk_set_probe(MAJOR_NR, NULL);
for (drive = 0; drive < N_DRIVE; drive++) {
if ((allowed_drive_mask & (1 << drive)) &&
fdc_state[FDC(drive)].version != FDC_NONE)
del_gendisk(disks + drive);
}
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
/* eject disk, if any */
dummy = fd_eject(0);
fd_eject(0);
}
MODULE_PARM(floppy,"s");
......
......@@ -33,6 +33,23 @@ static rwlock_t gendisk_lock;
*/
static struct gendisk *gendisk_head;
/*
* TEMPORARY KLUDGE.
*/
static struct {
struct list_head list;
struct gendisk *(*get)(int minor);
} gendisks[MAX_BLKDEV];
void blk_set_probe(int major, struct gendisk *(p)(int))
{
write_lock(&gendisk_lock);
gendisks[major].get = p;
write_unlock(&gendisk_lock);
}
EXPORT_SYMBOL(blk_set_probe); /* Will go away */
/**
* add_gendisk - add partitioning information to kernel list
* @gp: per-device partitioning information
......@@ -42,7 +59,6 @@ static struct gendisk *gendisk_head;
*/
static void add_gendisk(struct gendisk *gp)
{
struct gendisk *sgp;
struct hd_struct *p = NULL;
if (gp->minor_shift) {
......@@ -58,24 +74,9 @@ static void add_gendisk(struct gendisk *gp)
gp->part = p;
write_lock(&gendisk_lock);
/*
* In 2.5 this will go away. Fix the drivers who rely on
* old behaviour.
*/
for (sgp = gendisk_head; sgp; sgp = sgp->next)
{
if (sgp == gp)
{
printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
sgp->major);
goto out;
}
}
list_add(&gp->list, &gendisks[gp->major].list);
gp->next = gendisk_head;
gendisk_head = gp;
out:
write_unlock(&gendisk_lock);
}
......@@ -98,6 +99,7 @@ void unlink_gendisk(struct gendisk *disk)
break;
if (*p)
*p = (*p)->next;
list_del_init(&disk->list);
write_unlock(&gendisk_lock);
}
......@@ -111,20 +113,25 @@ void unlink_gendisk(struct gendisk *disk)
struct gendisk *
get_gendisk(kdev_t dev)
{
struct gendisk *gp = NULL;
struct gendisk *disk;
struct list_head *p;
int major = major(dev);
int minor = minor(dev);
read_lock(&gendisk_lock);
for (gp = gendisk_head; gp; gp = gp->next) {
if (gp->major != major)
continue;
if (gp->first_minor > minor)
if (gendisks[major].get) {
disk = gendisks[major].get(minor);
read_unlock(&gendisk_lock);
return disk;
}
list_for_each(p, &gendisks[major].list) {
disk = list_entry(p, struct gendisk, list);
if (disk->first_minor > minor)
continue;
if (gp->first_minor + (1<<gp->minor_shift) <= minor)
if (disk->first_minor + (1<<disk->minor_shift) <= minor)
continue;
read_unlock(&gendisk_lock);
return gp;
return disk;
}
read_unlock(&gendisk_lock);
return NULL;
......@@ -200,7 +207,10 @@ extern int cpqarray_init(void);
int __init device_init(void)
{
int i;
rwlock_init(&gendisk_lock);
for (i = 0; i < MAX_BLKDEV; i++)
INIT_LIST_HEAD(&gendisks[i].list);
blk_dev_init();
#ifdef CONFIG_FC4_SOC
/* This has to be done before scsi_dev_init */
......
......@@ -81,6 +81,7 @@ struct gendisk {
struct gendisk *next;
struct block_device_operations *fops;
sector_t capacity;
struct list_head list;
int flags;
int number; /* devfs crap */
......@@ -260,6 +261,9 @@ char *disk_name (struct gendisk *hd, int part, char *buf);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
extern void update_partition(struct gendisk *disk, int part);
/* will go away */
extern void blk_set_probe(int major, struct gendisk *(p)(int));
static inline unsigned int disk_index (kdev_t dev)
{
struct gendisk *g = get_gendisk(dev);
......
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