summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@math.psu.edu>2002-10-15 04:25:24 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-10-15 04:25:24 -0700
commitb288f6add39cf474fc2ec8087d32d3e1d4c1c6d0 (patch)
tree9e4a6e6154b4c399f09fe480afe185766d1d6216
parentafae25b7c8d594f6349e81dce2b16ce44aa9f0ed (diff)
[PATCH] preparation to use of driverfs refcounts, part 2 - disk
* 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.
-rw-r--r--drivers/block/genhd.c23
-rw-r--r--drivers/ide/ide-cd.c1
-rw-r--r--drivers/ide/ide-disk.c1
-rw-r--r--drivers/ide/ide-floppy.c1
-rw-r--r--drivers/scsi/sr.c34
-rw-r--r--fs/partitions/check.c221
-rw-r--r--include/linux/cdrom.h1
7 files changed, 173 insertions, 109 deletions
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 8ecb1461f43e..ecb2dcdf214d 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -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);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 3471aba90f64..8fffe423ab14 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -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;
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 5b0c1ca8e75d..aecd9a7de7ed 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -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));
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index fca1f92f896d..f10543ba3d8f 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -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;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 05fe1b938eb4..39af5cce16f0 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -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);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index a61a83ded312..5fc23d047567 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -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 {
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index b287b7a24b11..4387203c95b7 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -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 */