Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -442,6 +442,13 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
	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)
{
	kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -497,6 +504,12 @@ int class_device_add(struct class_device *class_dev)
		goto register_done;

	/* 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)) {
		struct class_device_attribute *attr;
		attr = kzalloc(sizeof(*attr), GFP_KERNEL);
@@ -505,12 +518,10 @@ int class_device_add(struct class_device *class_dev)
			kobject_del(&class_dev->kobj);
			goto register_done;
		}

		attr->attr.name = "dev";
		attr->attr.mode = S_IRUGO;
		attr->attr.owner = parent->owner;
		attr->show = show_dev;
		attr->store = NULL;
		class_device_create_file(class_dev, attr);
		class_dev->devt_attr = attr;
	}
@@ -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->dev->kobj, class_name);
	}
	class_device_remove_file(class_dev, &class_dev->uevent_attr);
	if (class_dev->devt_attr)
		class_device_remove_file(class_dev, class_dev->devt_attr);
	class_device_remove_attrs(class_dev);
+16 −0
Original line number Diff line number Diff line
@@ -154,6 +154,13 @@ static struct kset_hotplug_ops device_hotplug_ops = {
	.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.
 */
@@ -259,6 +266,14 @@ int device_add(struct device *dev)

	if ((error = kobject_add(&dev->kobj)))
		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);
	if ((error = device_pm_add(dev)))
		goto PMError;
@@ -350,6 +365,7 @@ void device_del(struct device * dev)

	if (parent)
		klist_del(&dev->knode_parent);
	device_remove_file(dev, &dev->uevent_attr);

	/* Notify the platform of the removal, in case they
	 * need to do anything...
+25 −0
Original line number Diff line number Diff line
@@ -337,10 +337,30 @@ static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
	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 = {
	.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)
{
	dev_t base = MKDEV(disk->major, disk->first_minor); 
@@ -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, 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 = {
	.attr = {.name = "dev", .mode = S_IRUGO },
	.show	= disk_dev_read
@@ -404,6 +428,7 @@ static struct disk_attribute disk_attr_stat = {
};

static struct attribute * default_attrs[] = {
	&disk_attr_uevent.attr,
	&disk_attr_dev.attr,
	&disk_attr_range.attr,
	&disk_attr_removable.attr,
+26 −1
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev)
struct part_attribute {
	struct attribute attr;
	ssize_t (*show)(struct hd_struct *,char *);
	ssize_t (*store)(struct hd_struct *,const char *, size_t);
};

static ssize_t 
@@ -204,11 +205,30 @@ part_attr_show(struct kobject * kobj, struct attribute * attr, char * 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;
}

static struct sysfs_ops part_sysfs_ops = {
	.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)
{
	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)
		       p->reads, (unsigned long long)p->read_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 = {
	.attr = {.name = "dev", .mode = S_IRUGO },
	.show	= part_dev_read
@@ -247,6 +271,7 @@ static struct part_attribute part_attr_stat = {
};

static struct attribute * default_attrs[] = {
	&part_attr_uevent.attr,
	&part_attr_dev.attr,
	&part_attr_start.attr,
	&part_attr_size.attr,
+28 −29
Original line number Diff line number Diff line
@@ -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 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 list_head	node;
@@ -198,6 +210,7 @@ struct class_device {
	struct class		* class;	/* required */
	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
	struct class_device_attribute *devt_attr;
	struct class_device_attribute uevent_attr;
	struct device		* dev;		/* not necessary, but nice to have */
	void			* class_data;	/* class-specific data */

@@ -228,18 +241,6 @@ extern int class_device_rename(struct class_device *, char *);
extern struct class_device * class_device_get(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 *, 
				     const struct class_device_attribute *);
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,
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 klist		klist_children;
	struct klist_node	knode_parent;		/* node in sibling list */
@@ -275,6 +290,7 @@ struct device {

	struct kobject kobj;
	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
	struct device_attribute uevent_attr;

	struct semaphore	sem;	/* semaphore to synchronize calls to
					 * its driver.
@@ -343,23 +359,6 @@ extern int device_attach(struct device * dev);
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
 * about devices and actions that the general device layer doesn't
Loading