Commit a7fd6706 authored by Kay Sievers's avatar Kay Sievers Committed by Greg Kroah-Hartman

[PATCH] add sysfs attr to re-emit device hotplug event

A "coldplug + udevstart" can be simple like this:
  for i in /sys/block/*/*/uevent; do echo 1 > $i; done
  for i in /sys/class/*/*/uevent; do echo 1 > $i; done
  for i in /sys/bus/*/devices/*/uevent; do echo 1 > $i; done
Signed-off-by: default avatarKay Sievers <kay.sievers@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d8539d81
...@@ -442,6 +442,13 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) ...@@ -442,6 +442,13 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
return print_dev_t(buf, class_dev->devt); return print_dev_t(buf, class_dev->devt);
} }
static ssize_t store_uevent(struct class_device *class_dev,
const char *buf, size_t count)
{
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
return count;
}
void class_device_initialize(struct class_device *class_dev) void class_device_initialize(struct class_device *class_dev)
{ {
kobj_set_kset_s(class_dev, class_obj_subsys); kobj_set_kset_s(class_dev, class_obj_subsys);
...@@ -497,6 +504,12 @@ int class_device_add(struct class_device *class_dev) ...@@ -497,6 +504,12 @@ int class_device_add(struct class_device *class_dev)
goto register_done; goto register_done;
/* add the needed attributes to this device */ /* add the needed attributes to this device */
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent->owner;
class_dev->uevent_attr.store = store_uevent;
class_device_create_file(class_dev, &class_dev->uevent_attr);
if (MAJOR(class_dev->devt)) { if (MAJOR(class_dev->devt)) {
struct class_device_attribute *attr; struct class_device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL); attr = kzalloc(sizeof(*attr), GFP_KERNEL);
...@@ -505,12 +518,10 @@ int class_device_add(struct class_device *class_dev) ...@@ -505,12 +518,10 @@ int class_device_add(struct class_device *class_dev)
kobject_del(&class_dev->kobj); kobject_del(&class_dev->kobj);
goto register_done; goto register_done;
} }
attr->attr.name = "dev"; attr->attr.name = "dev";
attr->attr.mode = S_IRUGO; attr->attr.mode = S_IRUGO;
attr->attr.owner = parent->owner; attr->attr.owner = parent->owner;
attr->show = show_dev; attr->show = show_dev;
attr->store = NULL;
class_device_create_file(class_dev, attr); class_device_create_file(class_dev, attr);
class_dev->devt_attr = attr; class_dev->devt_attr = attr;
} }
...@@ -621,6 +632,7 @@ void class_device_del(struct class_device *class_dev) ...@@ -621,6 +632,7 @@ void class_device_del(struct class_device *class_dev)
sysfs_remove_link(&class_dev->kobj, "device"); sysfs_remove_link(&class_dev->kobj, "device");
sysfs_remove_link(&class_dev->dev->kobj, class_name); sysfs_remove_link(&class_dev->dev->kobj, class_name);
} }
class_device_remove_file(class_dev, &class_dev->uevent_attr);
if (class_dev->devt_attr) if (class_dev->devt_attr)
class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_file(class_dev, class_dev->devt_attr);
class_device_remove_attrs(class_dev); class_device_remove_attrs(class_dev);
......
...@@ -154,6 +154,13 @@ static struct kset_hotplug_ops device_hotplug_ops = { ...@@ -154,6 +154,13 @@ static struct kset_hotplug_ops device_hotplug_ops = {
.hotplug = dev_hotplug, .hotplug = dev_hotplug,
}; };
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
kobject_hotplug(&dev->kobj, KOBJ_ADD);
return count;
}
/** /**
* device_subsys - structure to be registered with kobject core. * device_subsys - structure to be registered with kobject core.
*/ */
...@@ -259,6 +266,14 @@ int device_add(struct device *dev) ...@@ -259,6 +266,14 @@ int device_add(struct device *dev)
if ((error = kobject_add(&dev->kobj))) if ((error = kobject_add(&dev->kobj)))
goto Error; goto Error;
dev->uevent_attr.attr.name = "uevent";
dev->uevent_attr.attr.mode = S_IWUSR;
if (dev->driver)
dev->uevent_attr.attr.owner = dev->driver->owner;
dev->uevent_attr.store = store_uevent;
device_create_file(dev, &dev->uevent_attr);
kobject_hotplug(&dev->kobj, KOBJ_ADD); kobject_hotplug(&dev->kobj, KOBJ_ADD);
if ((error = device_pm_add(dev))) if ((error = device_pm_add(dev)))
goto PMError; goto PMError;
...@@ -350,6 +365,7 @@ void device_del(struct device * dev) ...@@ -350,6 +365,7 @@ void device_del(struct device * dev)
if (parent) if (parent)
klist_del(&dev->knode_parent); klist_del(&dev->knode_parent);
device_remove_file(dev, &dev->uevent_attr);
/* Notify the platform of the removal, in case they /* Notify the platform of the removal, in case they
* need to do anything... * need to do anything...
......
...@@ -337,10 +337,30 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, ...@@ -337,10 +337,30 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
return ret; return ret;
} }
static ssize_t disk_attr_store(struct kobject * kobj, struct attribute * attr,
const char *page, size_t count)
{
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->store)
ret = disk_attr->store(disk, page, count);
return ret;
}
static struct sysfs_ops disk_sysfs_ops = { static struct sysfs_ops disk_sysfs_ops = {
.show = &disk_attr_show, .show = &disk_attr_show,
.store = &disk_attr_store,
}; };
static ssize_t disk_uevent_store(struct gendisk * disk,
const char *buf, size_t count)
{
kobject_hotplug(&disk->kobj, KOBJ_ADD);
return count;
}
static ssize_t disk_dev_read(struct gendisk * disk, char *page) static ssize_t disk_dev_read(struct gendisk * disk, char *page)
{ {
dev_t base = MKDEV(disk->major, disk->first_minor); dev_t base = MKDEV(disk->major, disk->first_minor);
...@@ -382,6 +402,10 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) ...@@ -382,6 +402,10 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
} }
static struct disk_attribute disk_attr_uevent = {
.attr = {.name = "uevent", .mode = S_IWUSR },
.store = disk_uevent_store
};
static struct disk_attribute disk_attr_dev = { static struct disk_attribute disk_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO }, .attr = {.name = "dev", .mode = S_IRUGO },
.show = disk_dev_read .show = disk_dev_read
...@@ -404,6 +428,7 @@ static struct disk_attribute disk_attr_stat = { ...@@ -404,6 +428,7 @@ static struct disk_attribute disk_attr_stat = {
}; };
static struct attribute * default_attrs[] = { static struct attribute * default_attrs[] = {
&disk_attr_uevent.attr,
&disk_attr_dev.attr, &disk_attr_dev.attr,
&disk_attr_range.attr, &disk_attr_range.attr,
&disk_attr_removable.attr, &disk_attr_removable.attr,
......
...@@ -192,6 +192,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev) ...@@ -192,6 +192,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
struct part_attribute { struct part_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct hd_struct *,char *); ssize_t (*show)(struct hd_struct *,char *);
ssize_t (*store)(struct hd_struct *,const char *, size_t);
}; };
static ssize_t static ssize_t
...@@ -201,14 +202,33 @@ part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) ...@@ -201,14 +202,33 @@ part_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
ssize_t ret = 0; ssize_t ret = 0;
if (part_attr->show) if (part_attr->show)
ret = part_attr->show(p,page); ret = part_attr->show(p, page);
return ret;
}
static ssize_t
part_attr_store(struct kobject * kobj, struct attribute * attr,
const char *page, size_t count)
{
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->store)
ret = part_attr->store(p, page, count);
return ret; return ret;
} }
static struct sysfs_ops part_sysfs_ops = { static struct sysfs_ops part_sysfs_ops = {
.show = part_attr_show, .show = part_attr_show,
.store = part_attr_store,
}; };
static ssize_t part_uevent_store(struct hd_struct * p,
const char *page, size_t count)
{
kobject_hotplug(&p->kobj, KOBJ_ADD);
return count;
}
static ssize_t part_dev_read(struct hd_struct * p, char *page) static ssize_t part_dev_read(struct hd_struct * p, char *page)
{ {
struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
...@@ -229,6 +249,10 @@ static ssize_t part_stat_read(struct hd_struct * p, char *page) ...@@ -229,6 +249,10 @@ static ssize_t part_stat_read(struct hd_struct * p, char *page)
p->reads, (unsigned long long)p->read_sectors, p->reads, (unsigned long long)p->read_sectors,
p->writes, (unsigned long long)p->write_sectors); p->writes, (unsigned long long)p->write_sectors);
} }
static struct part_attribute part_attr_uevent = {
.attr = {.name = "uevent", .mode = S_IWUSR },
.store = part_uevent_store
};
static struct part_attribute part_attr_dev = { static struct part_attribute part_attr_dev = {
.attr = {.name = "dev", .mode = S_IRUGO }, .attr = {.name = "dev", .mode = S_IRUGO },
.show = part_dev_read .show = part_dev_read
...@@ -247,6 +271,7 @@ static struct part_attribute part_attr_stat = { ...@@ -247,6 +271,7 @@ static struct part_attribute part_attr_stat = {
}; };
static struct attribute * default_attrs[] = { static struct attribute * default_attrs[] = {
&part_attr_uevent.attr,
&part_attr_dev.attr, &part_attr_dev.attr,
&part_attr_start.attr, &part_attr_start.attr,
&part_attr_size.attr, &part_attr_size.attr,
......
...@@ -190,6 +190,18 @@ struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) ...@@ -190,6 +190,18 @@ struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store)
extern int class_create_file(struct class *, const struct class_attribute *); extern int class_create_file(struct class *, const struct class_attribute *);
extern void class_remove_file(struct class *, const struct class_attribute *); extern void class_remove_file(struct class *, const struct class_attribute *);
struct class_device_attribute {
struct attribute attr;
ssize_t (*show)(struct class_device *, char * buf);
ssize_t (*store)(struct class_device *, const char * buf, size_t count);
};
#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute class_device_attr_##_name = \
__ATTR(_name,_mode,_show,_store)
extern int class_device_create_file(struct class_device *,
const struct class_device_attribute *);
struct class_device { struct class_device {
struct list_head node; struct list_head node;
...@@ -198,6 +210,7 @@ struct class_device { ...@@ -198,6 +210,7 @@ struct class_device {
struct class * class; /* required */ struct class * class; /* required */
dev_t devt; /* dev_t, creates the sysfs "dev" */ dev_t devt; /* dev_t, creates the sysfs "dev" */
struct class_device_attribute *devt_attr; struct class_device_attribute *devt_attr;
struct class_device_attribute uevent_attr;
struct device * dev; /* not necessary, but nice to have */ struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */ void * class_data; /* class-specific data */
...@@ -228,18 +241,6 @@ extern int class_device_rename(struct class_device *, char *); ...@@ -228,18 +241,6 @@ extern int class_device_rename(struct class_device *, char *);
extern struct class_device * class_device_get(struct class_device *); extern struct class_device * class_device_get(struct class_device *);
extern void class_device_put(struct class_device *); extern void class_device_put(struct class_device *);
struct class_device_attribute {
struct attribute attr;
ssize_t (*show)(struct class_device *, char * buf);
ssize_t (*store)(struct class_device *, const char * buf, size_t count);
};
#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute class_device_attr_##_name = \
__ATTR(_name,_mode,_show,_store)
extern int class_device_create_file(struct class_device *,
const struct class_device_attribute *);
extern void class_device_remove_file(struct class_device *, extern void class_device_remove_file(struct class_device *,
const struct class_device_attribute *); const struct class_device_attribute *);
extern int class_device_create_bin_file(struct class_device *, extern int class_device_create_bin_file(struct class_device *,
...@@ -266,6 +267,20 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt, ...@@ -266,6 +267,20 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt,
extern void class_device_destroy(struct class *cls, dev_t devt); extern void class_device_destroy(struct class *cls, dev_t devt);
/* interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
#define DEVICE_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
extern int device_create_file(struct device *device, struct device_attribute * entry);
extern void device_remove_file(struct device * dev, struct device_attribute * attr);
struct device { struct device {
struct klist klist_children; struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_parent; /* node in sibling list */
...@@ -275,6 +290,7 @@ struct device { ...@@ -275,6 +290,7 @@ struct device {
struct kobject kobj; struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */ char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_attribute uevent_attr;
struct semaphore sem; /* semaphore to synchronize calls to struct semaphore sem; /* semaphore to synchronize calls to
* its driver. * its driver.
...@@ -343,23 +359,6 @@ extern int device_attach(struct device * dev); ...@@ -343,23 +359,6 @@ extern int device_attach(struct device * dev);
extern void driver_attach(struct device_driver * drv); extern void driver_attach(struct device_driver * drv);
/* driverfs interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
#define DEVICE_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
extern int device_create_file(struct device *device, struct device_attribute * entry);
extern void device_remove_file(struct device * dev, struct device_attribute * attr);
/* /*
* Platform "fixup" functions - allow the platform to have their say * Platform "fixup" functions - allow the platform to have their say
* about devices and actions that the general device layer doesn't * about devices and actions that the general device layer doesn't
......
...@@ -132,6 +132,7 @@ struct gendisk { ...@@ -132,6 +132,7 @@ struct gendisk {
struct disk_attribute { struct disk_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct gendisk *, char *); ssize_t (*show)(struct gendisk *, char *);
ssize_t (*store)(struct gendisk *, const char *, size_t);
}; };
/* /*
......
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