Commit 161e49bc authored by Patrick Mochel's avatar Patrick Mochel

convert block devices and partitions to use kobject & sysfs.

parent d7dce5e3
......@@ -252,14 +252,6 @@ struct seq_operations partitions_op = {
extern int blk_dev_init(void);
struct device_class disk_devclass = {
.name = "disk",
};
static struct bus_type disk_bus = {
name: "block",
};
static struct gendisk *base_probe(dev_t dev, int *part, void *data)
{
char name[20];
......@@ -268,6 +260,8 @@ static struct gendisk *base_probe(dev_t dev, int *part, void *data)
return NULL;
}
struct subsystem block_subsys;
int __init device_init(void)
{
struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
......@@ -280,23 +274,116 @@ int __init device_init(void)
for (i = 1; i < MAX_BLKDEV; i++)
probes[i] = base;
blk_dev_init();
devclass_register(&disk_devclass);
bus_register(&disk_bus);
subsystem_register(&block_subsys);
return 0;
}
__initcall(device_init);
EXPORT_SYMBOL(disk_devclass);
static void disk_release(struct device *dev)
/*
* kobject & sysfs bindings for block devices
*/
#define to_disk(obj) container_of(obj,struct gendisk,kobj)
struct disk_attribute {
struct attribute attr;
ssize_t (*show)(struct gendisk *, char *, size_t, loff_t);
};
static ssize_t disk_attr_show(struct kobject * kobj, struct attribute * attr,
char * page, size_t count, loff_t off)
{
struct gendisk * disk = to_disk(kobj);
struct disk_attribute * disk_attr = container_of(attr,struct disk_attribute,attr);
ssize_t ret = 0;
if (disk_attr->show)
ret = disk_attr->show(disk,page,count,off);
return ret;
}
static struct sysfs_ops disk_sysfs_ops = {
.show = &disk_attr_show,
};
static ssize_t disk_dev_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
dev_t base = MKDEV(disk->major, disk->first_minor);
return off ? 0 : sprintf(page, "%04x\n",base);
}
static ssize_t disk_range_read(struct gendisk * disk,
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 gendisk * disk,
char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk));
}
static inline unsigned MSEC(unsigned x)
{
return x * 1000 / HZ;
}
static ssize_t disk_stat_read(struct gendisk * disk,
char *page, size_t count, loff_t off)
{
disk_round_stats(disk);
return off ? 0 : sprintf(page,
"%8u %8u %8llu %8u "
"%8u %8u %8llu %8u "
"%8u %8u %8u"
"\n",
disk->reads, disk->read_merges, (u64)disk->read_sectors,
MSEC(disk->read_ticks),
disk->writes, disk->write_merges, (u64)disk->write_sectors,
MSEC(disk->write_ticks),
disk->in_flight, MSEC(disk->io_ticks),
MSEC(disk->time_in_queue));
}
static struct disk_attribute disk_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = disk_dev_read
};
static struct disk_attribute disk_attr_range = {
.attr = {.name = "range", .mode = S_IRUGO },
.show = disk_range_read
};
static struct disk_attribute disk_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = disk_size_read
};
static struct disk_attribute disk_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = disk_stat_read
};
static struct attribute * default_attrs[] = {
&disk_attr_dev.attr,
&disk_attr_range.attr,
&disk_attr_size.attr,
&disk_attr_stat.attr,
NULL,
};
static void disk_release(struct kobject * kobj)
{
struct gendisk *disk = to_disk(kobj);
kfree(disk->random);
kfree(disk->part);
kfree(disk);
}
struct subsystem block_subsys = {
.kobj = { .name = "block" },
.release = disk_release,
.sysfs_ops = &disk_sysfs_ops,
.default_attrs = default_attrs,
};
struct gendisk *alloc_disk(int minors)
{
struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
......@@ -314,11 +401,9 @@ struct gendisk *alloc_disk(int minors)
disk->minors = minors;
while (minors >>= 1)
disk->minor_shift++;
kobject_init(&disk->kobj);
disk->kobj.subsys = &block_subsys;
INIT_LIST_HEAD(&disk->full_list);
disk->disk_dev.bus = &disk_bus;
disk->disk_dev.release = disk_release;
disk->disk_dev.driver_data = disk;
device_initialize(&disk->disk_dev);
}
rand_initialize_disk(disk);
return disk;
......@@ -332,14 +417,13 @@ struct gendisk *get_disk(struct gendisk *disk)
owner = disk->fops->owner;
if (owner && !try_inc_mod_count(owner))
return NULL;
atomic_inc(&disk->disk_dev.refcount);
return disk;
return to_disk(kobject_get(&disk->kobj));
}
void put_disk(struct gendisk *disk)
{
if (disk)
put_device(&disk->disk_dev);
kobject_put(&disk->kobj);
}
EXPORT_SYMBOL(alloc_disk);
......
......@@ -277,231 +277,147 @@ static void devfs_remove_partitions(struct gendisk *dev)
#endif
}
static ssize_t part_dev_read(struct device *dev,
/*
* sysfs bindings for partitions
*/
struct part_attribute {
struct attribute attr;
ssize_t (*show)(struct hd_struct *,char *,size_t,loff_t);
};
static ssize_t part_attr_show(struct kobject * kobj, struct attribute * attr,
char * page, size_t count, loff_t off)
{
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
ssize_t ret = 0;
if (part_attr->show)
part_attr->show(p,page,count,off);
return ret;
}
static struct sysfs_ops part_sysfs_ops = {
.show part_attr_show,
};
static ssize_t part_dev_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->parent->driver_data;
struct hd_struct *p = dev->driver_data;
struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
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,
static ssize_t part_start_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->start_sect);
}
static ssize_t part_size_read(struct device *dev,
static ssize_t part_size_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->nr_sects);
}
static ssize_t part_stat_read(struct device *dev,
static ssize_t part_stat_read(struct hd_struct * p,
char *page, size_t count, loff_t off)
{
struct hd_struct *p = dev->driver_data;
return off ? 0 : sprintf(page, "%8u %8llu %8u %8llu\n",
p->reads, (u64)p->read_sectors,
p->writes, (u64)p->write_sectors);
}
static struct device_attribute part_attr_dev = {
static struct part_attribute part_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO },
.show = part_dev_read
};
static struct device_attribute part_attr_start = {
static struct part_attribute part_attr_start = {
.attr = {.name = "start", .mode = S_IRUGO },
.show = part_start_read
};
static struct device_attribute part_attr_size = {
static struct part_attribute part_attr_size = {
.attr = {.name = "size", .mode = S_IRUGO },
.show = part_size_read
};
static struct device_attribute part_attr_stat = {
static struct part_attribute part_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = part_stat_read
};
static struct attribute * default_attrs[] = {
&part_attr_dev.attr,
&part_attr_start.attr,
&part_attr_size.attr,
&part_attr_stat.attr,
NULL,
};
extern struct subsystem block_subsys;
static struct subsystem part_subsys = {
.kobj = { .name = "part" },
.parent = &block_subsys,
.default_attrs = default_attrs,
.sysfs_ops = &part_sysfs_ops,
};
static int __init part_subsys_init(void)
{
return subsystem_register(&part_subsys);
}
__initcall(part_subsys_init);
void delete_partition(struct gendisk *disk, int part)
{
struct hd_struct *p = disk->part + part - 1;
struct device *dev;
if (!p->nr_sects)
return;
p->start_sect = 0;
p->nr_sects = 0;
p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
devfs_unregister(p->de);
dev = p->hd_driverfs_dev;
p->hd_driverfs_dev = NULL;
if (dev) {
device_remove_file(dev, &part_attr_stat);
device_remove_file(dev, &part_attr_size);
device_remove_file(dev, &part_attr_start);
device_remove_file(dev, &part_attr_dev);
device_unregister(dev);
}
}
static void part_release(struct device *dev)
{
kfree(dev);
kobject_unregister(&p->kobj);
}
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;
struct device *dev;
p->start_sect = start;
p->nr_sects = len;
devfs_register_partition(disk, part);
dev = kmalloc(sizeof(struct device), GFP_KERNEL);
if (!dev)
return;
memset(dev, 0, sizeof(struct device));
dev->parent = parent;
sprintf(dev->bus_id, "p%d", part);
dev->release = part_release;
dev->driver_data = p;
device_register(dev);
device_create_file(dev, &part_attr_dev);
device_create_file(dev, &part_attr_start);
device_create_file(dev, &part_attr_size);
device_create_file(dev, &part_attr_stat);
p->hd_driverfs_dev = dev;
kobject_init(&p->kobj);
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->disk_name,part);
p->kobj.parent = &disk->kobj;
p->kobj.subsys = &part_subsys;
kobject_register(&p->kobj);
}
static ssize_t disk_dev_read(struct device *dev,
char *page, size_t count, loff_t off)
static void disk_sysfs_symlinks(struct gendisk *disk)
{
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",(unsigned long long)get_capacity(disk));
}
static inline unsigned MSEC(unsigned x)
{
return x * 1000 / HZ;
}
static ssize_t disk_stat_read(struct device *dev,
char *page, size_t count, loff_t off)
{
struct gendisk *disk = dev->driver_data;
disk_round_stats(disk);
return off ? 0 : sprintf(page,
"%8u %8u %8llu %8u "
"%8u %8u %8llu %8u "
"%8u %8u %8u"
"\n",
disk->reads, disk->read_merges, (u64)disk->read_sectors,
MSEC(disk->read_ticks),
disk->writes, disk->write_merges, (u64)disk->write_sectors,
MSEC(disk->write_ticks),
disk->in_flight, MSEC(disk->io_ticks),
MSEC(disk->time_in_queue));
}
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 struct device_attribute disk_attr_stat = {
.attr = {.name = "stat", .mode = S_IRUGO },
.show = disk_stat_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);
struct device *target = get_device(disk->driverfs_dev);
if (target) {
sysfs_create_link(&disk->kobj,&target->kobj,"device");
sysfs_create_link(&target->kobj,&disk->kobj,"block");
}
}
/* 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);
strncpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
/* ewww... some of these buggers have / in name... */
s = strchr(dev->bus_id, '/');
s = strchr(disk->kobj.name, '/');
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);
device_create_file(dev, &disk_attr_stat);
disk_driverfs_symlinks(disk);
kobject_register(&disk->kobj);
disk_sysfs_symlinks(disk);
if (disk->flags & GENHD_FL_CD)
devfs_create_cdrom(disk);
......@@ -620,16 +536,12 @@ void del_gendisk(struct gendisk *disk)
disk->time_in_queue = 0;
disk->stamp = disk->stamp_idle = 0;
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);
device_remove_file(&disk->disk_dev, &disk_attr_stat);
driverfs_remove_file(&disk->disk_dev.dir, "device");
kobject_unregister(&disk->kobj);
sysfs_remove_link(&disk->kobj, "device");
if (disk->driverfs_dev) {
driverfs_remove_file(&disk->driverfs_dev->dir, "block");
sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
put_device(disk->driverfs_dev);
}
device_del(&disk->disk_dev);
}
struct dev_name {
......@@ -680,3 +592,4 @@ char *partition_name(dev_t dev)
return dname->name;
}
......@@ -62,7 +62,7 @@ struct hd_struct {
sector_t start_sect;
sector_t nr_sects;
devfs_handle_t de; /* primary (master) devfs entry */
struct device *hd_driverfs_dev; /* support driverfs hiearchy */
struct kobject kobj;
unsigned reads, read_sectors, writes, write_sectors;
int policy;
};
......@@ -93,7 +93,7 @@ struct gendisk {
devfs_handle_t de; /* more of the same */
devfs_handle_t disk_de; /* piled higher and deeper */
struct device *driverfs_dev;
struct device disk_dev;
struct kobject kobj;
struct timer_rand_state *random;
int policy;
......@@ -130,8 +130,6 @@ static inline void set_capacity(struct gendisk *disk, sector_t size)
disk->capacity = size;
}
extern struct device_class disk_devclass;
#endif /* __KERNEL__ */
#ifdef CONFIG_SOLARIS_X86_PARTITION
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment