Don't issue uevents for legacy platform drivers

David Brownell dbrownell at users.sourceforge.unroutablenet
Wed Dec 13 04:33:15 EST 2006


Commit:     23ec7ff48b3b2fd9ad5897d7389cc06b6d8e6b7e
Parent:     e50b707bd42b0c4f395929830976443e5a4e21be
commit 23ec7ff48b3b2fd9ad5897d7389cc06b6d8e6b7e
Author:     David Brownell <dbrownell at users.sourceforge.net>
AuthorDate: Wed Dec 13 04:12:40 2006 -0500
Commit:     Andres Salomon <dilinger at debian.org>
CommitDate: Wed Dec 13 04:12:40 2006 -0500

    Don't issue uevents for legacy platform drivers
    
    We've had recent reports of some legacy "probe the hardware" style platform
    drivers having nasty problems with hotplug support.
    
    The core issue is that those drivers don't fully conform to the driver
    model.
    They assume a role that's the responsibility of infrastructure code:  they
    create their own device nodes.  But hotplugging relies on drivers to have
    split
    those roles into different modules, hence the problems.  If the driver
    creates
    nodes for devices that don't exist, the "modprobe $MODALIAS" step of
    hotplugging
    can become an endless loop *when driver load aborts* (it's safe otherwise).
    
    This fix adds a per-device flag saying whether its driver can't be
    hotplugged,
    which is set by APIs used for "probe the hardware" style drivers.  The flag
    is used to bypass relevant hotplug logic (setting the $MODALIAS environment
    variable) for those problematic drivers.
    
    The minor glitch is that in a few cases those APIs are used by platform
    code,
    instead of by drivers.  Examples include most places where a "pcspkr"
    device is
    created (although a recent un-merged patch fixed that for X86_PC), or the
    way
    platform devices are created for OpenFirmware nodes ... all those cases
    seem
    to kick in before userspace (and hotplug) is active though.
    
    So the net of this patch is removing some nasty failures with legacy
    drivers,
    while retaining hotplug capability for those platform drivers which are
    well
    behaved (the majority).
---
 drivers/base/platform.c |   20 ++++++++++++++++++++
 include/linux/device.h  |    1 +
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 940ce41..632be31 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,6 +160,11 @@ static void platform_device_release(stru
  *
  *	Create a platform device object which can have other objects attached
  *	to it, and which will have attached objects freed when it is released.
+ *
+ *	This device will be marked as not supporting hotpluggable drivers.  In
+ *	the unusual case that the device isn't being dynamically allocated as
+ *	of a legacy "probe the hardware" driver, infrastructure code should
+ *	consider reversing this marking.
  */
 struct platform_device *platform_device_alloc(const char *name, unsigned int id)
 {
@@ -172,6 +177,7 @@ struct platform_device *platform_device_
 		pa->pdev.id = id;
 		device_initialize(&pa->pdev.dev);
 		pa->pdev.dev.release = platform_device_release;
+		pa->pdev.dev.is_driver_not_hotpluggable = 1;
 	}
 
 	return pa ? &pa->pdev : NULL;
@@ -349,6 +355,13 @@ EXPORT_SYMBOL_GPL(platform_device_unregi
  *	memory allocated for the device allows drivers using such devices
  *	to be unloaded iwithout waiting for the last reference to the device
  *	to be dropped.
+ *
+ *	This interface is primarily intended for use with legacy drivers
+ *	which probe hardware directly.  Because such drivers create device
+ *	nodes themselves, rather than letting system infrastructure handle
+ *	such device enumeration tasks, they don't fully conform to the Linux
+ *	driver model.  In particular, when such drivers are built as modules,
+ *	they can't be "hotplugged".
  */
 struct platform_device *platform_device_register_simple(char *name, unsigned int id,
 							struct resource *res, unsigned int num)
@@ -477,6 +490,13 @@ static int platform_uevent(struct device
 {
 	struct platform_device	*pdev = to_platform_device(dev);
 
+	/* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
+	 * legacy probe-the-hardware drivers, which don't properly split
+	 * out enumeration logic from drivers.
+	 */
+	if (dev->is_driver_not_hotpluggable)
+		return 0;
+
 	envp[0] = buffer;
 	snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
 	return 0;
diff --git a/include/linux/device.h b/include/linux/device.h
index 662e6a1..494c14c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -330,6 +330,7 @@ struct device {
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
 	unsigned		is_registered:1;
+	unsigned		is_driver_not_hotpluggable:1;
 	struct device_attribute uevent_attr;
 	struct device_attribute *devt_attr;
 


More information about the Commits-kernel mailing list