[patch 2.6.19-rc6] fix hotplug for legacy platform drivers

From: David Brownell
Date: Wed Nov 29 2006 - 17:51:25 EST


On Monday 27 November 2006 11:03 am, Greg KH wrote:

> David, any chance you can fix this up, as people are seeing this bug
> today.

Here's my fix. Unlike the fix Kay suggested, it causes at worst only
a minor loss of functionality, so that tradeoff seems fair for a late
merge. I audited all the drivers using the relevant APIs, and I can't
see many (if any!) folk hitting problems from this.

- Dave


============== CUT HERE
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).

Signed-off-by: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>


Index: g26/include/linux/device.h
===================================================================
--- g26.orig/include/linux/device.h 2006-11-27 21:01:30.000000000 -0800
+++ g26/include/linux/device.h 2006-11-27 21:03:48.000000000 -0800
@@ -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;

Index: g26/drivers/base/platform.c
===================================================================
--- g26.orig/drivers/base/platform.c 2006-11-27 21:03:46.000000000 -0800
+++ g26/drivers/base/platform.c 2006-11-29 11:02:04.000000000 -0800
@@ -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)
@@ -525,6 +538,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;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/