diff options
| author | Alexander Viro <viro@math.psu.edu> | 2002-09-21 02:51:01 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-09-21 02:51:01 -0700 |
| commit | 443ac9b2957964cc7a8a6442f3dec2a286a0e471 (patch) | |
| tree | 0a48413f761ba749e657ff4388de54aaf580548a | |
| parent | ceb1ee4c055c9a0debecf2b1759b70ce65abf27d (diff) | |
[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...
| -rw-r--r-- | drivers/block/floppy.c | 42 | ||||
| -rw-r--r-- | drivers/block/genhd.c | 58 | ||||
| -rw-r--r-- | include/linux/genhd.h | 4 |
3 files changed, 74 insertions, 30 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 7a80e15cc962..6a482b38197a 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -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"); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index d808f4334fae..37f937d0bef5 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -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 */ diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 8632a84676e0..33cfbe2f1108 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -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); |
