]> git.hungrycats.org Git - linux/commitdiff
[PATCH] beginning of probe_disk() and gendisks for floppy
authorAlexander Viro <viro@math.psu.edu>
Sat, 21 Sep 2002 09:51:01 +0000 (02:51 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sat, 21 Sep 2002 09:51:01 +0000 (02:51 -0700)
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...

drivers/block/floppy.c
drivers/block/genhd.c
include/linux/genhd.h

index 7a80e15cc9620663807f0f09cffa0ea13ab523a3..6a482b38197ac5b33fd290603c13ad2e5d30cb24 100644 (file)
@@ -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");
index d808f4334fae30746daee782e7dc1dfdbf69f49f..37f937d0bef5341b5df1135180cdee8f45260be7 100644 (file)
@@ -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 */
index 8632a84676e039992c747a71ddeb54e2dedc7340..33cfbe2f110812ab307cd751bc474625536402ab 100644 (file)
@@ -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);