diff options
| author | Alexander Viro <viro@math.psu.edu> | 2002-10-15 04:25:24 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-10-15 04:25:24 -0700 |
| commit | b288f6add39cf474fc2ec8087d32d3e1d4c1c6d0 (patch) | |
| tree | 9e4a6e6154b4c399f09fe480afe185766d1d6216 | |
| parent | afae25b7c8d594f6349e81dce2b16ce44aa9f0ed (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.c | 23 | ||||
| -rw-r--r-- | drivers/ide/ide-cd.c | 1 | ||||
| -rw-r--r-- | drivers/ide/ide-disk.c | 1 | ||||
| -rw-r--r-- | drivers/ide/ide-floppy.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/sr.c | 34 | ||||
| -rw-r--r-- | fs/partitions/check.c | 221 | ||||
| -rw-r--r-- | include/linux/cdrom.h | 1 |
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 */ |
