]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] preparation to use of driverfs refcounts, part 2 - disk
authorAlexander Viro <viro@math.psu.edu>
Tue, 15 Oct 2002 11:25:24 +0000 (04:25 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 15 Oct 2002 11:25:24 +0000 (04:25 -0700)
* disk->disk_dev is initialized in alloc_disk(), device_add()'d in
  add_disk(), device_del()'d in unregister_disk() and device_put() in
  put_disk().
* devices of partitions are made its children.
* attributes of disk one: dev (dev_t of the thing), range (number of
  minors) and size (in sectors).
* attributes of partition ones: dev (ditto), start (in sectors) and
  size (in sectors).
* disk devices are put on a new bus - "block"
* if caller of add_disk() had set disk->driverfs_dev, we set symlinks:
  "device" from disk to underlying device and "block" from underlying
  device to disk.
* ->release() of disk_dev frees disk and disk->part.
At that point we have sane driverfs subtree for each gendisk and
refcount of its root (disk->disk_dev) can act as gendisk refcount.

drivers/block/genhd.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/scsi/sr.c
fs/partitions/check.c
include/linux/cdrom.h

index 8ecb1461f43e0014721895f67dc38d5f074a7dcd..ecb2dcdf214d13327bbf0b47a33d056275e1967f 100644 (file)
@@ -192,6 +192,10 @@ struct device_class disk_devclass = {
        .name           = "disk",
 };
 
+static struct bus_type disk_bus = {
+       name:           "block",
+};
+
 int __init device_init(void)
 {
        int i;
@@ -200,6 +204,7 @@ int __init device_init(void)
                INIT_LIST_HEAD(&gendisks[i].list);
        blk_dev_init();
        devclass_register(&disk_devclass);
+       bus_register(&disk_bus);
        return 0;
 }
 
@@ -207,6 +212,13 @@ __initcall(device_init);
 
 EXPORT_SYMBOL(disk_devclass);
 
+static void disk_release(struct device *dev)
+{
+       struct gendisk *disk = dev->driver_data;
+       kfree(disk->part);
+       kfree(disk);
+}
+
 struct gendisk *alloc_disk(int minors)
 {
        struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
@@ -224,16 +236,19 @@ struct gendisk *alloc_disk(int minors)
                disk->minors = minors;
                while (minors >>= 1)
                        disk->minor_shift++;
+               disk->disk_dev.bus = &disk_bus;
+               disk->disk_dev.release = disk_release;
+               disk->disk_dev.driver_data = disk;
+               device_initialize(&disk->disk_dev);
        }
        return disk;
 }
 
 void put_disk(struct gendisk *disk)
 {
-       if (disk) {
-               kfree(disk->part);
-               kfree(disk);
-       }
+       if (disk)
+               put_device(&disk->disk_dev);
 }
+
 EXPORT_SYMBOL(alloc_disk);
 EXPORT_SYMBOL(put_disk);
index 3471aba90f6492c3129aa480fd7e827e401d1dba..8fffe423ab14e487c347f4b5c4a16deee1d331c5 100644 (file)
@@ -3196,6 +3196,7 @@ static int ide_cdrom_attach (ide_drive_t *drive)
        g->minors = 1;
        g->minor_shift = 0;
        g->de = drive->de;
+       g->driverfs_dev = &drive->gendev;
        g->flags = GENHD_FL_CD;
        if (ide_cdrom_setup(drive)) {
                struct cdrom_device_info *devinfo = &info->devinfo;
index 5b0c1ca8e75dd214075a9d487a787513c71bc580..aecd9a7de7ed6fad9009fcb88b38441176ff6088 100644 (file)
@@ -1874,6 +1874,7 @@ static int idedisk_attach(ide_drive_t *drive)
        g->minors = 1 << PARTN_BITS;
        g->minor_shift = PARTN_BITS;
        g->de = drive->de;
+       g->driverfs_dev = &drive->gendev;
        g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
        g->flags |= GENHD_FL_DEVFS;
        set_capacity(g, current_capacity(drive));
index fca1f92f896d1caa3ea53fa8bdef5fb5365347c7..f10543ba3d8fa713db317c980782143b1d54acdc 100644 (file)
@@ -2110,6 +2110,7 @@ static int idefloppy_attach (ide_drive_t *drive)
        DRIVER(drive)->busy--;
        g->minors = 1 << PARTN_BITS;
        g->minor_shift = PARTN_BITS;
+       g->driverfs_dev = &drive->gendev;
        g->de = drive->de;
        g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
        g->flags |= GENHD_FL_DEVFS;
index 05fe1b938eb4428afe964e4d1a3837de8f637c05..39af5cce16f03c7bb2d93d7c4787c18c3114146c 100644 (file)
@@ -726,24 +726,6 @@ cleanup_dev:
        return 1;
 }
 
-/* Driverfs file support */
-static ssize_t sr_device_kdev_read(struct device *driverfs_dev, 
-                                  char *page, size_t count, loff_t off)
-{
-       kdev_t kdev; 
-       kdev.value=(int)(long)driverfs_dev->driver_data;
-       return off ? 0 : sprintf(page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,sr_device_kdev_read,NULL);
-
-static ssize_t sr_device_type_read(struct device *driverfs_dev, 
-                                  char *page, size_t count, loff_t off) 
-{
-       return off ? 0 : sprintf (page, "CHR\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,sr_device_type_read,NULL);
-
-
 void sr_finish()
 {
        int i;
@@ -797,22 +779,8 @@ void sr_finish()
                 */
                get_capabilities(cd);
                sr_vendor_init(cd);
-
-               sprintf(cd->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
-                       cd->device->sdev_driverfs_dev.bus_id);
-               sprintf(cd->cdi.cdrom_driverfs_dev.name, "%scdrom",
-                       cd->device->sdev_driverfs_dev.name);
-               cd->cdi.cdrom_driverfs_dev.parent = 
-                       &cd->device->sdev_driverfs_dev;
-               cd->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
-               cd->cdi.cdrom_driverfs_dev.driver_data = 
-                       (void *)(long)__mkdev(MAJOR_NR, i);
-               device_register(&cd->cdi.cdrom_driverfs_dev);
-               device_create_file(&cd->cdi.cdrom_driverfs_dev,
-                                  &dev_attr_type);
-               device_create_file(&cd->cdi.cdrom_driverfs_dev,
-                                  &dev_attr_kdev);
                disk->de = cd->device->de;
+               disk->driverfs_dev = &cd->device->sdev_driverfs_dev;
                register_cdrom(&cd->cdi);
                set_capacity(disk, cd->capacity);
                add_disk(disk);
index a61a83ded312fb9f458fc96ac8283ef201646800..5fc23d047567242f4bb3764db662aad9e2f9f72b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/blk.h>
 #include <linux/kmod.h>
 #include <linux/ctype.h>
+#include <../drivers/base/fs/fs.h>     /* Eeeeewwwww */
 
 #include "check.h"
 
@@ -111,57 +112,6 @@ char *disk_name(struct gendisk *hd, int part, char *buf)
        return buf;
 }
 
-/* Driverfs file support */
-static ssize_t partition_device_kdev_read(struct device *driverfs_dev, 
-                       char *page, size_t count, loff_t off)
-{
-       kdev_t kdev; 
-       kdev.value=(int)(long)driverfs_dev->driver_data;
-       return off ? 0 : sprintf (page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,partition_device_kdev_read,NULL);
-
-static ssize_t partition_device_type_read(struct device *driverfs_dev, 
-                       char *page, size_t count, loff_t off) 
-{
-       return off ? 0 : sprintf (page, "BLK\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
-
-static void driverfs_create_partitions(struct gendisk *hd)
-{
-       struct device *parent = hd->driverfs_dev;
-       struct device *dev = &hd->disk_dev;
-
-       /* if driverfs not supported by subsystem, skip partitions */
-       if (!(hd->flags & GENHD_FL_DRIVERFS))
-               return;
-
-       if (parent)  {
-               sprintf(dev->name, "%sdisc", parent->name);
-               sprintf(dev->bus_id, "%sdisc", parent->bus_id);
-               dev->parent = parent;
-               dev->bus = parent->bus;
-       } else {
-               sprintf(dev->name, "disc");
-               sprintf(dev->bus_id, "disc");
-       }
-       dev->driver_data = (void *)(long)__mkdev(hd->major, hd->first_minor);
-       device_register(dev);
-       device_create_file(dev, &dev_attr_type);
-       device_create_file(dev, &dev_attr_kdev);
-}
-
-static void driverfs_remove_partitions(struct gendisk *hd)
-{
-       struct device *dev = &hd->disk_dev;
-       if (!(hd->flags & GENHD_FL_DRIVERFS))
-               return;
-       device_remove_file(dev, &dev_attr_type);
-       device_remove_file(dev, &dev_attr_kdev);
-       put_device(dev);        
-}
-
 static struct parsed_partitions *
 check_partition(struct gendisk *hd, struct block_device *bdev)
 {
@@ -326,6 +276,40 @@ static void devfs_remove_partitions(struct gendisk *dev)
 #endif
 }
 
+static ssize_t part_dev_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct gendisk *disk = dev->parent->driver_data;
+       struct hd_struct *p = dev->driver_data;
+       int part = p - disk->part + 1;
+       dev_t base = MKDEV(disk->major, disk->first_minor); 
+       return off ? 0 : sprintf(page, "%04x\n",base + part);
+}
+static ssize_t part_start_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct hd_struct *p = dev->driver_data;
+       return off ? 0 : sprintf(page, "%llu\n",(u64)p->start_sect);
+}
+static ssize_t part_size_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct hd_struct *p = dev->driver_data;
+       return off ? 0 : sprintf(page, "%llu\n",(u64)p->nr_sects);
+}
+static struct device_attribute part_attr_dev = {
+       .attr = {.name = "dev", .mode = S_IRUGO },
+       .show   = part_dev_read
+};
+static struct device_attribute part_attr_start = {
+       .attr = {.name = "start", .mode = S_IRUGO },
+       .show   = part_start_read
+};
+static struct device_attribute part_attr_size = {
+       .attr = {.name = "size", .mode = S_IRUGO },
+       .show   = part_size_read
+};
+
 void delete_partition(struct gendisk *disk, int part)
 {
        struct hd_struct *p = disk->part + part - 1;
@@ -338,8 +322,9 @@ void delete_partition(struct gendisk *disk, int part)
        dev = p->hd_driverfs_dev;
        p->hd_driverfs_dev = NULL;
        if (dev) {
-               device_remove_file(dev, &dev_attr_type);
-               device_remove_file(dev, &dev_attr_kdev);
+               device_remove_file(dev, &part_attr_size);
+               device_remove_file(dev, &part_attr_start);
+               device_remove_file(dev, &part_attr_dev);
                device_unregister(dev); 
        }
 }
@@ -352,43 +337,130 @@ static void part_release(struct device *dev)
 void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
 {
        struct hd_struct *p = disk->part + part - 1;
-       struct device *parent = disk->disk_dev.parent;
+       struct device *parent = &disk->disk_dev;
        struct device *dev;
 
        p->start_sect = start;
        p->nr_sects = len;
        devfs_register_partition(disk, part);
-       if (!(disk->flags & GENHD_FL_DRIVERFS))
-               return;
        dev = kmalloc(sizeof(struct device), GFP_KERNEL);
        if (!dev)
                return;
        memset(dev, 0, sizeof(struct device));
-       if (parent)  {
-               sprintf(dev->name, "%spart%d", parent->name, part);
-               sprintf(dev->bus_id, "%s:p%d", parent->bus_id, part);
-               dev->parent = parent;
-               dev->bus = parent->bus;
-       } else {
-               sprintf(dev->name, "part%d", part);
-               sprintf(dev->bus_id, "p%d", part);
-       }
+       dev->parent = parent;
+       sprintf(dev->bus_id, "p%d", part);
        dev->release = part_release;
-       dev->driver_data =
-               (void *)(long)__mkdev(disk->major, disk->first_minor+part);
+       dev->driver_data = p;
        device_register(dev);
-       device_create_file(dev, &dev_attr_type);
-       device_create_file(dev, &dev_attr_kdev);
+       device_create_file(dev, &part_attr_dev);
+       device_create_file(dev, &part_attr_start);
+       device_create_file(dev, &part_attr_size);
        p->hd_driverfs_dev = dev;
 }
 
+static ssize_t disk_dev_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct gendisk *disk = dev->driver_data;
+       dev_t base = MKDEV(disk->major, disk->first_minor); 
+       return off ? 0 : sprintf(page, "%04x\n",base);
+}
+static ssize_t disk_range_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct gendisk *disk = dev->driver_data;
+       return off ? 0 : sprintf(page, "%d\n",disk->minors);
+}
+static ssize_t disk_size_read(struct device *dev,
+                       char *page, size_t count, loff_t off)
+{
+       struct gendisk *disk = dev->driver_data;
+       return off ? 0 : sprintf(page, "%llu\n",(u64)get_capacity(disk));
+}
+static struct device_attribute disk_attr_dev = {
+       .attr = {.name = "dev", .mode = S_IRUGO },
+       .show   = disk_dev_read
+};
+static struct device_attribute disk_attr_range = {
+       .attr = {.name = "range", .mode = S_IRUGO },
+       .show   = disk_range_read
+};
+static struct device_attribute disk_attr_size = {
+       .attr = {.name = "size", .mode = S_IRUGO },
+       .show   = disk_size_read
+};
+
+static void disk_driverfs_symlinks(struct gendisk *disk)
+{
+       struct device *target = disk->driverfs_dev;
+       struct device *dev = &disk->disk_dev;
+       struct device *p;
+       char *path;
+       char *s;
+       int length;
+       int depth;
+
+       if (!target)
+               return;
+
+       get_device(target);
+
+       length = get_devpath_length(target);
+       length += strlen("..");
+
+       if (length > PATH_MAX)
+               return;
+
+       if (!(path = kmalloc(length,GFP_KERNEL)))
+               return;
+       memset(path,0,length);
+
+       /* our relative position */
+       strcpy(path,"..");
+
+       fill_devpath(target, path, length);
+       driverfs_create_symlink(&dev->dir, "device", path);
+       kfree(path);
+
+       for (p = target, depth = 0; p; p = p->parent, depth++)
+               ;
+       length = get_devpath_length(dev);
+       length += 3 * depth - 1;
+
+       if (length > PATH_MAX)
+               return;
+
+       if (!(path = kmalloc(length,GFP_KERNEL)))
+               return;
+       memset(path,0,length);
+       for (s = path; depth--; s += 3)
+               strcpy(s, "../");
+
+       fill_devpath(dev, path, length);
+       driverfs_create_symlink(&target->dir, "block", path);
+       kfree(path);
+}
+
 /* Not exported, helper to add_disk(). */
 void register_disk(struct gendisk *disk)
 {
+       struct device *dev = &disk->disk_dev;
        struct parsed_partitions *state;
        struct block_device *bdev;
+       char *s;
        int j;
 
+       strcpy(dev->bus_id, disk->disk_name);
+       /* ewww... some of these buggers have / in name... */
+       s = strchr(dev->bus_id, '/');
+       if (s)
+               *s = '!';
+       device_add(dev);
+       device_create_file(dev, &disk_attr_dev);
+       device_create_file(dev, &disk_attr_range);
+       device_create_file(dev, &disk_attr_size);
+       disk_driverfs_symlinks(disk);
+
        if (disk->flags & GENHD_FL_CD)
                devfs_create_cdrom(disk);
 
@@ -404,7 +476,6 @@ void register_disk(struct gendisk *disk)
        if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
                return;
        state = check_partition(disk, bdev);
-       driverfs_create_partitions(disk);
        devfs_create_partitions(disk);
        if (state) {
                for (j = 1; j < state->limit; j++) {
@@ -499,8 +570,16 @@ void del_gendisk(struct gendisk *disk)
        disk->capacity = 0;
        disk->flags &= ~GENHD_FL_UP;
        unlink_gendisk(disk);
-       driverfs_remove_partitions(disk);
        devfs_remove_partitions(disk);
+       device_remove_file(&disk->disk_dev, &disk_attr_dev);
+       device_remove_file(&disk->disk_dev, &disk_attr_range);
+       device_remove_file(&disk->disk_dev, &disk_attr_size);
+       driverfs_remove_file(&disk->disk_dev.dir, "device");
+       if (disk->driverfs_dev) {
+               driverfs_remove_file(&disk->driverfs_dev->dir, "block");
+               put_device(disk->driverfs_dev);
+       }
+       device_del(&disk->disk_dev);
 }
 
 struct dev_name {
index b287b7a24b1157058c2b3adff0aafcceffd3cc7f..4387203c95b7e8199bbf490789ad00eaf5926992 100644 (file)
@@ -730,7 +730,6 @@ struct cdrom_device_info {
        struct cdrom_device_ops  *ops;  /* link to device_ops */
        struct cdrom_device_info *next; /* next device_info for this major */
        void *handle;                   /* driver-dependent data */
-       struct device cdrom_driverfs_dev; /* driverfs implementation */
 /* specifications */
         kdev_t dev;                    /* device number */
        int mask;                       /* mask of capability: disables them */