From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hannes Reinecke Date: Thu, 17 Jun 2004 11:21:48 +0000 Subject: Delayed hotplug events Message-Id: <40D17ECC.20501@suse.de> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------060909020407040203030507" List-Id: To: linux-hotplug@vger.kernel.org This is a multi-part message in MIME format. --------------060909020407040203030507 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: quoted-printable Hi all, currently we have the problem that the driver core might send out=20 hotplug events even though the initialisation of a device has not been=20 finished; worse, we might get an "add" followed by an "remove" event if=20 the device fails to initialise properly, with the corresponding device=20 never appearing in sysfs properly. This is due to the design of the driver core: a call to device_register will trigger a hotplug event, but any sysfs=20 attributes which are added _after_ device_register() will in fact=20 created after the hotplug event has been triggered. For the unbelievers,=20 look at drivers/scsi/scsi_sysfs.c:scsi_sysfs_add_sdev(). This leads to all sorts of nasty race conditions and waiting loops in=20 the hotplug agents. To solve this I've wrapped up a patch for delaying / suspending hotplug=20 events until they are explicitely enabled again. As an example of how it should be used I've patched=20 drivers/scsi/scsi_sysfs.c:scsi_sysfs_add_sdev(), so that the device=20 "add" event will now be triggered only _after_ the device has been=20 initialised properly, including all sysfs attributes. Is this approach feasible or am I completely off kilter here? And if the latter, how should it be solved properly? (Note: this is a proof of concept. No devices have been harmed in=20 creating this patch. I just wanted to get a general opinion before=20 venturing any further.) Cheers, Hannes --=20 Dr. Hannes Reinecke hare@suse.de SuSE Linux AG S390 & zSeries Maxfeldstra=DFe 5 +49 911 74053 688 90409 N=FCrnberg http://www.suse.de --------------060909020407040203030507 Content-Type: text/x-patch; name="delay-hotplug-events.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="delay-hotplug-events.patch" --- ./lib/kobject.c.orig 2004-06-17 09:18:27.000000000 +0200 +++ ./lib/kobject.c 2004-06-17 12:59:55.000000000 +0200 @@ -472,6 +472,53 @@ kobject_cleanup(kobj); } +static int kobject_hotplug_filter_all(struct kset *kset, struct kobject *kobj) +{ + return 0; +} + +/** + * kobject_disable_events - filter out all hotplug events + * @kobj: object + * + */ + +void kobject_disable_events(struct kobject * kobj ) +{ + struct kset_hotplug_ops *delayed_ops; + + if (kobj && kobj->kset) { + down_write(&kobj->kset->subsys->rwsem); + + delayed_ops = kobj->kset->hotplug_ops; + kobj->kset->hotplug_ops_stored = delayed_ops; + + delayed_ops->filter = kobject_hotplug_filter_all; + kobj->kset->hotplug_ops = delayed_ops; + + up_write(&kobj->kset->subsys->rwsem); + } +} + +/** + * kobject_enable_events - reset hotplug filter to original value + * @kobj: object + * + */ + +void kobject_enable_events(struct kobject * kobj ) +{ + struct kset_hotplug_ops *delayed_ops; + + if (kobj && kobj->kset && kobj->kset->hotplug_ops_stored) { + down_write(&kobj->kset->subsys->rwsem); + + kobj->kset->hotplug_ops = kobj->kset->hotplug_ops_stored; + kobj->kset->hotplug_ops_stored = NULL; + + up_write(&kobj->kset->subsys->rwsem); + } +} /** * kset_init - initialize a kset for use @@ -635,6 +682,8 @@ EXPORT_SYMBOL(kobject_del); EXPORT_SYMBOL(kobject_rename); EXPORT_SYMBOL(kobject_hotplug); +EXPORT_SYMBOL(kobject_enable_events); +EXPORT_SYMBOL(kobject_disable_events); EXPORT_SYMBOL(kset_register); EXPORT_SYMBOL(kset_unregister); --- ./drivers/base/core.c.orig 2004-06-17 09:03:58.000000000 +0200 +++ ./drivers/base/core.c 2004-06-17 13:06:29.581368704 +0200 @@ -271,6 +271,25 @@ return device_add(dev); } +void device_suspend_hotplug(struct device *dev) +{ + get_device(dev); + + kobject_disable_events(&dev->kobj); + + put_device(dev); +} + +void device_resume_hotplug(struct device *dev) +{ + get_device(dev); + + kobject_enable_events(&dev->kobj); + + kobject_hotplug("add", &dev->kobj); + + put_device(dev); +} /** * get_device - increment reference count for device. @@ -405,3 +424,5 @@ EXPORT_SYMBOL(device_create_file); EXPORT_SYMBOL(device_remove_file); +EXPORT_SYMBOL(device_suspend_hotplug); +EXPORT_SYMBOL(device_resume_hotplug); --- ./drivers/scsi/scsi_sysfs.c.orig 2004-06-17 13:00:45.000000000 +0200 +++ ./drivers/scsi/scsi_sysfs.c 2004-06-17 13:03:13.071318353 +0200 @@ -379,6 +379,7 @@ if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) return error; + device_suspend_hotplug(&sdev->sdev_gendev); error = device_add(&sdev->sdev_gendev); if (error) { printk(KERN_INFO "error 1\n"); @@ -439,6 +440,8 @@ } } + device_resume_hotplug(&sdev->sdev_gendev); + out: return error; --- ./include/linux/kobject.h.orig 2004-06-17 11:22:29.000000000 +0200 +++ ./include/linux/kobject.h 2004-06-17 12:55:06.000000000 +0200 @@ -47,6 +47,8 @@ extern int kobject_add(struct kobject *); extern void kobject_del(struct kobject *); +extern void kobject_enable_events(struct kobject *kobj); +extern void kobject_disable_events(struct kobject *kobj); extern int kobject_rename(struct kobject *, char *new_name); @@ -96,6 +98,7 @@ struct list_head list; struct kobject kobj; struct kset_hotplug_ops * hotplug_ops; + struct kset_hotplug_ops * hotplug_ops_stored; }; --- ./include/linux/device.h.orig 2004-06-17 12:14:21.000000000 +0200 +++ ./include/linux/device.h 2004-06-17 12:14:56.000000000 +0200 @@ -332,6 +332,8 @@ extern void device_bind_driver(struct device * dev); extern void device_release_driver(struct device * dev); extern void driver_attach(struct device_driver * drv); +extern void device_suspend_hotplug(struct device *dev); +extern void device_resume_hotplug(struct device *dev); /* driverfs interface for exporting device attributes */ --------------060909020407040203030507-- ------------------------------------------------------- This SF.Net email is sponsored by The 2004 JavaOne(SM) Conference Learn from the experts at JavaOne(SM), Sun's Worldwide Java Developer Conference, June 28 - July 1 at the Moscone Center in San Francisco, CA REGISTER AND SAVE! http://java.sun.com/javaone/sf Priority Code NWMGYKND _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel