Skip to contentSkip to conversation

Driver core patches for 2.6.21

PATCH New Greg KH 2 participants 48 messages Apr 27, 2007 1 message not in the archive

Subsystems (26)
lore
Share & tools
lore

Greg KH

author
#0 lore raw

PATCH 1/1 Driver core patches for 2.6.21

Here are some driver core patche for 2.6.21.

They do a wide range of things, see the shortlog below for details.

All of these have been in the -mm tree for quite some time.

Please pull from:
master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6.git/

Patches will be sent as a follow-on to this message to lkml for people to see.

thanks,

greg k-h

 Documentation/feature-removal-schedule.txt |    9 -
 arch/powerpc/kernel/of_platform.c          |    3 -
 drivers/amba/bus.c                         |   13 +-
 drivers/base/attribute_container.c         |   26 ++--
 drivers/base/base.h                        |    2 +-
 drivers/base/bus.c                         |  112 +++++++++--
 drivers/base/class.c                       |    2 +-
 drivers/base/core.c                        |  293 ++++++++++++++++++++--------
 drivers/base/dd.c                          |   66 ++++---
 drivers/base/dmapool.c                     |   14 +-
 drivers/base/driver.c                      |   20 --
 drivers/base/firmware_class.c              |   10 +-
 drivers/base/power/main.c                  |    3 +
 drivers/base/power/resume.c                |   13 ++-
 drivers/base/power/shutdown.c              |    2 -
 drivers/base/power/suspend.c               |   12 ++
 drivers/ide/ide-proc.c                     |    4 -
 drivers/ieee1394/nodemgr.c                 |   22 +--
 drivers/input/gameport/gameport.c          |   39 ++---
 drivers/input/serio/serio.c                |   41 ++---
 drivers/mmc/mmc_sysfs.c                    |   27 +--
 drivers/net/phy/fixed.c                    |    6 -
 drivers/net/phy/phy_device.c               |    9 +-
 drivers/pci/pci-driver.c                   |    6 +-
 drivers/pci/pci.c                          |   58 ++++--
 drivers/pnp/card.c                         |    6 -
 drivers/s390/cio/device.c                  |    6 +
 drivers/s390/crypto/ap_bus.c               |   28 ++--
 drivers/s390/net/qeth_proc.c               |    2 -
 drivers/scsi/hosts.c                       |    4 +-
 drivers/usb/core/devices.c                 |    2 -
 drivers/usb/core/devio.c                   |   13 --
 drivers/usb/core/driver.c                  |   12 +-
 drivers/usb/core/hub.c                     |    4 +-
 drivers/usb/core/message.c                 |    2 +-
 drivers/usb/host/ohci-hcd.c                |    6 -
 fs/debugfs/file.c                          |   42 ++++
 fs/namei.c                                 |   72 +++++--
 fs/super.c                                 |   12 --
 fs/sysfs/bin.c                             |    2 +-
 fs/sysfs/file.c                            |   14 +-
 fs/sysfs/group.c                           |    6 +-
 include/linux/debugfs.h                    |    9 +
 include/linux/device.h                     |   69 +++++---
 include/linux/kobject.h                    |   12 +-
 include/linux/namei.h                      |    1 +
 include/linux/pci.h                        |    2 -
 include/linux/pm.h                         |   37 ++++
 include/linux/sysfs.h                      |    4 +-
 kernel/module.c                            |    4 +-
 kernel/power/main.c                        |   18 ++-
 lib/kobject.c                              |   62 +++++-
 lib/kobject_uevent.c                       |   26 ++--
 lib/kref.c                                 |    2 +
 net/core/net-sysfs.c                       |   27 ++-
 sound/aoa/soundbus/core.c                  |   80 +++-----
 56 files changed, 854 insertions(+), 544 deletions(-)

---------------

Adrian Bunk (1):
the overdue removal of the mount/umount uevents

Akinobu Mita (1):
mod_sysfs_setup() doesn't return errno when kobject_add_dir() failure occurs

Alan Stern (1):
device_schedule_callback() needs a module reference

Andrew Morton (2):
powerpc: make it compile for multithread change
sysfs: bin.c printk fix

Cornelia Huck (7):
driver core: per-subsystem multithreaded probing driver core: don't fail attaching the device if it cannot be bound Driver core: suppress uevents via filter
Driver core: switch firmware_class to uevent_suppress.
kobject: kobject_add() reference leak
qeth: Remove usage of subsys.rwsem
s390: cio: Delay uevents for subchannels

Dan Williams (1):
dev_dbg: check dev_dbg() arguments

David Brownell (1):
define platform wakeup hook, use in pci_enable_wake()

Dmitriy Monakhov (2):
driver core: fix device_add error path
kobject: kobject_shadow_add cleanup

Dmitry Torokhov (4):
driver core: Use attribute groups in struct device_type Driver core: add suspend() and resume() to struct device_type
Input: serio - do not touch bus's rwsem
Input: gameport - do not touch bus's rwsem

Eric Rannaud (1):
uevent: use add_uevent_var() instead of open coding it

Eric W. Biederman (1):
kobject: Comment and warning fixes to kobject.c

Greg Kroah-Hartman (10):
Driver core: remove unneeded completion from driver release path Driver core: remove use of rwsem
SCSI: use the proper semaphore to protect the class lists
USB: remove use of the bus rwsem, as it doesn't really protect anything.
PNP: stop using the subsystem rwsem
IDE: remove rwsem use from ide-proc core
IEEE1394: remove rwsem use from ieee1394 core
PHY: remove rwsem use from phy core
kobject core: remove rwsem from struct subsystem
driver core: bus_add_driver should return an error if no bus

James Morris (1):
security: prevent permission checking of file removal via sysfs_remove_group()

Jean Delvare (1):
dev_printk and new-style class devices

Jean Tourrilhes (1):
Driver core: notify userspace of network device renames

Johannes Berg (1):
s2ram: add arch irq disable/enable hooks

John Anthony Kazos Jr (1):
Kobject: kobject_uevent.c: Collapse unnecessary loop nesting (top_kobj)

Kay Sievers (5):
driver core: fix namespace issue with devices assigned to classes Driver core: udev triggered device-<>driver binding
Driver core: add name to device_type
Driver core: make uevent-environment available in uevent-file Driver core: warn when userspace writes to the uevent file in a non-supported way

Matthias Kaehlcke (2):
Driver core: use mutex instead of semaphore in DMA pool handler drivers/base/attribute_container.c: use mutex instead of binary semaphore

Michael Ellerman (1):
debugfs: Add debugfs_create_u64()

Oliver Neukum (1):
kref: fix CPU ordering with respect to krefs

#1 lore raw

PATCH 1/46 driver core: fix device_add error path

From: Dmitriy Monakhov <[email protected]>

- At the moment we jump here device was't added to dev->class->devices list yet.

---
 drivers/base/core.c |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)
drivers/base/core.c +0 -9
index d7fcf82..db3a151 100644
@@ -677,15 +677,6 @@ int device_add(struct device *dev)
 #endif
 			sysfs_remove_link(&dev->kobj, "device");
 		}
-
-		down(&dev->class->sem);
-		/* notify any interfaces that the device is now gone */
-		list_for_each_entry(class_intf, &dev->class->interfaces, node)
-			if (class_intf->remove_dev)
-				class_intf->remove_dev(dev, class_intf);
-		/* remove the device from the class list */
-		list_del_init(&dev->node);
-		up(&dev->class->sem);
 	}
  ueventattrError:
 	device_remove_file(dev, &dev->uevent_attr);
Signature · 1 line
1.5.1.2
#2 lore raw

PATCH 2/46 driver core: fix namespace issue with devices assigned to classes

From: Kay Sievers <[email protected]>

- uses a kset in "struct class" to keep track of all directories belonging to this class
- merges with the /sys/devices/virtual logic.
- removes the namespace-dir if the last member of that class leaves the directory.

There may be locking or refcounting fixes left, I stopped when it seemed to work with network and sound modules. :)

From: Kay Sievers <[email protected]>

---
 drivers/base/class.c    |    2 +-
 drivers/base/core.c     |   82 +++++++++++++++++++++++++++++++++++++----------
 include/linux/device.h  |    3 +-
 include/linux/kobject.h |    2 +
 lib/kobject.c           |   12 ++++++-
 lib/kobject_uevent.c    |   16 ++++++---
 6 files changed, 89 insertions(+), 28 deletions(-)
drivers/base/class.c +1 -1
index d596812..80bbb20 100644
@@ -145,6 +145,7 @@ int class_register(struct class * cls)
 	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->devices);
 	INIT_LIST_HEAD(&cls->interfaces);
+	kset_init(&cls->class_dirs);
 	init_MUTEX(&cls->sem);
 	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
 	if (error)
@@ -163,7 +164,6 @@ int class_register(struct class * cls)
 void class_unregister(struct class * cls)
 {
 	pr_debug("device class '%s': unregistering\n", cls->name);
-	kobject_unregister(cls->virtual_dir);
 	remove_class_attrs(cls);
 	subsystem_unregister(&cls->subsys);
 }
drivers/base/core.c +65 -17

112 lines not on this page · raw message

include/linux/device.h +1 -2
index 5cf30e9..de0e73e 100644
@@ -181,10 +181,9 @@ struct class {
 	struct list_head	children;
 	struct list_head	devices;
 	struct list_head	interfaces;
+	struct kset		class_dirs;
 	struct semaphore	sem;	/* locks both the children and interfaces lists */
 
-	struct kobject		*virtual_dir;
-
 	struct class_attribute		* class_attrs;
 	struct class_device_attribute	* class_dev_attrs;
 	struct device_attribute		* dev_attrs;
include/linux/kobject.h +2 -0
index b850e03..d37cd7f 100644
@@ -89,6 +89,8 @@ extern void kobject_unregister(struct kobject *);
 extern struct kobject * kobject_get(struct kobject *);
 extern void kobject_put(struct kobject *);
 
+extern struct kobject *kobject_kset_add_dir(struct kset *kset,
+					    struct kobject *, const char *);
 extern struct kobject *kobject_add_dir(struct kobject *, const char *);
 
 extern char * kobject_get_path(struct kobject *, gfp_t);
lib/kobject.c +10 -2
index 057921c..f664551 100644
@@ -488,13 +488,15 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *	kobject_add_dir - add sub directory of object.
+ *	kobject__kset_add_dir - add sub directory of object.
+ *	@kset:		kset the directory is belongs to.
  *	@parent:	object in which a directory is created.
  *	@name:	directory name.
  *
  *	Add a plain directory object as child of given object.
  */
-struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+struct kobject *kobject_kset_add_dir(struct kset *kset,
+				     struct kobject *parent, const char *name)
 {
 	struct kobject *k;
 	int ret;
@@ -506,6 +508,7 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
 	if (!k)
 		return NULL;
 
+	k->kset = kset;
 	k->parent = parent;
 	k->ktype = &dir_ktype;
 	kobject_set_name(k, name);
@@ -520,6 +523,11 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
 	return k;
 }
 
+struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+{
+	return kobject_kset_add_dir(NULL, parent, name);
+}
+
 /**
  *	kset_init - initialize a kset for use
  *	@k:	kset 
lib/kobject_uevent.c +10 -6
index 82fc179..4122f38 100644
@@ -115,6 +115,16 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			return 0;
 		}
 
+	/* originating subsystem */
+	if (uevent_ops && uevent_ops->name)
+		subsystem = uevent_ops->name(kset, kobj);
+	else
+		subsystem = kobject_name(&kset->kobj);
+	if (!subsystem) {
+		pr_debug("unset subsytem caused the event to drop!\n");
+		return 0;
+	}
+
 	/* environment index */
 	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
 	if (!envp)
@@ -134,12 +144,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 		goto exit;
 	}
 
-	/* originating subsystem */
-	if (uevent_ops && uevent_ops->name)
-		subsystem = uevent_ops->name(kset, kobj);
-	else
-		subsystem = kobject_name(&kset->kobj);
-
 	/* event environemnt for helper process only */
 	envp[i++] = "HOME=/";
 	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
Signature · 1 line
1.5.1.2
#3 lore raw

PATCH 3/46 dev_printk and new-style class devices

From: Jean Delvare <[email protected]>

As the new-style class devices (as opposed to old-style struct class_device) are becoming more widely used, I noticed that the dev_printk-based functions are not working properly with these. New-style class devices have no driver nor bus, almost by definition, and as a result dev_driver_string(), which is used as the first parameter of dev_printk, resolves to an empty string. This causes entries like the following to show in my logs:

i2c-2: adapter [SMBus stub driver] registered

Notice the unaesthetical leading whitespace. In order to fix this problem, I suggest that we extend dev_driver_string to deal with new-style class devices:

---
 drivers/base/core.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/base/core.c +2 -1
index 658eae5..9ea12d9 100644
@@ -43,7 +43,8 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
 const char *dev_driver_string(struct device *dev)
 {
 	return dev->driver ? dev->driver->name :
-			(dev->bus ? dev->bus->name : "");
+			(dev->bus ? dev->bus->name :
+			(dev->class ? dev->class->name : ""));
 }
 EXPORT_SYMBOL(dev_driver_string);
 
Signature · 1 line
1.5.1.2

A message that is not in the archive (sent off-list or not yet received): [email protected]

#5 lore raw

PATCH 5/46 driver core: Use attribute groups in struct device_type

From: Dmitry Torokhov <[email protected]>

Driver core: use attribute groups in struct device_type

Attribute groups are more flexible than attribute lists (an attribute list can be represented by anonymous group) so switch struct device_type to use them.

Also rework attribute creation for devices so that they all cleaned up properly in case of errors.

---
 drivers/base/core.c    |  115 +++++++++++++++++++++++++++++-------------------
 include/linux/device.h |    2 +-
 2 files changed, 70 insertions(+), 47 deletions(-)
drivers/base/core.c +69 -46
index 9ea12d9..bb2cc37 100644
@@ -246,64 +246,95 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
-static int device_add_groups(struct device *dev)
+static int device_add_attributes(struct device *dev,
+				 struct device_attribute *attrs)
+{
+	int error = 0;
+	int i;
+
+	if (attrs) {
+		for (i = 0; attr_name(attrs[i]); i++) {
+			error = device_create_file(dev, &attrs[i]);
+			if (error)
+				break;
+		}
+		if (error)
+			while (--i >= 0)
+				device_remove_file(dev, &attrs[i]);
+	}
+	return error;
+}
+
+static void device_remove_attributes(struct device *dev,
+				     struct device_attribute *attrs)
 {
 	int i;
+
+	if (attrs)
+		for (i = 0; attr_name(attrs[i]); i++)
+			device_remove_file(dev, &attrs[i]);
+}
+
+static int device_add_groups(struct device *dev,
+			     struct attribute_group **groups)
+{
 	int error = 0;
+	int i;
 
-	if (dev->groups) {
-		for (i = 0; dev->groups[i]; i++) {
-			error = sysfs_create_group(&dev->kobj, dev->groups[i]);
+	if (groups) {
+		for (i = 0; groups[i]; i++) {
+			error = sysfs_create_group(&dev->kobj, groups[i]);
 			if (error) {
 				while (--i >= 0)
-					sysfs_remove_group(&dev->kobj, dev->groups[i]);
-				goto out;
+					sysfs_remove_group(&dev->kobj, groups[i]);
+				break;
 			}
 		}
 	}
-out:
 	return error;
 }
 
-static void device_remove_groups(struct device *dev)
+static void device_remove_groups(struct device *dev,
+				 struct attribute_group **groups)
 {
 	int i;
-	if (dev->groups) {
-		for (i = 0; dev->groups[i]; i++) {
-			sysfs_remove_group(&dev->kobj, dev->groups[i]);
-		}
-	}
+
+	if (groups)
+		for (i = 0; groups[i]; i++)
+			sysfs_remove_group(&dev->kobj, groups[i]);
 }
 
 static int device_add_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
 	struct device_type *type = dev->type;
-	int error = 0;
-	int i;
+	int error;
 
-	if (class && class->dev_attrs) {
-		for (i = 0; attr_name(class->dev_attrs[i]); i++) {
-			error = device_create_file(dev, &class->dev_attrs[i]);
-			if (error)
-				break;
-		}
+	if (class) {
+		error = device_add_attributes(dev, class->dev_attrs);
 		if (error)
-			while (--i >= 0)
-				device_remove_file(dev, &class->dev_attrs[i]);
+			return error;
 	}
 
-	if (type && type->attrs) {
-		for (i = 0; attr_name(type->attrs[i]); i++) {
-			error = device_create_file(dev, &type->attrs[i]);
-			if (error)
-				break;
-		}
+	if (type) {
+		error = device_add_groups(dev, type->groups);
 		if (error)
-			while (--i >= 0)
-				device_remove_file(dev, &type->attrs[i]);
+			goto err_remove_class_attrs;
 	}
 
+	error = device_add_groups(dev, dev->groups);
+	if (error)
+		goto err_remove_type_groups;
+
+	return 0;
+
+ err_remove_type_groups:
+	if (type)
+		device_remove_groups(dev, type->groups);
+ err_remove_class_attrs:
+	if (class)
+		device_remove_attributes(dev, class->dev_attrs);
+
 	return error;
 }
 
@@ -311,17 +342,14 @@ static void device_remove_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
 	struct device_type *type = dev->type;
-	int i;
 
-	if (class && class->dev_attrs) {
-		for (i = 0; attr_name(class->dev_attrs[i]); i++)
-			device_remove_file(dev, &class->dev_attrs[i]);
-	}
+	device_remove_groups(dev, dev->groups);
 
-	if (type && type->attrs) {
-		for (i = 0; attr_name(type->attrs[i]); i++)
-			device_remove_file(dev, &type->attrs[i]);
-	}
+	if (type)
+		device_remove_groups(dev, type->groups);
+
+	if (class)
+		device_remove_attributes(dev, class->dev_attrs);
 }
 
 
@@ -638,8 +666,6 @@ int device_add(struct device *dev)
 
 	if ((error = device_add_attrs(dev)))
 		goto AttrsError;
-	if ((error = device_add_groups(dev)))
-		goto GroupError;
 	if ((error = device_pm_add(dev)))
 		goto PMError;
 	if ((error = bus_add_device(dev)))
@@ -663,7 +689,7 @@ int device_add(struct device *dev)
 		up(&dev->class->sem);
 	}
  Done:
- 	kfree(class_name);
+	kfree(class_name);
 	put_device(dev);
 	return error;
  AttachError:
@@ -674,8 +700,6 @@ int device_add(struct device *dev)
 	if (dev->bus)
 		blocking_notifier_call_chain(&dev->bus->bus_notifier,
 					     BUS_NOTIFY_DEL_DEVICE, dev);
-	device_remove_groups(dev);
- GroupError:
 	device_remove_attrs(dev);
  AttrsError:
 	if (dev->devt_attr) {
@@ -838,7 +862,6 @@ void device_del(struct device * dev)
 		}
 	}
 	device_remove_file(dev, &dev->uevent_attr);
-	device_remove_groups(dev);
 	device_remove_attrs(dev);
 	bus_remove_device(dev);
 
include/linux/device.h +1 -1
index 9d54fe1..3b64fde 100644
@@ -332,7 +332,7 @@ extern struct class_device *class_device_create(struct class *cls,
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
 struct device_type {
-	struct device_attribute *attrs;
+	struct attribute_group **groups;
 	int (*uevent)(struct device *dev, char **envp, int num_envp,
 		      char *buffer, int buffer_size);
 	void (*release)(struct device *dev);
Signature · 1 line
1.5.1.2
#6 lore raw

PATCH 6/46 Driver core: add name to device_type

From: Kay Sievers <[email protected]>

If "name" of a device_type is specified, the uevent will contain the device_type name in the DEVTYPE variable. This helps userspace to distingiush between different types of devices, belonging to the same subsystem.

---
 drivers/base/core.c    |    5 +++++
 include/linux/device.h |   10 ++++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)
drivers/base/core.c +5 -0
index bb2cc37..bffb69e 100644
@@ -157,6 +157,11 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
 			       "MINOR=%u", MINOR(dev->devt));
 	}
 
+	if (dev->type && dev->type->name)
+		add_uevent_var(envp, num_envp, &i,
+			       buffer, buffer_size, &length,
+			       "DEVTYPE=%s", dev->type->name);
+
 	if (dev->driver)
 		add_uevent_var(envp, num_envp, &i,
 			       buffer, buffer_size, &length,
include/linux/device.h +10 -0
index 3b64fde..7f63d4d 100644
@@ -331,7 +331,17 @@ extern struct class_device *class_device_create(struct class *cls,
 					__attribute__((format(printf,5,6)));
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
+/*
+ * The type of device, "struct device" is embedded in. A class
+ * or bus can contain devices of different types
+ * like "partitions" and "disks", "mouse" and "event".
+ * This identifies the device type and carries type-specific
+ * information, equivalent to the kobj_type of a kobject.
+ * If "name" is specified, the uevent will contain it in
+ * the DEVTYPE variable.
+ */
 struct device_type {
+	const char *name;
 	struct attribute_group **groups;
 	int (*uevent)(struct device *dev, char **envp, int num_envp,
 		      char *buffer, int buffer_size);
Signature · 1 line
1.5.1.2
#7 lore raw

PATCH 7/46 kobject: kobject_shadow_add cleanup

From: Dmitriy Monakhov <[email protected]>

- correct function name in comments
- parrent assignment does metter only inside "if" block, so move it inside this block.

---
 lib/kobject.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
lib/kobject.c +2 -2
index f664551..bbbfab4 100644
@@ -157,7 +157,7 @@ static void unlink(struct kobject * kobj)
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
+ *	kobject_shadow_add - add an object to the hierarchy.
  *	@kobj:	object.
  *	@shadow_parent: sysfs directory to add to.
  */
@@ -190,8 +190,8 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 
 		list_add_tail(&kobj->entry,&kobj->kset->list);
 		spin_unlock(&kobj->kset->list_lock);
+		kobj->parent = parent;
 	}
-	kobj->parent = parent;
 
 	error = create_dir(kobj, shadow_parent);
 	if (error) {
Signature · 1 line
1.5.1.2
#8 lore raw

PATCH 8/46 driver core: per-subsystem multithreaded probing

From: Cornelia Huck <[email protected]>

Make multithreaded probing work per subsystem instead of per driver.

It doesn't make much sense to probe the same device for multiple drivers in parallel (after all, only one driver can bind to the device). Instead, create a probing thread for each device that probes the drivers one after another. Also make the decision to use multi-threaded probe per bus instead of per device and adapt the pci code.

---
 drivers/base/dd.c        |   62 +++++++++++++++++++++++-----------------------
 drivers/pci/pci-driver.c |    6 +---
 include/linux/device.h   |    3 +-
 include/linux/pci.h      |    2 -
 4 files changed, 33 insertions(+), 40 deletions(-)
drivers/base/dd.c +31 -31
index 6a48824..616b4bb 100644
@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev)
 	return ret;
 }
 
-struct stupid_thread_structure {
-	struct device_driver *drv;
-	struct device *dev;
-};
-
 static atomic_t probe_count = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
 
-static int really_probe(void *void_data)
+static int really_probe(struct device *dev, struct device_driver *drv)
 {
-	struct stupid_thread_structure *data = void_data;
-	struct device_driver *drv = data->drv;
-	struct device *dev = data->dev;
 	int ret = 0;
 
 	atomic_inc(&probe_count);
@@ -154,7 +146,6 @@ probe_failed:
 	 */
 	ret = 0;
 done:
-	kfree(data);
 	atomic_dec(&probe_count);
 	wake_up(&probe_waitqueue);
 	return ret;
@@ -186,16 +177,14 @@ int driver_probe_done(void)
  * format of the ID structures, nor what is to be considered a match and
  * what is not.
  *
- * This function returns 1 if a match is found, an error if one occurs
- * (that is not -ENODEV or -ENXIO), and 0 otherwise.
+ * This function returns 1 if a match is found, -ENODEV if the device is
+ * not registered, and 0 otherwise.
  *
  * This function must be called with @dev->sem held.  When called for a
  * USB interface, @dev->parent->sem must be held as well.
  */
 int driver_probe_device(struct device_driver * drv, struct device * dev)
 {
-	struct stupid_thread_structure *data;
-	struct task_struct *probe_task;
 	int ret = 0;
 
 	if (!device_is_registered(dev))
@@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
 	pr_debug("%s: Matched Device %s with Driver %s\n",
 		 drv->bus->name, dev->bus_id, drv->name);
 
-	data = kmalloc(sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-	data->drv = drv;
-	data->dev = dev;
-
-	if (drv->multithread_probe) {
-		probe_task = kthread_run(really_probe, data,
-					 "probe-%s", dev->bus_id);
-		if (IS_ERR(probe_task))
-			ret = really_probe(data);
-	} else
-		ret = really_probe(data);
+	ret = really_probe(dev, drv);
 
 done:
 	return ret;
@@ -230,30 +207,53 @@ static int __device_attach(struct device_driver * drv, void * data)
 	return driver_probe_device(drv, dev);
 }
 
+static int device_probe_drivers(void *data)
+{
+	struct device *dev = data;
+	int ret = 0;
+
+	if (dev->bus) {
+		down(&dev->sem);
+		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+		up(&dev->sem);
+	}
+	return ret;
+}
+
 /**
  *	device_attach - try to attach device to a driver.
  *	@dev:	device.
  *
  *	Walk the list of drivers that the bus has and call
  *	driver_probe_device() for each pair. If a compatible
- *	pair is found, break out and return.
+ *	pair is found, break out and return. If the bus specifies
+ *	multithreaded probing, walking the list of drivers is done
+ *	on a probing thread.
  *
  *	Returns 1 if the device was bound to a driver;
- *	0 if no matching device was found; error code otherwise.
+ *	0 if no matching device was found or multithreaded probing is done;
+ *	error code otherwise.
  *
  *	When called for a USB interface, @dev->parent->sem must be held.
  */
 int device_attach(struct device * dev)
 {
 	int ret = 0;
+	struct task_struct *probe_task = ERR_PTR(-ENOMEM);
 
 	down(&dev->sem);
 	if (dev->driver) {
 		ret = device_bind_driver(dev);
 		if (ret == 0)
 			ret = 1;
-	} else
-		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+	} else {
+		if (dev->bus->multithread_probe)
+			probe_task = kthread_run(device_probe_drivers, dev,
+						 "probe-%s", dev->bus_id);
+		if(IS_ERR(probe_task))
+			ret = bus_for_each_drv(dev->bus, NULL, dev,
+					       __device_attach);
+	}
 	up(&dev->sem);
 	return ret;
 }
drivers/pci/pci-driver.c +1 -5
index a3c1755..39e80fc 100644
@@ -434,11 +434,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 	drv->driver.mod_name = mod_name;
 	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
-	if (pci_multithread_probe)
-		drv->driver.multithread_probe = pci_multithread_probe;
-	else
-		drv->driver.multithread_probe = drv->multithread_probe;
-
 	spin_lock_init(&drv->dynids.lock);
 	INIT_LIST_HEAD(&drv->dynids.list);
 
@@ -574,6 +569,7 @@ struct bus_type pci_bus_type = {
 
 static int __init pci_driver_init(void)
 {
+	pci_bus_type.multithread_probe = pci_multithread_probe;
 	return bus_register(&pci_bus_type);
 }
 
include/linux/device.h +1 -2
index 7f63d4d..eb1fff0 100644
@@ -80,6 +80,7 @@ struct bus_type {
 	int (*resume)(struct device * dev);
 
 	unsigned int drivers_autoprobe:1;
+	unsigned int multithread_probe:1;
 };
 
 extern int __must_check bus_register(struct bus_type * bus);
@@ -139,8 +140,6 @@ struct device_driver {
 	void	(*shutdown)	(struct device * dev);
 	int	(*suspend)	(struct device * dev, pm_message_t state);
 	int	(*resume)	(struct device * dev);
-
-	unsigned int multithread_probe:1;
 };
 
 
include/linux/pci.h +0 -2
index 481ea06..a3ad762 100644
@@ -361,8 +361,6 @@ struct pci_driver {
 	struct pci_error_handlers *err_handler;
 	struct device_driver	driver;
 	struct pci_dynids dynids;
-
-	int multithread_probe;
 };
 
 #define	to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
Signature · 1 line
1.5.1.2
#9 lore raw

PATCH 9/46 powerpc: make it compile for multithread change

From: Andrew Morton <[email protected]>

arch/powerpc/kernel/of_platform.c:479: error: unknown field `multithread_probe' specified in initializer

Cc Paul Mackerras <[email protected]>
Cc Benjamin Herrenschmidt <[email protected]>
---
 arch/powerpc/kernel/of_platform.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)
arch/powerpc/kernel/of_platform.c +0 -3
index b734517..9e7a4d2 100644
@@ -475,9 +475,6 @@ static struct of_platform_driver of_pci_phb_driver = {
        .name = "of-pci",
        .match_table = of_pci_phb_ids,
        .probe = of_pci_phb_probe,
-       .driver = {
-	       .multithread_probe = 1,
-       },
 };
 
 static __init int of_pci_phb_init(void)
Signature · 1 line
1.5.1.2
#10 lore raw

PATCH 10/46 driver core: don't fail attaching the device if it cannot be bound

From: Cornelia Huck <[email protected]>

Don't fail bus_attach_device() if the device cannot be bound.

If dev->driver has been specified, reset it to NULL if device_bind_driver() failed and add the device as an unbound device. As a result, bus_attach_device() now cannot fail, and we can remove some checking from device_add().

Also remove an unneeded check in bus_rescan_devices_helper().

---
 drivers/base/base.h |    2 +-
 drivers/base/bus.c  |   11 ++++-------
 drivers/base/core.c |    5 +----
 drivers/base/dd.c   |    6 +++++-
 4 files changed, 11 insertions(+), 13 deletions(-)
drivers/base/base.h +1 -1
index de7e144..d597f26 100644
@@ -16,7 +16,7 @@ extern int cpu_dev_init(void);
 extern int attribute_container_init(void);
 
 extern int bus_add_device(struct device * dev);
-extern int bus_attach_device(struct device * dev);
+extern void bus_attach_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
 extern struct bus_type *get_bus(struct bus_type * bus);
 extern void put_bus(struct bus_type * bus);
drivers/base/bus.c +4 -7
index 9df2e6d..20b6dc8 100644
@@ -447,7 +447,7 @@ out_put:
  *	- Add device to bus's list of devices.
  *	- Try to attach to driver.
  */
-int bus_attach_device(struct device * dev)
+void bus_attach_device(struct device * dev)
 {
 	struct bus_type *bus = dev->bus;
 	int ret = 0;
@@ -456,13 +456,12 @@ int bus_attach_device(struct device * dev)
 		dev->is_registered = 1;
 		if (bus->drivers_autoprobe)
 			ret = device_attach(dev);
-		if (ret >= 0) {
+		WARN_ON(ret < 0);
+		if (ret >= 0)
 			klist_add_tail(&dev->knode_bus, &bus->klist_devices);
-			ret = 0;
-		} else
+		else
 			dev->is_registered = 0;
 	}
-	return ret;
 }
 
 /**
@@ -669,8 +668,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
 		ret = device_attach(dev);
 		if (dev->parent)
 			up(&dev->parent->sem);
-		if (ret > 0)
-			ret = 0;
 	}
 	return ret < 0 ? ret : 0;
 }
drivers/base/core.c +1 -4
index bffb69e..be6aeb4 100644
@@ -677,8 +677,7 @@ int device_add(struct device *dev)
 		goto BusError;
 	if (!dev->uevent_suppress)
 		kobject_uevent(&dev->kobj, KOBJ_ADD);
-	if ((error = bus_attach_device(dev)))
-		goto AttachError;
+	bus_attach_device(dev);
 	if (parent)
 		klist_add_tail(&dev->knode_parent, &parent->klist_children);
 
@@ -697,8 +696,6 @@ int device_add(struct device *dev)
 	kfree(class_name);
 	put_device(dev);
 	return error;
- AttachError:
-	bus_remove_device(dev);
  BusError:
 	device_pm_remove(dev);
  PMError:
drivers/base/dd.c +5 -1
index 616b4bb..18dba8e 100644
@@ -232,7 +232,7 @@ static int device_probe_drivers(void *data)
  *
  *	Returns 1 if the device was bound to a driver;
  *	0 if no matching device was found or multithreaded probing is done;
- *	error code otherwise.
+ *	-ENODEV if the device is not registered.
  *
  *	When called for a USB interface, @dev->parent->sem must be held.
  */
@@ -246,6 +246,10 @@ int device_attach(struct device * dev)
 		ret = device_bind_driver(dev);
 		if (ret == 0)
 			ret = 1;
+		else {
+			dev->driver = NULL;
+			ret = 0;
+		}
 	} else {
 		if (dev->bus->multithread_probe)
 			probe_task = kthread_run(device_probe_drivers, dev,
Signature · 1 line
1.5.1.2
#11 lore raw

PATCH 11/46 Driver core: remove unneeded completion from driver release path

The completion in the driver release path is due to ancient history in the _very_ early 2.5 days when we were not tracking the module reference count of attributes. It is not needed at all and can be removed.

Note, we now have an empty release function for the driver structure. This is due to the fact that drivers are statically allocated in the system at this point in time, something which I want to change in the future. But remember, drivers are really code, which is reference counted by the module, unlike devices, which are data and _must_ be reference counted properly in order to work correctly.

---
 drivers/base/bus.c     |   15 +++++++++++++--
 drivers/base/driver.c  |   20 --------------------
 include/linux/device.h |    1 -
 3 files changed, 13 insertions(+), 23 deletions(-)
drivers/base/bus.c +13 -2
index 20b6dc8..1a5a350 100644
@@ -63,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = {
 
 static void driver_release(struct kobject * kobj)
 {
-	struct device_driver * drv = to_driver(kobj);
-	complete(&drv->unloaded);
+	/*
+	 * Yes this is an empty release function, it is this way because struct
+	 * device is always a static object, not a dynamic one.  Yes, this is
+	 * not nice and bad, but remember, drivers are code, reference counted
+	 * by the module count, not a device, which is really data.  And yes,
+	 * in the future I do want to have all drivers be created dynamically,
+	 * and am working toward that goal, but it will take a bit longer...
+	 *
+	 * But do not let this example give _anyone_ the idea that they can
+	 * create a release function without any code in it at all, to do that
+	 * is almost always wrong.  If you have any questions about this,
+	 * please send an email to <[email protected]>
+	 */
 }
 
 static struct kobj_type ktype_driver = {
drivers/base/driver.c +0 -20
index 082bfde..eb11475 100644
@@ -149,10 +149,6 @@ void put_driver(struct device_driver * drv)
  *	We pass off most of the work to the bus_add_driver() call,
  *	since most of the things we have to do deal with the bus
  *	structures.
- *
- *	The one interesting aspect is that we setup @drv->unloaded
- *	as a completion that gets complete when the driver reference
- *	count reaches 0.
  */
 int driver_register(struct device_driver * drv)
 {
@@ -162,35 +158,19 @@ int driver_register(struct device_driver * drv)
 		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
 	}
 	klist_init(&drv->klist_devices, NULL, NULL);
-	init_completion(&drv->unloaded);
 	return bus_add_driver(drv);
 }
 
-
 /**
  *	driver_unregister - remove driver from system.
  *	@drv:	driver.
  *
  *	Again, we pass off most of the work to the bus-level call.
- *
- *	Though, once that is done, we wait until @drv->unloaded is completed.
- *	This will block until the driver refcount reaches 0, and it is
- *	released. Only modular drivers will call this function, and we
- *	have to guarantee that it won't complete, letting the driver
- *	unload until all references are gone.
  */
 
 void driver_unregister(struct device_driver * drv)
 {
 	bus_remove_driver(drv);
-	/*
-	 * If the driver is a module, we are probably in
-	 * the module unload path, and we want to wait
-	 * for everything to unload before we can actually
-	 * finish the unload.
-	 */
-	if (drv->owner)
-		wait_for_completion(&drv->unloaded);
 }
 
 /**
include/linux/device.h +0 -1
index eb1fff0..c9dc458 100644
@@ -126,7 +126,6 @@ struct device_driver {
 	const char		* name;
 	struct bus_type		* bus;
 
-	struct completion	unloaded;
 	struct kobject		kobj;
 	struct klist		klist_devices;
 	struct klist_node	knode_bus;
Signature · 1 line
1.5.1.2
#12 lore raw

PATCH 12/46 kref: fix CPU ordering with respect to krefs

From: Oliver Neukum <[email protected]>

some atomic operations are only atomic, not ordered. Thus a CPU is allowed to reorder memory references to an object to before the reference is obtained. This fixes it.

---
 lib/kref.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
lib/kref.c +2 -0
index 0d07cc3..a6dc3ec 100644
@@ -21,6 +21,7 @@
 void kref_init(struct kref *kref)
 {
 	atomic_set(&kref->refcount,1);
+	smp_mb();
 }
 
 /**
@@ -31,6 +32,7 @@ void kref_get(struct kref *kref)
 {
 	WARN_ON(!atomic_read(&kref->refcount));
 	atomic_inc(&kref->refcount);
+	smp_mb__after_atomic_inc();
 }
 
 /**
Signature · 1 line
1.5.1.2
#13 lore raw

PATCH 13/46 Driver core: notify userspace of network device renames

From: Jean Tourrilhes <[email protected]>

Provide rename event for when we rename network devices.

---
 lib/kobject.c        |   30 ++++++++++++++++++++++++++++++
 net/core/net-sysfs.c |   11 +++++++++++
 2 files changed, 41 insertions(+), 0 deletions(-)
lib/kobject.c +30 -0
index bbbfab4..db1d237 100644
@@ -311,13 +311,43 @@ EXPORT_SYMBOL(kobject_set_name);
 int kobject_rename(struct kobject * kobj, const char *new_name)
 {
 	int error = 0;
+	const char *devpath = NULL;
+	char *devpath_string = NULL;
+	char *envp[2];
 
 	kobj = kobject_get(kobj);
 	if (!kobj)
 		return -EINVAL;
 	if (!kobj->parent)
 		return -EINVAL;
+
+	devpath = kobject_get_path(kobj, GFP_KERNEL);
+	if (!devpath) {
+		error = -ENOMEM;
+		goto out;
+	}
+	devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
+	if (!devpath_string) {
+		error = -ENOMEM;
+		goto out;
+	}
+	sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
+	envp[0] = devpath_string;
+	envp[1] = NULL;
+	/* Note : if we want to send the new name alone, not the full path,
+	 * we could probably use kobject_name(kobj); */
+
 	error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+
+	/* This function is mostly/only used for network interface.
+	 * Some hotplug package track interfaces by their name and
+	 * therefore want to know when the name is changed by the user. */
+	if (!error)
+		kobject_uevent_env(kobj, KOBJ_MOVE, envp);
+
+out:
+	kfree(devpath_string);
+	kfree(devpath);
 	kobject_put(kobj);
 
 	return error;
net/core/net-sysfs.c +11 -0
index 221a64a..e441ec7 100644
@@ -424,6 +424,17 @@ static int netdev_uevent(struct device *d, char **envp,
 	if ((size <= 0) || (i >= num_envp))
 		return -ENOMEM;
 
+	/* pass ifindex to uevent.
+	 * ifindex is useful as it won't change (interface name may change)
+	 * and is what RtNetlink uses natively. */
+	envp[i++] = buf;
+	n = snprintf(buf, size, "IFINDEX=%d", dev->ifindex) + 1;
+	buf += n;
+	size -= n;
+
+	if ((size <= 0) || (i >= num_envp))
+		return -ENOMEM;
+
 	envp[i] = NULL;
 	return 0;
 }
Signature · 1 line
1.5.1.2
#14 lore raw

PATCH 14/46 Driver core: suppress uevents via filter

From: Cornelia Huck <[email protected]>

Suppress uevents for devices if uevent_suppress is set via dev_uevent_filter(). This makes the driver core suppress all device uevents, not just the add event in device_add().

---
 drivers/base/core.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
drivers/base/core.c +3 -2
index be6aeb4..c34a4d8 100644
@@ -120,6 +120,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
 
 	if (ktype == &ktype_device) {
 		struct device *dev = to_dev(kobj);
+		if (dev->uevent_suppress)
+			return 0;
 		if (dev->bus)
 			return 1;
 		if (dev->class)
@@ -675,8 +677,7 @@ int device_add(struct device *dev)
 		goto PMError;
 	if ((error = bus_add_device(dev)))
 		goto BusError;
-	if (!dev->uevent_suppress)
-		kobject_uevent(&dev->kobj, KOBJ_ADD);
+	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	bus_attach_device(dev);
 	if (parent)
 		klist_add_tail(&dev->knode_parent, &parent->klist_children);
Signature · 1 line
1.5.1.2
#15 lore raw

PATCH 15/46 Driver core: switch firmware_class to uevent_suppress.

From: Cornelia Huck <[email protected]>

Use uevent_suppress instead of returning an error code in firmware_uevent(). Get rid of the now unneeded FW_STATUS_READY and FW_STATUS_READY_NOHOTPLUG.

---
 drivers/base/firmware_class.c |   10 ++--------
 1 files changed, 2 insertions(+), 8 deletions(-)
drivers/base/firmware_class.c +2 -8
index c0a979a..97ab5bd 100644
@@ -31,8 +31,6 @@ enum {
 	FW_STATUS_LOADING,
 	FW_STATUS_DONE,
 	FW_STATUS_ABORT,
-	FW_STATUS_READY,
-	FW_STATUS_READY_NOHOTPLUG,
 };
 
 static int loading_timeout = 60;	/* In seconds */
@@ -96,9 +94,6 @@ static int firmware_uevent(struct device *dev, char **envp, int num_envp,
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
 	int i = 0, len = 0;
 
-	if (!test_bit(FW_STATUS_READY, &fw_priv->status))
-		return -ENODEV;
-
 	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
 			   "FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
@@ -333,6 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 	dev_set_drvdata(f_dev, fw_priv);
+	f_dev->uevent_suppress = 1;
 	retval = device_register(f_dev);
 	if (retval) {
 		printk(KERN_ERR "%s: device_register failed\n",
@@ -382,9 +378,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
 	}
 
 	if (uevent)
-                set_bit(FW_STATUS_READY, &fw_priv->status);
-        else
-                set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
+		f_dev->uevent_suppress = 0;
 	*dev_p = f_dev;
 	goto out;
 
Signature · 1 line
1.5.1.2
#16 lore raw

PATCH 16/46 uevent: use add_uevent_var() instead of open coding it

From: Eric Rannaud <[email protected]>

Make use of add_uevent_var() instead of (often incorrectly) open coding it.

---
 drivers/amba/bus.c           |   13 +++----
 drivers/ieee1394/nodemgr.c   |   14 +++----
 drivers/mmc/mmc_sysfs.c      |   27 ++++++--------
 drivers/s390/crypto/ap_bus.c |   28 +++++++--------
 net/core/net-sysfs.c         |   28 ++++++---------
 sound/aoa/soundbus/core.c    |   80 +++++++++++++++++-------------------------
 6 files changed, 79 insertions(+), 111 deletions(-)
drivers/amba/bus.c +6 -7
index fd54750..268e301 100644
@@ -47,14 +47,13 @@ static int amba_match(struct device *dev, struct device_driver *drv)
 static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
 {
 	struct amba_device *pcdev = to_amba_device(dev);
+	int retval = 0, i = 0, len = 0;
 
-	if (nr_env < 2)
-		return -ENOMEM;
-
-	snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid);
-	*envp++ = buf;
-	*envp++ = NULL;
-	return 0;
+	retval = add_uevent_var(envp, nr_env, &i,
+				buf, bufsz, &len,
+				"AMBA_ID=%08x", pcdev->periphid);
+	envp[i] = NULL;
+	return retval;
 }
 #else
 #define amba_uevent NULL
drivers/ieee1394/nodemgr.c +6 -8
index c5ace19..1644e6f 100644
@@ -1163,6 +1163,7 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
 	struct unit_directory *ud;
 	int i = 0;
 	int length = 0;
+	int retval = 0;
 	/* ieee1394:venNmoNspNverN */
 	char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
 
@@ -1176,14 +1177,11 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
 
 #define PUT_ENVP(fmt,val) 					\
 do {								\
-    	int printed;						\
-	envp[i++] = buffer;					\
-	printed = snprintf(buffer, buffer_size - length,	\
-			   fmt, val);				\
-	if ((buffer_size - (length+printed) <= 0) || (i >= num_envp))	\
-		return -ENOMEM;					\
-	length += printed+1;					\
-	buffer += printed+1;					\
+	retval = add_uevent_var(envp, num_envp, &i,		\
+				buffer, buffer_size, &length,	\
+				fmt, val);			\
+	if (retval)						\
+		return retval;					\
 } while (0)
 
 	PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
drivers/mmc/mmc_sysfs.c +11 -16
index d32698b..e0e82d8 100644
@@ -86,31 +86,26 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
 {
 	struct mmc_card *card = dev_to_mmc_card(dev);
 	char ccc[13];
-	int i = 0;
-
-#define add_env(fmt,val)						\
-	({								\
-		int len, ret = -ENOMEM;					\
-		if (i < num_envp) {					\
-			envp[i++] = buf;				\
-			len = snprintf(buf, buf_size, fmt, val) + 1;	\
-			buf_size -= len;				\
-			buf += len;					\
-			if (buf_size >= 0)				\
-				ret = 0;				\
-		}							\
-		ret;							\
-	})
+	int retval = 0, i = 0, length = 0;
+
+#define add_env(fmt,val) do {					\
+	retval = add_uevent_var(envp, num_envp, &i,		\
+				buf, buf_size, &length,		\
+				fmt, val);			\
+	if (retval)						\
+		return retval;					\
+} while (0);
 
 	for (i = 0; i < 12; i++)
 		ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
 	ccc[12] = '\0';
 
-	i = 0;
 	add_env("MMC_CCC=%s", ccc);
 	add_env("MMC_MANFID=%06x", card->cid.manfid);
 	add_env("MMC_NAME=%s", mmc_card_name(card));
 	add_env("MMC_OEMID=%04x", card->cid.oemid);
+#undef add_env
+	envp[i] = NULL;
 
 	return 0;
 }
drivers/s390/crypto/ap_bus.c +13 -15
index bf37cdf..5aac0ec 100644
@@ -423,27 +423,25 @@ static int ap_uevent (struct device *dev, char **envp, int num_envp,
 		       char *buffer, int buffer_size)
 {
 	struct ap_device *ap_dev = to_ap_dev(dev);
-	int length;
+	int retval = 0, length = 0, i = 0;
 
 	if (!ap_dev)
 		return -ENODEV;
 
 	/* Set up DEV_TYPE environment variable. */
-	envp[0] = buffer;
-	length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X",
-			   ap_dev->device_type);
-	if (buffer_size - length <= 0)
-		return -ENOMEM;
-	buffer += length;
-	buffer_size -= length;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"DEV_TYPE=%04X", ap_dev->device_type);
+	if (retval)
+		return retval;
+
 	/* Add MODALIAS= */
-	envp[1] = buffer;
-	length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X",
-			   ap_dev->device_type);
-	if (buffer_size - length <= 0)
-		return -ENOMEM;
-	envp[2] = NULL;
-	return 0;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"MODALIAS=ap:t%02X", ap_dev->device_type);
+
+	envp[i] = NULL;
+	return retval;
 }
 
 static struct bus_type ap_bus_type = {
net/core/net-sysfs.c +11 -17
index e441ec7..b21307b 100644
@@ -412,31 +412,25 @@ static int netdev_uevent(struct device *d, char **envp,
 			 int num_envp, char *buf, int size)
 {
 	struct net_device *dev = to_net_dev(d);
-	int i = 0;
-	int n;
+	int retval, len = 0, i = 0;
 
 	/* pass interface to uevent. */
-	envp[i++] = buf;
-	n = snprintf(buf, size, "INTERFACE=%s", dev->name) + 1;
-	buf += n;
-	size -= n;
-
-	if ((size <= 0) || (i >= num_envp))
-		return -ENOMEM;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buf, size, &len,
+				"INTERFACE=%s", dev->name);
+	if (retval)
+		goto exit;
 
 	/* pass ifindex to uevent.
 	 * ifindex is useful as it won't change (interface name may change)
 	 * and is what RtNetlink uses natively. */
-	envp[i++] = buf;
-	n = snprintf(buf, size, "IFINDEX=%d", dev->ifindex) + 1;
-	buf += n;
-	size -= n;
-
-	if ((size <= 0) || (i >= num_envp))
-		return -ENOMEM;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buf, size, &len,
+				"IFINDEX=%d", dev->ifindex);
 
+exit:
 	envp[i] = NULL;
-	return 0;
+	return retval;
 }
 #endif
 
sound/aoa/soundbus/core.c +32 -48

104 lines not on this page · raw message

Signature · 1 line
1.5.1.2
#17 lore raw

PATCH 17/46 Driver core: add suspend() and resume() to struct device_type

From: Dmitry Torokhov <[email protected]>

Driver core: add suspend() and resume() to struct device_type

In cases when there are devices of different types in the same class we can't use class's implementation of suspend and resume methods and we need to add them to struct device_type instead.

Also fix error handling in resume code (we should not try to call class's resume method iof bus's resume method for the device failed.

---
 drivers/base/power/resume.c  |   13 ++++++++++++-
 drivers/base/power/suspend.c |   12 ++++++++++++
 include/linux/device.h       |    2 ++
 3 files changed, 26 insertions(+), 1 deletions(-)
drivers/base/power/resume.c +12 -1
index 020be36..a2c6418 100644
@@ -26,7 +26,9 @@ int resume_device(struct device * dev)
 
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
+
 	down(&dev->sem);
+
 	if (dev->power.pm_parent
 			&& dev->power.pm_parent->power.power_state.event) {
 		dev_err(dev, "PM: resume from %d, parent %s still %d\n",
@@ -34,15 +36,24 @@ int resume_device(struct device * dev)
 			dev->power.pm_parent->bus_id,
 			dev->power.pm_parent->power.power_state.event);
 	}
+
 	if (dev->bus && dev->bus->resume) {
 		dev_dbg(dev,"resuming\n");
 		error = dev->bus->resume(dev);
 	}
-	if (dev->class && dev->class->resume) {
+
+	if (!error && dev->type && dev->type->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->type->resume(dev);
+	}
+
+	if (!error && dev->class && dev->class->resume) {
 		dev_dbg(dev,"class resume\n");
 		error = dev->class->resume(dev);
 	}
+
 	up(&dev->sem);
+
 	TRACE_RESUME(error);
 	return error;
 }
drivers/base/power/suspend.c +12 -0
index ece136b..42d2b86 100644
@@ -78,6 +78,18 @@ int suspend_device(struct device * dev, pm_message_t state)
 		suspend_report_result(dev->class->suspend, error);
 	}
 
+	if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) {
+		dev_dbg(dev, "%s%s\n",
+			suspend_verb(state.event),
+			((state.event == PM_EVENT_SUSPEND)
+					&& device_may_wakeup(dev))
+				? ", may wakeup"
+				: ""
+			);
+		error = dev->type->suspend(dev, state);
+		suspend_report_result(dev->type->suspend, error);
+	}
+
 	if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
 		dev_dbg(dev, "%s%s\n",
 			suspend_verb(state.event),
include/linux/device.h +2 -0
index c9dc458..af603a1 100644
@@ -344,6 +344,8 @@ struct device_type {
 	int (*uevent)(struct device *dev, char **envp, int num_envp,
 		      char *buffer, int buffer_size);
 	void (*release)(struct device *dev);
+	int (*suspend)(struct device * dev, pm_message_t state);
+	int (*resume)(struct device * dev);
 };
 
 /* interface for exporting device attributes */
Signature · 1 line
1.5.1.2
#18 lore raw

PATCH 18/46 Kobject: kobject_uevent.c: Collapse unnecessary loop nesting (top_kobj)

From: John Anthony Kazos Jr <[email protected]>

Collapses a do..while() loop within an if() to a simple while() loop for simplicity and readability.

---
 lib/kobject_uevent.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
lib/kobject_uevent.c +2 -4
index 4122f38..d9a3510 100644
@@ -95,10 +95,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
 	/* search the kset we belong to */
 	top_kobj = kobj;
-	if (!top_kobj->kset && top_kobj->parent) {
-		do {
-			top_kobj = top_kobj->parent;
-		} while (!top_kobj->kset && top_kobj->parent);
+	while (!top_kobj->kset && top_kobj->parent) {
+		top_kobj = top_kobj->parent;
 	}
 	if (!top_kobj->kset) {
 		pr_debug("kobject attempted to send uevent without kset!\n");
Signature · 1 line
1.5.1.2
#19 lore raw

PATCH 19/46 kobject: kobject_add() reference leak

From: Cornelia Huck <[email protected]>

We leak a reference if we attempt to add a kobject with no name.

---
 lib/kobject.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
lib/kobject.c +1 -0
index db1d237..eb251aa 100644
@@ -174,6 +174,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 	if (!*kobj->k_name) {
 		pr_debug("kobject attempted to be registered with no name!\n");
 		WARN_ON(1);
+		kobject_put(kobj);
 		return -EINVAL;
 	}
 	parent = kobject_get(kobj->parent);
Signature · 1 line
1.5.1.2
#20 lore raw

PATCH 20/46 Driver core: remove use of rwsem

This lock is never used by the rest of the driver core, so the fact that we are grabbing it here means it isn't correct...

---
 drivers/base/power/shutdown.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/base/power/shutdown.c +0 -2
index 3483ae4..58b6f77 100644
@@ -36,7 +36,6 @@ void device_shutdown(void)
 {
 	struct device * dev, *devn;
 
-	down_write(&devices_subsys.rwsem);
 	list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
 				kobj.entry) {
 		if (dev->bus && dev->bus->shutdown) {
@@ -47,7 +46,6 @@ void device_shutdown(void)
 			dev->driver->shutdown(dev);
 		}
 	}
-	up_write(&devices_subsys.rwsem);
 
 	sysdev_shutdown();
 }
Signature · 1 line
1.5.1.2
#21 lore raw

PATCH 21/46 SCSI: use the proper semaphore to protect the class lists

SCSI was using the incorrect lock to protect walking the list of all devices in the class. This patch fixes this.

---
 drivers/scsi/hosts.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/hosts.c +2 -2
index 38c3a29..bd8e7f3 100644
@@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
 	struct class_device *cdev;
 	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
 
-	down_read(&class->subsys.rwsem);
+	down(&class->sem);
 	list_for_each_entry(cdev, &class->children, node) {
 		p = class_to_shost(cdev);
 		if (p->host_no == hostnum) {
@@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
 			break;
 		}
 	}
-	up_read(&class->subsys.rwsem);
+	up(&class->sem);
 
 	return shost;
 }
Signature · 1 line
1.5.1.2
#22 lore raw

PATCH 22/46 USB: remove use of the bus rwsem, as it doesn't really protect anything.

The driver core stopped using the rwsem a long time ago, yet the USB core still grabbed the lock, thinking it protected something. This patch removes that useless use.

Cc Alan Stern <[email protected]>
Cc Oliver Neukum <[email protected]>
Cc David Brownell <[email protected]>
Cc linux-usb-devel <[email protected]>
---
 drivers/usb/core/devices.c |    2 --
 drivers/usb/core/devio.c   |   13 -------------
 drivers/usb/core/driver.c  |   12 ++++++------
 drivers/usb/core/message.c |    2 +-
 4 files changed, 7 insertions(+), 22 deletions(-)
drivers/usb/core/devices.c +0 -2
index aefc798..6753ca0 100644
@@ -246,7 +246,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
 
 	if (start > end)
 		return start;
-	down_read(&usb_bus_type.subsys.rwsem);
 	if (iface) {
 		driver_name = (iface->dev.driver
 				? iface->dev.driver->name
@@ -263,7 +262,6 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
 			 desc->bInterfaceSubClass,
 			 desc->bInterfaceProtocol,
 			 driver_name);
-	up_read(&usb_bus_type.subsys.rwsem);
 	return start;
 }
 
drivers/usb/core/devio.c +0 -13
index 36e7a84..fc3545d 100644
@@ -421,14 +421,11 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
 	if (test_bit(ifnum, &ps->ifclaimed))
 		return 0;
 
-	/* lock against other changes to driver bindings */
-	down_write(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(dev, ifnum);
 	if (!intf)
 		err = -ENOENT;
 	else
 		err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
-	up_write(&usb_bus_type.subsys.rwsem);
 	if (err == 0)
 		set_bit(ifnum, &ps->ifclaimed);
 	return err;
@@ -444,8 +441,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
 	if (ifnum >= 8*sizeof(ps->ifclaimed))
 		return err;
 	dev = ps->dev;
-	/* lock against other changes to driver bindings */
-	down_write(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(dev, ifnum);
 	if (!intf)
 		err = -ENOENT;
@@ -453,7 +448,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
 		usb_driver_release_interface(&usbfs_driver, intf);
 		err = 0;
 	}
-	up_write(&usb_bus_type.subsys.rwsem);
 	return err;
 }
 
@@ -813,7 +807,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 
 	if (copy_from_user(&gd, arg, sizeof(gd)))
 		return -EFAULT;
-	down_read(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(ps->dev, gd.interface);
 	if (!intf || !intf->dev.driver)
 		ret = -ENODATA;
@@ -822,7 +815,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 				sizeof(gd.driver));
 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
 	}
-	up_read(&usb_bus_type.subsys.rwsem);
 	return ret;
 }
 
@@ -1351,15 +1343,12 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
-
-		down_write(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver) {
 			driver = to_usb_driver(intf->dev.driver);
 			dev_dbg (&intf->dev, "disconnect by usbfs\n");
 			usb_driver_release_interface(driver, intf);
 		} else
 			retval = -ENODATA;
-		up_write(&usb_bus_type.subsys.rwsem);
 		break;
 
 	/* let kernel drivers try to (re)bind to the interface */
@@ -1371,7 +1360,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
 	/* talk directly to the interface's driver */
 	default:
-		down_read(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver)
 			driver = to_usb_driver(intf->dev.driver);
 		if (driver == NULL || driver->ioctl == NULL) {
@@ -1381,7 +1369,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 			if (retval == -ENOIOCTLCMD)
 				retval = -ENOTTY;
 		}
-		up_read(&usb_bus_type.subsys.rwsem);
 	}
 
 	/* cleanup and return */
drivers/usb/core/driver.c +6 -6
index 9e3e943..e6dd2b9 100644
@@ -287,9 +287,9 @@ static int usb_unbind_interface(struct device *dev)
  * way to bind to an interface is to return the private data from
  * the driver's probe() method.
  *
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock.  So driver probe() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
+ * Callers must own the device lock, so driver probe() entries don't need
+ * extra locking, but other call contexts may need to explicitly claim that
+ * lock.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
 				struct usb_interface *iface, void* priv)
@@ -330,9 +330,9 @@ EXPORT_SYMBOL(usb_driver_claim_interface);
  * also causes the driver disconnect() method to be called.
  *
  * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock.  So driver disconnect() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
+ * Callers must own the device lock, so driver disconnect() entries don't
+ * need extra locking, but other call contexts may need to explicitly claim
+ * that lock.
  */
 void usb_driver_release_interface(struct usb_driver *driver,
 					struct usb_interface *iface)
drivers/usb/core/message.c +1 -1
index 217a3d6..c359ccb 100644
@@ -1349,7 +1349,7 @@ static void release_interface(struct device *dev)
  *
  * This call is synchronous. The calling context must be able to sleep,
  * must own the device lock, and must not hold the driver model's USB
- * bus rwsem; usb device driver probe() methods cannot use this routine.
+ * bus mutex; usb device driver probe() methods cannot use this routine.
  *
  * Returns zero on success, or else the status code returned by the
  * underlying call that failed.  On successful completion, each interface
Signature · 1 line
1.5.1.2
#23 lore raw

PATCH 23/46 PNP: stop using the subsystem rwsem

The rwsem is not used to protect anything, so the use of it by the PNP subsystem isn't really useful, and it's doubtful if it really did anything or not. So I've removed it.

---
 drivers/pnp/card.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)
drivers/pnp/card.c +0 -6
index 91c047a..dd6384b 100644
@@ -311,7 +311,6 @@ done:
 	return NULL;
 
 found:
-	down_write(&dev->dev.bus->subsys.rwsem);
 	dev->card_link = clink;
 	dev->dev.driver = &drv->link.driver;
 	if (pnp_bus_type.probe(&dev->dev))
@@ -319,14 +318,11 @@ found:
 	if (device_bind_driver(&dev->dev))
 		goto err_out;
 
-	up_write(&dev->dev.bus->subsys.rwsem);
-
 	return dev;
 
 err_out:
 	dev->dev.driver = NULL;
 	dev->card_link = NULL;
-	up_write(&dev->dev.bus->subsys.rwsem);
 	return NULL;
 }
 
@@ -340,11 +336,9 @@ void pnp_release_card_device(struct pnp_dev * dev)
 	struct pnp_card_driver * drv = dev->card_link->driver;
 	if (!drv)
 		return;
-	down_write(&dev->dev.bus->subsys.rwsem);
 	drv->link.remove = &card_remove;
 	device_release_driver(&dev->dev);
 	drv->link.remove = &card_remove_first;
-	up_write(&dev->dev.bus->subsys.rwsem);
 }
 
 /*
Signature · 1 line
1.5.1.2
#24 lore raw

PATCH 24/46 Input: serio - do not touch bus's rwsem

From: Dmitry Torokhov <[email protected]>

The subsystem rwsem is not used by the driver core at all, so there is no point in trying to access it.

---
 drivers/input/serio/serio.c |   41 +++++++++++++++--------------------------
 1 files changed, 15 insertions(+), 26 deletions(-)
drivers/input/serio/serio.c +15 -26
index a15e531..5895202 100644
@@ -115,18 +115,18 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser
  * Basic serio -> driver core mappings
  */
 
-static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 {
 	int error;
 
-	down_write(&serio_bus.subsys.rwsem);
-
 	if (serio_match_port(drv->id_table, serio)) {
+
 		serio->dev.driver = &drv->driver;
 		if (serio_connect_driver(serio, drv)) {
 			serio->dev.driver = NULL;
-			goto out;
+			return -ENODEV;
 		}
+
 		error = device_bind_driver(&serio->dev);
 		if (error) {
 			printk(KERN_WARNING
@@ -136,31 +136,21 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 				drv->description, error);
 			serio_disconnect_driver(serio);
 			serio->dev.driver = NULL;
-			goto out;
+			return error;
 		}
 	}
- out:
-	up_write(&serio_bus.subsys.rwsem);
-}
-
-static void serio_release_driver(struct serio *serio)
-{
-	down_write(&serio_bus.subsys.rwsem);
-	device_release_driver(&serio->dev);
-	up_write(&serio_bus.subsys.rwsem);
+	return 0;
 }
 
 static void serio_find_driver(struct serio *serio)
 {
 	int error;
 
-	down_write(&serio_bus.subsys.rwsem);
 	error = device_attach(&serio->dev);
 	if (error < 0)
 		printk(KERN_WARNING
 			"serio: device_attach() failed for %s (%s), error: %d\n",
 			serio->phys, serio->name, error);
-	up_write(&serio_bus.subsys.rwsem);
 }
 
 
@@ -470,13 +460,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
 {
 	struct serio *serio = to_serio_port(dev);
 	struct device_driver *drv;
-	int retval;
+	int error;
 
-	retval = mutex_lock_interruptible(&serio_mutex);
-	if (retval)
-		return retval;
+	error = mutex_lock_interruptible(&serio_mutex);
+	if (error)
+		return error;
 
-	retval = count;
 	if (!strncmp(buf, "none", count)) {
 		serio_disconnect_port(serio);
 	} else if (!strncmp(buf, "reconnect", count)) {
@@ -486,15 +475,15 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
 		serio_find_driver(serio);
 	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
 		serio_disconnect_port(serio);
-		serio_bind_driver(serio, to_serio_driver(drv));
+		error = serio_bind_driver(serio, to_serio_driver(drv));
 		put_driver(drv);
 	} else {
-		retval = -EINVAL;
+		error = -EINVAL;
 	}
 
 	mutex_unlock(&serio_mutex);
 
-	return retval;
+	return error ? error : count;
 }
 
 static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
@@ -665,7 +654,7 @@ static void serio_disconnect_port(struct serio *serio)
 		do {
 			parent = s->parent;
 
-			serio_release_driver(s);
+			device_release_driver(&s->dev);
 			serio_destroy_port(s);
 		} while ((s = parent) != serio);
 	}
@@ -673,7 +662,7 @@ static void serio_disconnect_port(struct serio *serio)
 	/*
 	 * Ok, no children left, now disconnect this port
 	 */
-	serio_release_driver(serio);
+	device_release_driver(&serio->dev);
 }
 
 void serio_rescan(struct serio *serio)
Signature · 1 line
1.5.1.2
#25 lore raw

PATCH 25/46 Input: gameport - do not touch bus's rwsem

From: Dmitry Torokhov <[email protected]>

The subsystem rwsem is not used by the driver core at all, so there is no point in trying to access it.

---
 drivers/input/gameport/gameport.c |   39 ++++++++++++------------------------
 1 files changed, 13 insertions(+), 26 deletions(-)
drivers/input/gameport/gameport.c +13 -26
index a00fe47..bd686a2 100644
@@ -190,16 +190,14 @@ static void gameport_run_poll_handler(unsigned long d)
  * Basic gameport -> driver core mappings
  */
 
-static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
+static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
 {
 	int error;
 
-	down_write(&gameport_bus.subsys.rwsem);
-
 	gameport->dev.driver = &drv->driver;
 	if (drv->connect(gameport, drv)) {
 		gameport->dev.driver = NULL;
-		goto out;
+		return -ENODEV;
 	}
 
 	error = device_bind_driver(&gameport->dev);
@@ -211,31 +209,21 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv
 			drv->description, error);
 		drv->disconnect(gameport);
 		gameport->dev.driver = NULL;
-		goto out;
+		return error;
 	}
 
- out:
-	up_write(&gameport_bus.subsys.rwsem);
-}
-
-static void gameport_release_driver(struct gameport *gameport)
-{
-	down_write(&gameport_bus.subsys.rwsem);
-	device_release_driver(&gameport->dev);
-	up_write(&gameport_bus.subsys.rwsem);
+	return 0;
 }
 
 static void gameport_find_driver(struct gameport *gameport)
 {
 	int error;
 
-	down_write(&gameport_bus.subsys.rwsem);
 	error = device_attach(&gameport->dev);
 	if (error < 0)
 		printk(KERN_WARNING
 			"gameport: device_attach() failed for %s (%s), error: %d\n",
 			gameport->phys, gameport->name, error);
-	up_write(&gameport_bus.subsys.rwsem);
 }
 
 
@@ -483,13 +471,12 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
 {
 	struct gameport *gameport = to_gameport_port(dev);
 	struct device_driver *drv;
-	int retval;
+	int error;
 
-	retval = mutex_lock_interruptible(&gameport_mutex);
-	if (retval)
-		return retval;
+	error = mutex_lock_interruptible(&gameport_mutex);
+	if (error)
+		return error;
 
-	retval = count;
 	if (!strncmp(buf, "none", count)) {
 		gameport_disconnect_port(gameport);
 	} else if (!strncmp(buf, "reconnect", count)) {
@@ -499,15 +486,15 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
 		gameport_find_driver(gameport);
 	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
 		gameport_disconnect_port(gameport);
-		gameport_bind_driver(gameport, to_gameport_driver(drv));
+		error = gameport_bind_driver(gameport, to_gameport_driver(drv));
 		put_driver(drv);
 	} else {
-		retval = -EINVAL;
+		error = -EINVAL;
 	}
 
 	mutex_unlock(&gameport_mutex);
 
-	return retval;
+	return error ? error : count;
 }
 
 static struct device_attribute gameport_device_attrs[] = {
@@ -655,7 +642,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
 		do {
 			parent = s->parent;
 
-			gameport_release_driver(s);
+			device_release_driver(&s->dev);
 			gameport_destroy_port(s);
 		} while ((s = parent) != gameport);
 	}
@@ -663,7 +650,7 @@ static void gameport_disconnect_port(struct gameport *gameport)
 	/*
 	 * Ok, no children left, now disconnect this port
 	 */
-	gameport_release_driver(gameport);
+	device_release_driver(&gameport->dev);
 }
 
 void gameport_rescan(struct gameport *gameport)
Signature · 1 line
1.5.1.2
#26 lore raw

PATCH 26/46 IDE: remove rwsem use from ide-proc core

The subsystem rwsem is not used by the driver core at all, so the use of it in the ide-proc code of it doesn't make any sense. Perhaps a local lock might be needed, but I do not really think so.

Cc Bartlomiej Zolnierkiewicz <[email protected]>
Cc linux ide <[email protected]>
---
 drivers/ide/ide-proc.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)
drivers/ide/ide-proc.c +0 -4
index afb71c6..a9e0b30 100644
@@ -310,14 +310,12 @@ static int proc_ide_read_driver
 	ide_driver_t	*ide_drv;
 	int		len;
 
-	down_read(&dev->bus->subsys.rwsem);
 	if (dev->driver) {
 		ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
 		len = sprintf(page, "%s version %s\n",
 				dev->driver->name, ide_drv->version);
 	} else
 		len = sprintf(page, "ide-default version 0.9.newide\n");
-	up_read(&dev->bus->subsys.rwsem);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -327,7 +325,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
 	int ret = 1;
 	int err;
 
-	down_write(&dev->bus->subsys.rwsem);
 	device_release_driver(dev);
 	/* FIXME: device can still be in use by previous driver */
 	strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
@@ -345,7 +342,6 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
 	}
 	if (dev->driver && !strcmp(dev->driver->name, driver))
 		ret = 0;
-	up_write(&dev->bus->subsys.rwsem);
 
 	return ret;
 }
Signature · 1 line
1.5.1.2
#27 lore raw

PATCH 27/46 IEEE1394: remove rwsem use from ieee1394 core

The subsystem rwsem is not used by the driver core at all, so the use of it in the ieee1394 code doesn't make any sense. They might possibly want to use a local lock, but as most of these operations are already protected by a local lock, it really doesn't look like it would be needed.

Cc Ben Collins <[email protected]>
Cc Stefan Richter <[email protected]>
Cc linux1394-devel <[email protected]>
---
 drivers/ieee1394/nodemgr.c |    8 --------
 1 files changed, 0 insertions(+), 8 deletions(-)
drivers/ieee1394/nodemgr.c +0 -8
index 1644e6f..dbeba45 100644
@@ -370,9 +370,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute
 
 	if (state == 1) {
 		ud->ignore_driver = 1;
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		device_release_driver(dev);
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	} else if (state == 0)
 		ud->ignore_driver = 0;
 
@@ -1391,12 +1389,10 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
 		if (ud->ne != ne)
 			continue;
 
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver &&
 		    (!ud->device.driver->suspend ||
 		      ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
 			device_release_driver(&ud->device);
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 }
@@ -1416,10 +1412,8 @@ static void nodemgr_resume_ne(struct node_entry *ne)
 		if (ud->ne != ne)
 			continue;
 
-		down_read(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver && ud->device.driver->resume)
 			ud->device.driver->resume(&ud->device);
-		up_read(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 
@@ -1440,7 +1434,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
 		if (ud->ne != ne)
 			continue;
 
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver) {
 			pdrv = container_of(ud->device.driver,
 					    struct hpsb_protocol_driver,
@@ -1448,7 +1441,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
 			if (pdrv->update && pdrv->update(ud))
 				device_release_driver(&ud->device);
 		}
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 }
Signature · 1 line
1.5.1.2
#28 lore raw

PATCH 28/46 PHY: remove rwsem use from phy core

The subsystem rwsem is not used by the driver core at all, so the use of it in the phy code doesn't make any sense. They might possibly want to use a local lock, but I am unsure about that.

---
 drivers/net/phy/fixed.c      |    6 ------
 drivers/net/phy/phy_device.c |    9 +--------
 2 files changed, 1 insertions(+), 14 deletions(-)
drivers/net/phy/fixed.c +0 -6
index 66da91b..68c99b4 100644
@@ -276,21 +276,15 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
 	   artificially, we are binding the driver here by hand;
 	   it will be the same for all the fixed phys anyway.
 	 */
-	down_write(&phydev->dev.bus->subsys.rwsem);
-
 	phydev->dev.driver = &fixed_mdio_driver.driver;
 
 	err = phydev->dev.driver->probe(&phydev->dev);
 	if(err < 0) {
 		printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
-		up_write(&phydev->dev.bus->subsys.rwsem);
 		goto probe_fail;
 	}
 
 	err = device_bind_driver(&phydev->dev);
-
-	up_write(&phydev->dev.bus->subsys.rwsem);
-
 	if (err)
 		goto probe_fail;
 
drivers/net/phy/phy_device.c +1 -8
index 7d5b6d1..8f01952 100644
@@ -208,16 +208,12 @@ struct phy_device *phy_attach(struct net_device *dev,
 	 * exist, and we should use the genphy driver. */
 	if (NULL == d->driver) {
 		int err;
-		down_write(&d->bus->subsys.rwsem);
 		d->driver = &genphy_driver.driver;
 
 		err = d->driver->probe(d);
-
 		if (err >= 0)
 			err = device_bind_driver(d);
 
-		up_write(&d->bus->subsys.rwsem);
-
 		if (err)
 			return ERR_PTR(err);
 	}
@@ -258,11 +254,8 @@ void phy_detach(struct phy_device *phydev)
 	 * was using the generic driver), we unbind the device
 	 * from the generic driver so that there's a chance a
 	 * real driver could be loaded */
-	if (phydev->dev.driver == &genphy_driver.driver) {
-		down_write(&phydev->dev.bus->subsys.rwsem);
+	if (phydev->dev.driver == &genphy_driver.driver)
 		device_release_driver(&phydev->dev);
-		up_write(&phydev->dev.bus->subsys.rwsem);
-	}
 }
 EXPORT_SYMBOL(phy_detach);
 
Signature · 1 line
1.5.1.2
#29 lore raw

PATCH 29/46 qeth: Remove usage of subsys.rwsem

From: Cornelia Huck <[email protected]>

the current driver tree contains the removal of subsys.rwsem. Unfortunately, this breaks qeth. However, it should be no problem to fix the walking of the devices for /proc/qeth:

No need to take subsys.rwsem during walking the devices, driver_find_devices() should already suffice.

---
 drivers/s390/net/qeth_proc.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/s390/net/qeth_proc.c +0 -2
index 81f805c..89d56c8 100644
@@ -37,7 +37,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
 	struct device *dev = NULL;
 	loff_t nr = 0;
 
-	down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
 	if (*offset == 0)
 		return SEQ_START_TOKEN;
 	while (1) {
@@ -53,7 +52,6 @@ qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
 static void
 qeth_procfile_seq_stop(struct seq_file *s, void* it)
 {
-	up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
 }
 
 static void *
Signature · 1 line
1.5.1.2
#30 lore raw

PATCH 30/46 kobject core: remove rwsem from struct subsystem

It isn't used at all by the driver core anymore, and the few usages of it within the kernel have now all been fixed as most of them were using it incorrectly. So remove it.

Now the whole struct subsys can be removed from the system, but that's for a later patch...

---
 include/linux/kobject.h |    2 --
 lib/kobject.c           |    4 +---
 2 files changed, 1 insertions(+), 5 deletions(-)
include/linux/kobject.h +0 -2
index d37cd7f..a659a97 100644
@@ -22,7 +22,6 @@
 #include <linux/sysfs.h>
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
-#include <linux/rwsem.h>
 #include <linux/kref.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
@@ -177,7 +176,6 @@ extern struct kobject * kset_find_obj(struct kset *, const char *);
 
 struct subsystem {
 	struct kset		kset;
-	struct rw_semaphore	rwsem;
 };
 
 #define decl_subsys(_name,_type,_uevent_ops) \
lib/kobject.c +1 -3
index eb251aa..2882aff 100644
@@ -652,7 +652,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
 
 void subsystem_init(struct subsystem * s)
 {
-	init_rwsem(&s->rwsem);
 	kset_init(&s->kset);
 }
 
@@ -661,8 +660,7 @@ void subsystem_init(struct subsystem * s)
  *	@s:	the subsystem we're registering.
  *
  *	Once we register the subsystem, we want to make sure that 
- *	the kset points back to this subsystem for correct usage of 
- *	the rwsem. 
+ *	the kset points back to this subsystem.
  */
 
 int subsystem_register(struct subsystem * s)
Signature · 1 line
1.5.1.2
#31 lore raw

PATCH 31/46 Driver core: make uevent-environment available in uevent-file

From: Kay Sievers <[email protected]>

This allows sysfs to show the environment variables that are available if the uevent happens. This lets userspace not have to cache all of this information as the kernel already knows it.

---
 drivers/base/core.c |   50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 49 insertions(+), 1 deletions(-)
drivers/base/core.c +49 -1
index c34a4d8..72c6ee5 100644
@@ -246,6 +246,53 @@ static struct kset_uevent_ops device_uevent_ops = {
 	.uevent =	dev_uevent,
 };
 
+static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct kobject *top_kobj;
+	struct kset *kset;
+	char *envp[32];
+	char data[PAGE_SIZE];
+	char *pos;
+	int i;
+	size_t count = 0;
+	int retval;
+
+	/* search the kset, the device belongs to */
+	top_kobj = &dev->kobj;
+	if (!top_kobj->kset && top_kobj->parent) {
+		do {
+			top_kobj = top_kobj->parent;
+		} while (!top_kobj->kset && top_kobj->parent);
+	}
+	if (!top_kobj->kset)
+		goto out;
+	kset = top_kobj->kset;
+	if (!kset->uevent_ops || !kset->uevent_ops->uevent)
+		goto out;
+
+	/* respect filter */
+	if (kset->uevent_ops && kset->uevent_ops->filter)
+		if (!kset->uevent_ops->filter(kset, &dev->kobj))
+			goto out;
+
+	/* let the kset specific function add its keys */
+	pos = data;
+	retval = kset->uevent_ops->uevent(kset, &dev->kobj,
+					  envp, ARRAY_SIZE(envp),
+					  pos, PAGE_SIZE);
+	if (retval)
+		goto out;
+
+	/* copy keys to file */
+	for (i = 0; envp[i]; i++) {
+		pos = &buf[count];
+		count += sprintf(pos, "%s\n", envp[i]);
+	}
+out:
+	return count;
+}
+
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
@@ -621,10 +668,11 @@ int device_add(struct device *dev)
 					     BUS_NOTIFY_ADD_DEVICE, dev);
 
 	dev->uevent_attr.attr.name = "uevent";
-	dev->uevent_attr.attr.mode = S_IWUSR;
+	dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR;
 	if (dev->driver)
 		dev->uevent_attr.attr.owner = dev->driver->owner;
 	dev->uevent_attr.store = store_uevent;
+	dev->uevent_attr.show = show_uevent;
 	error = device_create_file(dev, &dev->uevent_attr);
 	if (error)
 		goto attrError;
Signature · 1 line
1.5.1.2
#32 lore raw

PATCH 32/46 Driver core: warn when userspace writes to the uevent file in a non-supported way

From: Kay Sievers <[email protected]>

In the future we will allow the uevent type to be written to the uevent file to trigger the different types of uevents. But for now, as we only support the ADD event, warn if userspace tries to write anything else to this file.

---
 drivers/base/core.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/base/core.c +3 -0
index 72c6ee5..f69305c 100644
@@ -296,6 +296,9 @@ out:
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
+	if (memcmp(buf, "add", 3) != 0)
+		dev_err(dev, "uevent: unsupported action-string; this will "
+			"be ignored in a future kernel version");
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	return count;
 }
Signature · 1 line
1.5.1.2
#33 lore raw

PATCH 33/46 kobject: Comment and warning fixes to kobject.c

From: Eric W. Biederman <[email protected]>

This dots some i's and crosses some t's after left over from when kobject_kset_add_dir was built from kobject_add_dir.

---
 lib/kobject.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)
lib/kobject.c +10 -3
index 2882aff..cecf2fb 100644
@@ -519,7 +519,7 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *	kobject__kset_add_dir - add sub directory of object.
+ *	kobject_kset_add_dir - add sub directory of object.
  *	@kset:		kset the directory is belongs to.
  *	@parent:	object in which a directory is created.
  *	@name:	directory name.
@@ -545,8 +545,8 @@ struct kobject *kobject_kset_add_dir(struct kset *kset,
 	kobject_set_name(k, name);
 	ret = kobject_register(k);
 	if (ret < 0) {
-		printk(KERN_WARNING "kobject_add_dir: "
-			"kobject_register error: %d\n", ret);
+		printk(KERN_WARNING "%s: kobject_register error: %d\n",
+			__func__, ret);
 		kobject_del(k);
 		return NULL;
 	}
@@ -554,6 +554,13 @@ struct kobject *kobject_kset_add_dir(struct kset *kset,
 	return k;
 }
 
+/**
+ *	kobject_add_dir - add sub directory of object.
+ *	@parent:	object in which a directory is created.
+ *	@name:	directory name.
+ *
+ *	Add a plain directory object as child of given object.
+ */
 struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
 {
 	return kobject_kset_add_dir(NULL, parent, name);
Signature · 1 line
1.5.1.2
#34 lore raw

PATCH 34/46 the overdue removal of the mount/umount uevents

From: Adrian Bunk <[email protected]>

This patch contains the overdue removal of the mount/umount uevents.

---
 Documentation/feature-removal-schedule.txt |    9 ---------
 fs/super.c                                 |   12 ------------
 include/linux/kobject.h                    |    8 +++-----
 lib/kobject_uevent.c                       |    4 ----
 4 files changed, 3 insertions(+), 30 deletions(-)
Documentation/feature-removal-schedule.txt +0 -9
index 6da6636..ec0b484 100644
@@ -134,15 +134,6 @@ Who:	Arjan van de Ven <[email protected]>
 
 ---------------------------
 
-What:	mount/umount uevents
-When:	February 2007
-Why:	These events are not correct, and do not properly let userspace know
-	when a file system has been mounted or unmounted.  Userspace should
-	poll the /proc/mounts file instead to detect this properly.
-Who:	Greg Kroah-Hartman <[email protected]>
-
----------------------------
-
 What:	USB driver API moves to EXPORT_SYMBOL_GPL
 When:	February 2008
 Files:	include/linux/usb.h, drivers/usb/core/driver.c
fs/super.c +0 -12
index 60b1e50..8341e4e 100644
@@ -725,16 +725,6 @@ static int test_bdev_super(struct super_block *s, void *data)
 	return (void *)s->s_bdev == data;
 }
 
-static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
-{
-	if (bdev->bd_disk) {
-		if (bdev->bd_part)
-			kobject_uevent(&bdev->bd_part->kobj, action);
-		else
-			kobject_uevent(&bdev->bd_disk->kobj, action);
-	}
-}
-
 int get_sb_bdev(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data,
 	int (*fill_super)(struct super_block *, void *, int),
@@ -782,7 +772,6 @@ int get_sb_bdev(struct file_system_type *fs_type,
 		}
 
 		s->s_flags |= MS_ACTIVE;
-		bdev_uevent(bdev, KOBJ_MOUNT);
 	}
 
 	return simple_set_mnt(mnt, s);
@@ -801,7 +790,6 @@ void kill_block_super(struct super_block *sb)
 {
 	struct block_device *bdev = sb->s_bdev;
 
-	bdev_uevent(bdev, KOBJ_UMOUNT);
 	generic_shutdown_super(sb);
 	sync_blockdev(bdev);
 	close_bdev_excl(bdev);
include/linux/kobject.h +3 -5
index a659a97..eb0e63e 100644
@@ -42,11 +42,9 @@ enum kobject_action {
 	KOBJ_ADD	= (__force kobject_action_t) 0x01,	/* exclusive to core */
 	KOBJ_REMOVE	= (__force kobject_action_t) 0x02,	/* exclusive to core */
 	KOBJ_CHANGE	= (__force kobject_action_t) 0x03,	/* device state change */
-	KOBJ_MOUNT	= (__force kobject_action_t) 0x04,	/* mount event for block devices (broken) */
-	KOBJ_UMOUNT	= (__force kobject_action_t) 0x05,	/* umount event for block devices (broken) */
-	KOBJ_OFFLINE	= (__force kobject_action_t) 0x06,	/* device offline */
-	KOBJ_ONLINE	= (__force kobject_action_t) 0x07,	/* device online */
-	KOBJ_MOVE	= (__force kobject_action_t) 0x08,	/* device move */
+	KOBJ_OFFLINE	= (__force kobject_action_t) 0x04,	/* device offline */
+	KOBJ_ONLINE	= (__force kobject_action_t) 0x05,	/* device online */
+	KOBJ_MOVE	= (__force kobject_action_t) 0x06,	/* device move */
 };
 
 struct kobject {
lib/kobject_uevent.c +0 -4
index d9a3510..12e311d 100644
@@ -42,10 +42,6 @@ static char *action_to_string(enum kobject_action action)
 		return "remove";
 	case KOBJ_CHANGE:
 		return "change";
-	case KOBJ_MOUNT:
-		return "mount";
-	case KOBJ_UMOUNT:
-		return "umount";
 	case KOBJ_OFFLINE:
 		return "offline";
 	case KOBJ_ONLINE:
Signature · 1 line
1.5.1.2
#35 lore raw

PATCH 35/46 debugfs: Add debugfs_create_u64()

From: Michael Ellerman <[email protected]>

I went to use this the other day, only to find it didn't exist.

It's a straight copy of the debugfs u32 code, then s/u32/u64/. A quick test shows it seems to be working.

---
 fs/debugfs/file.c       |   42 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/debugfs.h |    9 +++++++++
 2 files changed, 51 insertions(+), 0 deletions(-)
fs/debugfs/file.c +42 -0
index 682f928..2e124e0 100644
@@ -179,6 +179,48 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
 
+static void debugfs_u64_set(void *data, u64 val)
+{
+	*(u64 *)data = val;
+}
+
+static u64 debugfs_u64_get(void *data)
+{
+	return *(u64 *)data;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+
+/**
+ * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is %NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ *         from.
+ *
+ * This function creates a file in debugfs with the given name that
+ * contains the value of the variable @value.  If the @mode variable is so
+ * set, it can be read from, and written to.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, %NULL will be returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned.  It is not wise to check for this value, but rather, check for
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+				 struct dentry *parent, u64 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_u64);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_u64);
+
 static ssize_t read_file_bool(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
include/linux/debugfs.h +9 -0
index 9fa0983..5a9c495 100644
@@ -44,6 +44,8 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode,
 				  struct dentry *parent, u16 *value);
 struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+				  struct dentry *parent, u64 *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
 
@@ -104,6 +106,13 @@ static inline struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 	return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+						struct dentry *parent,
+						u64 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 						 struct dentry *parent,
 						 u32 *value)
Signature · 1 line
1.5.1.2
#36 lore raw

PATCH 36/46 driver core: bus_add_driver should return an error if no bus

As pointed out by Dave Jones.

---
 drivers/base/bus.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/base/bus.c +1 -1
index 1a5a350..1d76e23 100644
@@ -603,7 +603,7 @@ int bus_add_driver(struct device_driver *drv)
 	int error = 0;
 
 	if (!bus)
-		return 0;
+		return -EINVAL;
 
 	pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
 	error = kobject_set_name(&drv->kobj, "%s", drv->name);
Signature · 1 line
1.5.1.2
#37 lore raw

PATCH 37/46 Driver core: use mutex instead of semaphore in DMA pool handler

From: Matthias Kaehlcke <[email protected]>

the DMA pool handler uses a semaphore as mutex. use the mutex API instead of the (binary) semaphore

---
 drivers/base/dmapool.c |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)
drivers/base/dmapool.c +7 -7
index cd467c9..9406259 100644
@@ -37,7 +37,7 @@ struct dma_page {	/* cacheable header for 'allocation' bytes */
 
 #define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
 
-static DECLARE_MUTEX (pools_lock);
+static DEFINE_MUTEX (pools_lock);
 
 static ssize_t
 show_pools (struct device *dev, struct device_attribute *attr, char *buf)
@@ -55,7 +55,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf)
 	size -= temp;
 	next += temp;
 
-	down (&pools_lock);
+	mutex_lock(&pools_lock);
 	list_for_each_entry(pool, &dev->dma_pools, pools) {
 		unsigned pages = 0;
 		unsigned blocks = 0;
@@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf)
 		size -= temp;
 		next += temp;
 	}
-	up (&pools_lock);
+	mutex_unlock(&pools_lock);
 
 	return PAGE_SIZE - size;
 }
@@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev,
 	if (dev) {
 		int ret;
 
-		down (&pools_lock);
+		mutex_lock(&pools_lock);
 		if (list_empty (&dev->dma_pools))
 			ret = device_create_file (dev, &dev_attr_pools);
 		else
@@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev,
 			kfree(retval);
 			retval = NULL;
 		}
-		up (&pools_lock);
+		mutex_unlock(&pools_lock);
 	} else
 		INIT_LIST_HEAD (&retval->pools);
 
@@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page)
 void
 dma_pool_destroy (struct dma_pool *pool)
 {
-	down (&pools_lock);
+	mutex_lock(&pools_lock);
 	list_del (&pool->pools);
 	if (pool->dev && list_empty (&pool->dev->dma_pools))
 		device_remove_file (pool->dev, &dev_attr_pools);
-	up (&pools_lock);
+	mutex_unlock(&pools_lock);
 
 	while (!list_empty (&pool->page_list)) {
 		struct dma_page		*page;
Signature · 1 line
1.5.1.2
#38 lore raw

PATCH 38/46 sysfs: bin.c printk fix

From: Andrew Morton <[email protected]>

fs/sysfs/bin.c: In function 'read':
fs/sysfs/bin.c:77: warning: format '%zd' expects type 'signed size_t', but argument 4 has type 'int'

---
 fs/sysfs/bin.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
fs/sysfs/bin.c +1 -1
index d3b9f5f..8ea2a51 100644
@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
 	if (copy_to_user(userbuf, buffer, count))
 		return -EFAULT;
 
-	pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
+	pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
 
 	*off = offs + count;
 
Signature · 1 line
1.5.1.2
#39 lore raw

PATCH 39/46 s390: cio: Delay uevents for subchannels

From: Cornelia Huck <[email protected]>

We often have the situation that we register a subchannel and start device recognition, only to find out that the device is not usable after all, which triggers an unregister of the subchannel. This often happens on hundreds of subchannels on a LPAR, leading to a storm of events which aren't of any use. Therefore, use uevent_suppress to delay the KOBJ_ADD uevent for a subchannel until we know that its ccw_device is to be registered.

---
 drivers/s390/cio/device.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
drivers/s390/cio/device.c +6 -0
index 0335590..a23ff58 100644
@@ -871,6 +871,12 @@ io_subchannel_register(struct work_struct *work)
 		}
 		goto out;
 	}
+	/*
+	 * Now we know this subchannel will stay, we can throw
+	 * our delayed uevent.
+	 */
+	sch->dev.uevent_suppress = 0;
+	kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
 	/* make it known to the system */
 	ret = ccw_device_register(cdev);
 	if (ret) {
Signature · 1 line
1.5.1.2
#40 lore raw

PATCH 40/46 device_schedule_callback() needs a module reference

From: Alan Stern <[email protected]>

This patch (as896b) fixes an oversight in the design of device_schedule_callback(). It is necessary to acquire a reference to the module owning the callback routine, to prevent the module from being unloaded before the callback can run.

---
 drivers/base/core.c    |   16 ++++++++++------
 fs/sysfs/file.c        |   14 +++++++++++---
 include/linux/device.h |    8 ++++++--
 include/linux/sysfs.h  |    4 ++--
 4 files changed, 29 insertions(+), 13 deletions(-)
drivers/base/core.c +10 -6
index f69305c..8aa090d 100644
@@ -480,9 +480,10 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
 EXPORT_SYMBOL_GPL(device_remove_bin_file);
 
 /**
- * device_schedule_callback - helper to schedule a callback for a device
+ * device_schedule_callback_owner - helper to schedule a callback for a device
  * @dev: device.
  * @func: callback function to invoke later.
+ * @owner: module owning the callback routine
  *
  * Attribute methods must not unregister themselves or their parent device
  * (which would amount to the same thing).  Attempts to do so will deadlock,
@@ -493,20 +494,23 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file);
  * argument in the workqueue's process context.  @dev will be pinned until
  * @func returns.
  *
+ * This routine is usually called via the inline device_schedule_callback(),
+ * which automatically sets @owner to THIS_MODULE.
+ *
  * Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated.
+ * be allocated, -ENODEV if a reference to @owner isn't available.
  *
  * NOTE: This routine won't work if CONFIG_SYSFS isn't set!  It uses an
  * underlying sysfs routine (since it is intended for use by attribute
  * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
  */
-int device_schedule_callback(struct device *dev,
-		void (*func)(struct device *))
+int device_schedule_callback_owner(struct device *dev,
+		void (*func)(struct device *), struct module *owner)
 {
 	return sysfs_schedule_callback(&dev->kobj,
-			(void (*)(void *)) func, dev);
+			(void (*)(void *)) func, dev, owner);
 }
-EXPORT_SYMBOL_GPL(device_schedule_callback);
+EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
 
 static void klist_children_get(struct klist_node *n)
 {
fs/sysfs/file.c +11 -3
index fc46333..db0413a 100644
@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct {
 	struct kobject 		*kobj;
 	void			(*func)(void *);
 	void			*data;
+	struct module		*owner;
 	struct work_struct	work;
 };
 
@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
 
 	(ss->func)(ss->data);
 	kobject_put(ss->kobj);
+	module_put(ss->owner);
 	kfree(ss);
 }
 
@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
  * @kobj: object we're acting for.
  * @func: callback function to invoke later.
  * @data: argument to pass to @func.
+ * @owner: module owning the callback code
  *
  * sysfs attribute methods must not unregister themselves or their parent
  * kobject (which would amount to the same thing).  Attempts to do so will
@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
  * until @func returns.
  *
  * Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated.
+ * be allocated, -ENODEV if a reference to @owner isn't available.
  */
 int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
-		void *data)
+		void *data, struct module *owner)
 {
 	struct sysfs_schedule_callback_struct *ss;
 
+	if (!try_module_get(owner))
+		return -ENODEV;
 	ss = kmalloc(sizeof(*ss), GFP_KERNEL);
-	if (!ss)
+	if (!ss) {
+		module_put(owner);
 		return -ENOMEM;
+	}
 	kobject_get(kobj);
 	ss->kobj = kobj;
 	ss->func = func;
 	ss->data = data;
+	ss->owner = owner;
 	INIT_WORK(&ss->work, sysfs_schedule_callback_work);
 	schedule_work(&ss->work);
 	return 0;
include/linux/device.h +6 -2
index af603a1..8511d14 100644
@@ -367,8 +367,12 @@ extern int __must_check device_create_bin_file(struct device *dev,
 					       struct bin_attribute *attr);
 extern void device_remove_bin_file(struct device *dev,
 				   struct bin_attribute *attr);
-extern int device_schedule_callback(struct device *dev,
-		void (*func)(struct device *));
+extern int device_schedule_callback_owner(struct device *dev,
+		void (*func)(struct device *), struct module *owner);
+
+/* This is a macro to avoid include problems with THIS_MODULE */
+#define device_schedule_callback(dev, func)			\
+	device_schedule_callback_owner(dev, func, THIS_MODULE)
 
 /* device resource management */
 typedef void (*dr_release_t)(struct device *dev, void *res);
include/linux/sysfs.h +2 -2
index fea9a6b..7d5d1ec 100644
@@ -80,7 +80,7 @@ struct sysfs_ops {
 #ifdef CONFIG_SYSFS
 
 extern int sysfs_schedule_callback(struct kobject *kobj,
-		void (*func)(void *), void *data);
+		void (*func)(void *), void *data, struct module *owner);
 
 extern int __must_check
 sysfs_create_dir(struct kobject *, struct dentry *);
@@ -137,7 +137,7 @@ extern int __must_check sysfs_init(void);
 #else /* CONFIG_SYSFS */
 
 static inline int sysfs_schedule_callback(struct kobject *kobj,
-		void (*func)(void *), void *data)
+		void (*func)(void *), void *data, struct module *owner)
 {
 	return -ENOSYS;
 }
Signature · 1 line
1.5.1.2
#41 lore raw

PATCH 41/46 security: prevent permission checking of file removal via sysfs_remove_group()

From: James Morris <[email protected]>

Prevent permission checking from being performed when the kernel wants to unconditionally remove a sysfs group, by introducing an kernel-only variant of lookup_one_len(), lookup_one_len_kern().

Additionally, as sysfs_remove_group() does not check the return value of the lookup before using it, a BUG_ON has been added to pinpoint the cause of any problems potentially caused by this (and as a form of annotation).

Cc Nagendra Singh Tomar <[email protected]>
Cc Tejun Heo <[email protected]>
Cc Stephen Smalley <[email protected]>
Cc Eric Paris <[email protected]>
---
 fs/namei.c            |   72 +++++++++++++++++++++++++++++++++++-------------
 fs/sysfs/group.c      |    6 +++-
 include/linux/namei.h |    1 +
 3 files changed, 57 insertions(+), 22 deletions(-)
fs/namei.c +52 -20
index ee60cc4..880052c 100644
@@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
 	return err;
 }
 
-/*
- * Restricted form of lookup. Doesn't follow links, single-component only,
- * needs parent already locked. Doesn't follow mounts.
- * SMP-safe.
- */
-static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
+static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
 {
-	struct dentry * dentry;
+	struct dentry *dentry;
 	struct inode *inode;
 	int err;
 
 	inode = base->d_inode;
-	err = permission(inode, MAY_EXEC, nd);
-	dentry = ERR_PTR(err);
-	if (err)
-		goto out;
 
 	/*
 	 * See if the low-level filesystem might want
@@ -1287,35 +1278,76 @@ out:
 	return dentry;
 }
 
+/*
+ * Restricted form of lookup. Doesn't follow links, single-component only,
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+	int err;
+
+	inode = base->d_inode;
+
+	err = permission(inode, MAY_EXEC, nd);
+	dentry = ERR_PTR(err);
+	if (err)
+		goto out;
+
+	dentry = __lookup_hash_kern(name, base, nd);
+out:
+	return dentry;
+}
+
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
 	return __lookup_hash(&nd->last, nd->dentry, nd);
 }
 
 /* SMP-safe */
-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
 {
 	unsigned long hash;
-	struct qstr this;
 	unsigned int c;
 
-	this.name = name;
-	this.len = len;
+	this->name = name;
+	this->len = len;
 	if (!len)
-		goto access;
+		return -EACCES;
 
 	hash = init_name_hash();
 	while (len--) {
 		c = *(const unsigned char *)name++;
 		if (c == '/' || c == '\0')
-			goto access;
+			return -EACCES;
 		hash = partial_name_hash(c, hash);
 	}
-	this.hash = end_name_hash(hash);
+	this->hash = end_name_hash(hash);
+	return 0;
+}
 
+struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+{
+	int err;
+	struct qstr this;
+
+	err = __lookup_one_len(name, &this, base, len);
+	if (err)
+		return ERR_PTR(err);
 	return __lookup_hash(&this, base, NULL);
-access:
-	return ERR_PTR(-EACCES);
+}
+
+struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len)
+{
+	int err;
+	struct qstr this;
+
+	err = __lookup_one_len(name, &this, base, len);
+	if (err)
+		return ERR_PTR(err);
+	return __lookup_hash_kern(&this, base, NULL);
 }
 
 /*
fs/sysfs/group.c +4 -2
index b20951c..52eed2a 100644
@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj,
 {
 	struct dentry * dir;
 
-	if (grp->name)
-		dir = lookup_one_len(grp->name, kobj->dentry,
+	if (grp->name) {
+		dir = lookup_one_len_kern(grp->name, kobj->dentry,
 				strlen(grp->name));
+		BUG_ON(IS_ERR(dir));
+	}
 	else
 		dir = dget(kobj->dentry);
 
include/linux/namei.h +1 -0
index d39a5a6..b7dd249 100644
@@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
Signature · 1 line
1.5.1.2
#42 lore raw

PATCH 42/46 define platform wakeup hook, use in pci_enable_wake()

From: David Brownell <[email protected]>

This defines a platform hook to enable/disable a device as a wakeup event source. It's initially for use with ACPI, but more generally it could be used whenever enable_irq_wake()/disable_irq_wake() don't suffice.

The hook is called -- if available -- inside pci_enable_wake(); and the semantics of that call are enhanced so that support for PCI PME# is no longer needed. It can now work for devices with "legacy PCI PM", when platform support allows it. (That support would use some board-specific signal for for the same purpose as PME#.)

---
 drivers/base/power/main.c |    3 ++
 drivers/pci/pci.c         |   58 +++++++++++++++++++++++++++++++-------------
 include/linux/pm.h        |   19 ++++++++++++++
 3 files changed, 63 insertions(+), 17 deletions(-)
drivers/base/power/main.c +3 -0
index bbbb973..05dc876 100644
@@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq);
 DECLARE_MUTEX(dpm_sem);
 DECLARE_MUTEX(dpm_list_sem);
 
+int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
+
 /**
  *	device_pm_set_parent - Specify power dependency.
  *	@dev:		Device who needs power.
drivers/pci/pci.c +41 -17

93 lines not on this page · raw message

include/linux/pm.h +19 -0
index 21db05a..b0ab623 100644
@@ -273,6 +273,20 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
 		__suspend_report_result(__FUNCTION__, fn, ret);		\
 	} while (0)
 
+/*
+ * Platform hook to activate device wakeup capability, if that's not already
+ * handled by enable_irq_wake() etc.
+ * Returns zero on success, else negative errno
+ */
+extern int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
+static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
+{
+	if (platform_enable_wakeup)
+		return (*platform_enable_wakeup)(dev, is_on);
+	return 0;
+}
+
 #else /* !CONFIG_PM */
 
 static inline int device_suspend(pm_message_t state)
@@ -294,6 +308,11 @@ static inline void dpm_runtime_resume(struct device * dev)
 
 #define suspend_report_result(fn, ret) do { } while (0)
 
+static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
+{
+	return -EIO;
+}
+
 #endif
 
 /* changes to device_may_wakeup take effect on the next pm state change.
Signature · 1 line
1.5.1.2
#43 lore raw

PATCH 43/46 s2ram: add arch irq disable/enable hooks

From: Johannes Berg <[email protected]>

After some more discussion this patch replaces it:

From: Johannes Berg <[email protected]>
Subject: suspend: add arch irq disable/enable hooks

For powermac, we need to do some things between suspending devices and device_power_off, for example setting the decrementer. This patch allows architectures to define arch_s2ram_{en,dis}able_irqs in their asm/suspend.h to have control over this step.

---
 include/linux/pm.h  |   18 ++++++++++++++++++
 kernel/power/main.c |   18 +++++++++++++++---
 2 files changed, 33 insertions(+), 3 deletions(-)
include/linux/pm.h +18 -0
index b0ab623..9bd86db 100644
@@ -166,6 +166,24 @@ extern struct pm_ops *pm_ops;
 extern int pm_suspend(suspend_state_t state);
 
 
+/**
+ * arch_suspend_disable_irqs - disable IRQs for suspend
+ *
+ * Disables IRQs (in the default case). This is a weak symbol in the common
+ * code and thus allows architectures to override it if more needs to be
+ * done. Not called for suspend to disk.
+ */
+extern void arch_suspend_disable_irqs(void);
+
+/**
+ * arch_suspend_enable_irqs - enable IRQs after suspend
+ *
+ * Enables IRQs (in the default case). This is a weak symbol in the common
+ * code and thus allows architectures to override it if more needs to be
+ * done. Not called for suspend to disk.
+ */
+extern void arch_suspend_enable_irqs(void);
+
 /*
  * Device power management
  */
kernel/power/main.c +15 -3
index a064dfd..3062e94 100644
@@ -111,13 +111,24 @@ static int suspend_prepare(suspend_state_t state)
 	return error;
 }
 
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+	local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+	local_irq_enable();
+}
 
 int suspend_enter(suspend_state_t state)
 {
 	int error = 0;
-	unsigned long flags;
 
-	local_irq_save(flags);
+	arch_suspend_disable_irqs();
+	BUG_ON(!irqs_disabled());
 
 	if ((error = device_power_down(PMSG_SUSPEND))) {
 		printk(KERN_ERR "Some devices failed to power down\n");
@@ -126,7 +137,8 @@ int suspend_enter(suspend_state_t state)
 	error = pm_ops->enter(state);
 	device_power_up();
  Done:
-	local_irq_restore(flags);
+	arch_suspend_enable_irqs();
+	BUG_ON(irqs_disabled());
 	return error;
 }
 
Signature · 1 line
1.5.1.2
#44 lore raw

PATCH 44/46 mod_sysfs_setup() doesn't return errno when kobject_add_dir() failure occurs

From: Akinobu Mita <[email protected]>

mod_sysfs_setup() doesn't return an errno when kobject_add_dir() for module "holders" directory fails. So caller of mod_sysfs_setup() will keep going and get oops.

---
 kernel/module.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
kernel/module.c +3 -1
index dcdb32b..9da5af6 100644
@@ -1148,8 +1148,10 @@ int mod_sysfs_setup(struct module *mod,
 		goto out;
 
 	mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
-	if (!mod->holders_dir)
+	if (!mod->holders_dir) {
+		err = -ENOMEM;
 		goto out_unreg;
+	}
 
 	err = module_param_sysfs_setup(mod, kparam, num_params);
 	if (err)
Signature · 1 line
1.5.1.2
#45 lore raw

PATCH 45/46 drivers/base/attribute_container.c: use mutex instead of binary semaphore

From: Matthias Kaehlcke <[email protected]>

use mutex instead of binary semaphore in
drivers/base/attribute_container.c

---
 drivers/base/attribute_container.c |   26 +++++++++++++-------------
 1 files changed, 13 insertions(+), 13 deletions(-)
drivers/base/attribute_container.c +13 -13
index 2222073..1ec0654 100644
@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
 
 static struct list_head attribute_container_list;
 
-static DECLARE_MUTEX(attribute_container_mutex);
+static DEFINE_MUTEX(attribute_container_mutex);
 
 /**
  * attribute_container_register - register an attribute container
@@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont)
 	klist_init(&cont->containers,internal_container_klist_get,
 		   internal_container_klist_put);
 		
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_add_tail(&cont->node, &attribute_container_list);
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 
 	return 0;
 }
@@ -94,7 +94,7 @@ int
 attribute_container_unregister(struct attribute_container *cont)
 {
 	int retval = -EBUSY;
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	spin_lock(&cont->containers.k_lock);
 	if (!list_empty(&cont->containers.k_list))
 		goto out;
@@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont)
 	list_del(&cont->node);
  out:
 	spin_unlock(&cont->containers.k_lock);
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 	return retval;
 		
 }
@@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev,
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 
@@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev,
 			attribute_container_add_class_device(&ic->classdev);
 		klist_add_tail(&ic->node, &cont->containers);
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /* FIXME: can't break out of this unless klist_iter_exit is also
@@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev,
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 		struct klist_iter iter;
@@ -234,7 +234,7 @@ attribute_container_remove_device(struct device *dev,
 			}
 		}
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
@@ -255,7 +255,7 @@ attribute_container_device_trigger(struct device *dev,
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 		struct klist_iter iter;
@@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev,
 				fn(cont, dev, &ic->classdev);
 		}
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
@@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev,
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		if (cont->match(cont, dev))
 			fn(cont, dev);
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
Signature · 1 line
1.5.1.2
#46 lore raw

PATCH 46/46 dev_dbg: check dev_dbg() arguments

From: Dan Williams <[email protected]>

Duplicate what Zach Brown did for pr_debug in commit 8b2a1fd1b394c60eaa2587716102dd5e9b4e5990

---
 drivers/usb/core/hub.c      |    4 +---
 drivers/usb/host/ohci-hcd.c |    6 ------
 include/linux/device.h      |    6 +++++-
 3 files changed, 6 insertions(+), 10 deletions(-)
drivers/usb/core/hub.c +1 -3
index b89a98e..7a60285 100644
@@ -119,8 +119,7 @@ MODULE_PARM_DESC(use_both_schemes,
 		"first one fails");
 
 
-#ifdef	DEBUG
-static inline char *portspeed (int portstatus)
+static inline char *portspeed(int portstatus)
 {
 	if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
     		return "480 Mb/s";
@@ -129,7 +128,6 @@ static inline char *portspeed (int portstatus)
 	else
 		return "12 Mb/s";
 }
-#endif
 
 /* Note that hdev or one of its children must be locked! */
 static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev)
drivers/usb/host/ohci-hcd.c +0 -6
index f0d29ed..e8bbe8b 100644
@@ -486,9 +486,6 @@ static int ohci_run (struct ohci_hcd *ohci)
 	 * or if bus glue did the same (e.g. for PCI add-in cards with
 	 * PCI PM support).
 	 */
-	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
-			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-			ohci_readl (ohci, &ohci->regs->control));
 	if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
 			&& !device_may_wakeup(hcd->self.controller))
 		device_init_wakeup(hcd->self.controller, 1);
@@ -744,9 +741,6 @@ static void ohci_stop (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
-	ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
-		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-		hcd->state);
 	ohci_dump (ohci, 1);
 
 	flush_scheduled_work();
include/linux/device.h +5 -1
index 8511d14..a0cd2ce 100644
@@ -571,7 +571,11 @@ extern const char *dev_driver_string(struct device *dev);
 #define dev_dbg(dev, format, arg...)		\
 	dev_printk(KERN_DEBUG , dev , format , ## arg)
 #else
-#define dev_dbg(dev, format, arg...) do { (void)(dev); } while (0)
+static inline int __attribute__ ((format (printf, 2, 3)))
+dev_dbg(struct device * dev, const char * fmt, ...)
+{
+	return 0;
+}
 #endif
 
 #define dev_err(dev, format, arg...)		\
Signature · 1 line
1.5.1.2
Acked-by on v1 28/46
#47 lore raw

Re: [PATCH 28/46] PHY: remove rwsem use from phy core

In reply to Greg Kroah-Hartman
Quoted 6 lines · Greg Kroah-Hartman

The subsystem rwsem is not used by the driver core at all, so the use of it in the phy code doesn't make any sense. They might possibly want to use a local lock, but I am unsure about that.

Quoted 1 line

---

I think I copied that code from elsewhere without truly understanding it.

*bows head in shame*

As such, I have no objection to this patch unless someone says it breaks their board. :)

Quoted 74 lines
 drivers/net/phy/fixed.c      |    6 ------
 drivers/net/phy/phy_device.c |    9 +--------
 2 files changed, 1 insertions(+), 14 deletions(-)
drivers/net/phy/fixed.c +0 -6
index 66da91b..68c99b4 100644
@@ -276,21 +276,15 @@ static int fixed_mdio_register_device(int  
 number, int speed, int duplex)
 	   artificially, we are binding the driver here by hand;
 	   it will be the same for all the fixed phys anyway.
 	 */
-	down_write(&phydev->dev.bus->subsys.rwsem);
-
 	phydev->dev.driver = &fixed_mdio_driver.driver;
 
 	err = phydev->dev.driver->probe(&phydev->dev);
 	if(err < 0) {
 		printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev- 
 >dev.bus_id);
-		up_write(&phydev->dev.bus->subsys.rwsem);
 		goto probe_fail;
 	}
 
 	err = device_bind_driver(&phydev->dev);
-
-	up_write(&phydev->dev.bus->subsys.rwsem);
-
 	if (err)
drivers/net/phy/fixed.c +0 -0
 		goto probe_fail;
drivers/net/phy/phy_device.c +0 -4
index 7d5b6d1..8f01952 100644
@@ -208,16 +208,12 @@ struct phy_device *phy_attach(struct  
 net_device *dev,
 	 * exist, and we should use the genphy driver. */
 	if (NULL == d->driver) {
 		int err;
-		down_write(&d->bus->subsys.rwsem);
 		d->driver = &genphy_driver.driver;
 
 		err = d->driver->probe(d);
-
 		if (err >= 0)
 			err = device_bind_driver(d);
 
-		up_write(&d->bus->subsys.rwsem);
-
 		if (err)
 			return ERR_PTR(err);
drivers/net/phy/phy_device.c +1 -4
 	}
@@ -258,11 +254,8 @@ void phy_detach(struct phy_device *phydev)
 	 * was using the generic driver), we unbind the device
 	 * from the generic driver so that there's a chance a
 	 * real driver could be loaded */
-	if (phydev->dev.driver == &genphy_driver.driver) {
-		down_write(&phydev->dev.bus->subsys.rwsem);
+	if (phydev->dev.driver == &genphy_driver.driver)
 		device_release_driver(&phydev->dev);
-		up_write(&phydev->dev.bus->subsys.rwsem);
-	}
 }
 EXPORT_SYMBOL(phy_detach);
 
Signature · 6 lines
1.5.1.2

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#48 lore raw

PATCH 4/46 Driver core: udev triggered device-driver binding

In reply to Greg Kroah-Hartman

From: Kay Sievers <[email protected]>

We get two per-bus sysfs files:
ls-l /sys/subsystem/usb
drwxr-xr-x 2 root root 0 2007-02-16 16:42 devices
drwxr-xr-x 7 root root 0 2007-02-16 14:55 drivers
-rw-r--r-- 1 root root 4096 2007-02-16 16:42 drivers_autoprobe --w------- 1 root root 4096 2007-02-16 16:42 drivers_probe

The flag "drivers_autoprobe" controls the behavior of the bus to bind devices by default, or just initialize the device and leave it alone.

The command "drivers_probe" accepts a bus_id and the bus tries to bind a driver to this device.

Systems who want to control the driver binding with udev, switch off the bus initiated probing:
echo 0 > /sys/subsystem/usb/drivers_autoprobe
echo 0 > /sys/subsystem/pcmcia/drivers_autoprobe
...

and initiate the probing with udev rules like:
ACTION=="add", SUBSYSTEM=="usb", ATTR{subsystem/drivers_probe}="$kernel" ACTION=="add", SUBSYSTEM=="pcmcia", ATTR{subsystem/drivers_probe}="$kernel"
...

Custom driver binding can happen in earlier rules by something like:
ACTION=="add", SUBSYSTEM=="usb", \
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678" \
ATTR{subsystem/drivers/<custom-driver>/bind}="$kernel"

This is intended to solve the modprobe.conf mess with "install-rules", custom bind/unbind-scripts and all the weird things people invented over the years. It should also provide the functionality "libusual" was supposed to do.

With udev, one can just write a udev rule to drive all USB-disks at the third port of USB-hub by the "ub" driver, and everything else by usb-storage. One can also instruct udev to bind different wireless drivers to identical cards - just selected by the pcmcia slot-number, and whatever ...

To use the mentioned rules, it needs udev version 106, to be able to write ATTR{}="$kernel" to sysfs files.

---
 drivers/base/bus.c     |   84 ++++++++++++++++++++++++++++++++++++++++++++---
 include/linux/device.h |   34 +++++++++++--------
 2 files changed, 97 insertions(+), 21 deletions(-)
drivers/base/bus.c +78 -6
index 253868e..9df2e6d 100644
@@ -27,6 +27,9 @@
 #define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
+static int __must_check bus_rescan_devices_helper(struct device *dev,
+						void *data);
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -133,7 +136,6 @@ static decl_subsys(bus, &ktype_bus, NULL);
 
 
 #ifdef CONFIG_HOTPLUG
-
 /* Manually detach a device from its associated driver. */
 static int driver_helper(struct device *dev, void *data)
 {
@@ -199,6 +201,33 @@ static ssize_t driver_bind(struct device_driver *drv,
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
+static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
+{
+	return sprintf(buf, "%d\n", bus->drivers_autoprobe);
+}
+
+static ssize_t store_drivers_autoprobe(struct bus_type *bus,
+				       const char *buf, size_t count)
+{
+	if (buf[0] == '0')
+		bus->drivers_autoprobe = 0;
+	else
+		bus->drivers_autoprobe = 1;
+	return count;
+}
+
+static ssize_t store_drivers_probe(struct bus_type *bus,
+				   const char *buf, size_t count)
+{
+	struct device *dev;
+
+	dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+	if (!dev)
+		return -ENODEV;
+	if (bus_rescan_devices_helper(dev, NULL) != 0)
+		return -EINVAL;
+	return count;
+}
 #endif
 
 static struct device * next_device(struct klist_iter * i)
@@ -425,7 +454,8 @@ int bus_attach_device(struct device * dev)
 
 	if (bus) {
 		dev->is_registered = 1;
-		ret = device_attach(dev);
+		if (bus->drivers_autoprobe)
+			ret = device_attach(dev);
 		if (ret >= 0) {
 			klist_add_tail(&dev->knode_bus, &bus->klist_devices);
 			ret = 0;
@@ -515,9 +545,41 @@ static void remove_bind_files(struct device_driver *drv)
 	driver_remove_file(drv, &driver_attr_bind);
 	driver_remove_file(drv, &driver_attr_unbind);
 }
+
+static int add_probe_files(struct bus_type *bus)
+{
+	int retval;
+
+	bus->drivers_probe_attr.attr.name = "drivers_probe";
+	bus->drivers_probe_attr.attr.mode = S_IWUSR;
+	bus->drivers_probe_attr.attr.owner = bus->owner;
+	bus->drivers_probe_attr.store = store_drivers_probe;
+	retval = bus_create_file(bus, &bus->drivers_probe_attr);
+	if (retval)
+		goto out;
+
+	bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
+	bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
+	bus->drivers_autoprobe_attr.attr.owner = bus->owner;
+	bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
+	bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
+	retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+	if (retval)
+		bus_remove_file(bus, &bus->drivers_probe_attr);
+out:
+	return retval;
+}
+
+static void remove_probe_files(struct bus_type *bus)
+{
+	bus_remove_file(bus, &bus->drivers_autoprobe_attr);
+	bus_remove_file(bus, &bus->drivers_probe_attr);
+}
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
 static inline void remove_bind_files(struct device_driver *drv) {}
+static inline int add_probe_files(struct bus_type *bus) { return 0; }
+static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
 /**
@@ -541,9 +603,11 @@ int bus_add_driver(struct device_driver *drv)
 	if ((error = kobject_register(&drv->kobj)))
 		goto out_put_bus;
 
-	error = driver_attach(drv);
-	if (error)
-		goto out_unregister;
+	if (drv->bus->drivers_autoprobe) {
+		error = driver_attach(drv);
+		if (error)
+			goto out_unregister;
+	}
 	klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
@@ -762,6 +826,12 @@ int bus_register(struct bus_type * bus)
 
 	klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
 	klist_init(&bus->klist_drivers, NULL, NULL);
+
+	bus->drivers_autoprobe = 1;
+	retval = add_probe_files(bus);
+	if (retval)
+		goto bus_probe_files_fail;
+
 	retval = bus_add_attrs(bus);
 	if (retval)
 		goto bus_attrs_fail;
@@ -770,6 +840,8 @@ int bus_register(struct bus_type * bus)
 	return 0;
 
 bus_attrs_fail:
+	remove_probe_files(bus);
+bus_probe_files_fail:
 	kset_unregister(&bus->drivers);
 bus_drivers_fail:
 	kset_unregister(&bus->devices);
@@ -779,7 +851,6 @@ out:
 	return retval;
 }
 
-
 /**
  *	bus_unregister - remove a bus from the system
  *	@bus:	bus.
@@ -791,6 +862,7 @@ void bus_unregister(struct bus_type * bus)
 {
 	pr_debug("bus %s: unregistering\n", bus->name);
 	bus_remove_attrs(bus);
+	remove_probe_files(bus);
 	kset_unregister(&bus->drivers);
 	kset_unregister(&bus->devices);
 	subsystem_unregister(&bus->subsys);
include/linux/device.h +19 -15
index de0e73e..9d54fe1 100644
@@ -34,9 +34,24 @@ struct device;
 struct device_driver;
 struct class;
 struct class_device;
+struct bus_type;
+
+struct bus_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct bus_type *, char * buf);
+	ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+};
+
+#define BUS_ATTR(_name,_mode,_show,_store)	\
+struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+extern int __must_check bus_create_file(struct bus_type *,
+					struct bus_attribute *);
+extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
 
 struct bus_type {
 	const char		* name;
+	struct module		* owner;
 
 	struct subsystem	subsys;
 	struct kset		drivers;
@@ -49,6 +64,8 @@ struct bus_type {
 	struct bus_attribute	* bus_attrs;
 	struct device_attribute	* dev_attrs;
 	struct driver_attribute	* drv_attrs;
+	struct bus_attribute drivers_autoprobe_attr;
+	struct bus_attribute drivers_probe_attr;
 
 	int		(*match)(struct device * dev, struct device_driver * drv);
 	int		(*uevent)(struct device *dev, char **envp,
@@ -61,6 +78,8 @@ struct bus_type {
 	int (*suspend_late)(struct device * dev, pm_message_t state);
 	int (*resume_early)(struct device * dev);
 	int (*resume)(struct device * dev);
+
+	unsigned int drivers_autoprobe:1;
 };
 
 extern int __must_check bus_register(struct bus_type * bus);
@@ -102,21 +121,6 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 #define BUS_NOTIFY_UNBIND_DRIVER	0x00000004 /* driver about to be
 						      unbound */
 
-/* sysfs interface for exporting bus attributes */
-
-struct bus_attribute {
-	struct attribute	attr;
-	ssize_t (*show)(struct bus_type *, char * buf);
-	ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
-};
-
-#define BUS_ATTR(_name,_mode,_show,_store)	\
-struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-extern int __must_check bus_create_file(struct bus_type *,
-					struct bus_attribute *);
-extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
-
 struct device_driver {
 	const char		* name;
 	struct bus_type		* bus;
Signature · 1 line
1.5.1.2