Commit e5dd1278 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Driver core: move the static kobject out of struct driver



This patch removes the kobject, and a few other driver-core-only fields
out of struct driver and into the driver core only.  Now drivers can be
safely create on the stack or statically (like they currently are.)

Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c63469a3
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -27,6 +27,14 @@ struct bus_type_private {
	struct bus_type *bus;
};

struct driver_private {
	struct kobject kobj;
	struct klist klist_devices;
	struct klist_node knode_bus;
	struct module_kobject *mkobj;
	struct device_driver *driver;
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)

/* initialisation functions */
extern int devices_init(void);
+39 −32
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
 *
 * Copyright (c) 2002-3 Patrick Mochel
 * Copyright (c) 2002-3 Open Source Development Labs
 * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
 * Copyright (c) 2007 Novell Inc.
 *
 * This file is released under the GPLv2
 *
@@ -24,7 +26,6 @@
 */

#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
#define to_driver(obj) container_of(obj, struct device_driver, kobj)


static int __must_check bus_rescan_devices_helper(struct device *dev,
@@ -49,11 +50,11 @@ static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
	struct driver_attribute * drv_attr = to_drv_attr(attr);
	struct device_driver * drv = to_driver(kobj);
	struct driver_private *drv_priv = to_driver(kobj);
	ssize_t ret = -EIO;

	if (drv_attr->show)
		ret = drv_attr->show(drv, buf);
		ret = drv_attr->show(drv_priv->driver, buf);
	return ret;
}

@@ -62,11 +63,11 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr,
	       const char * buf, size_t count)
{
	struct driver_attribute * drv_attr = to_drv_attr(attr);
	struct device_driver * drv = to_driver(kobj);
	struct driver_private *drv_priv = to_driver(kobj);
	ssize_t ret = -EIO;

	if (drv_attr->store)
		ret = drv_attr->store(drv, buf, count);
		ret = drv_attr->store(drv_priv->driver, buf, count);
	return ret;
}

@@ -75,22 +76,12 @@ static struct sysfs_ops driver_sysfs_ops = {
	.store	= drv_attr_store,
};


static void driver_release(struct kobject *kobj)
{
	/*
	 * 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 <greg@kroah.com>
	 */
	struct driver_private *drv_priv = to_driver(kobj);

	pr_debug("%s: freeing %s\n", __FUNCTION__, kobject_name(kobj));
	kfree(drv_priv);
}

static struct kobj_type driver_ktype = {
@@ -350,7 +341,13 @@ struct device * bus_find_device(struct bus_type *bus,
static struct device_driver * next_driver(struct klist_iter * i)
{
	struct klist_node * n = klist_next(i);
	return n ? container_of(n, struct device_driver, knode_bus) : NULL;
	struct driver_private *drv_priv;

	if (n) {
		drv_priv = container_of(n, struct driver_private, knode_bus);
		return drv_priv->driver;
	}
	return NULL;
}

/**
@@ -384,7 +381,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_drivers, &i,
			     start ? &start->knode_bus : NULL);
			     start ? &start->p->knode_bus : NULL);
	while ((drv = next_driver(&i)) && !error)
		error = fn(drv, data);
	klist_iter_exit(&i);
@@ -620,7 +617,7 @@ static ssize_t driver_uevent_store(struct device_driver *drv,
	enum kobject_action action;

	if (kobject_action_type(buf, count, &action) == 0)
		kobject_uevent(&drv->kobj, action);
		kobject_uevent(&drv->p->kobj, action);
	return count;
}
static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
@@ -632,19 +629,29 @@ static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
 */
int bus_add_driver(struct device_driver *drv)
{
	struct bus_type * bus = bus_get(drv->bus);
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

	bus = bus_get(drv->bus);
	if (!bus)
		return -EINVAL;

	pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
	error = kobject_set_name(&drv->kobj, "%s", drv->name);

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	error = kobject_set_name(&priv->kobj, "%s", drv->name);
	if (error)
		goto out_put_bus;
	drv->kobj.kset = bus->p->drivers_kset;
	drv->kobj.ktype = &driver_ktype;
	error = kobject_register(&drv->kobj);
	priv->kobj.kset = bus->p->drivers_kset;
	priv->kobj.ktype = &driver_ktype;
	klist_init(&priv->klist_devices, NULL, NULL);
	priv->driver = drv;
	drv->p = priv;
	error = kobject_register(&priv->kobj);
	if (error)
		goto out_put_bus;

@@ -653,7 +660,7 @@ int bus_add_driver(struct device_driver *drv)
		if (error)
			goto out_unregister;
	}
	klist_add_tail(&drv->knode_bus, &bus->p->klist_drivers);
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
	module_add_driver(drv->owner, drv);

	error = driver_create_file(drv, &driver_attr_uevent);
@@ -676,7 +683,7 @@ int bus_add_driver(struct device_driver *drv)

	return error;
out_unregister:
	kobject_unregister(&drv->kobj);
	kobject_unregister(&priv->kobj);
out_put_bus:
	bus_put(bus);
	return error;
@@ -699,11 +706,11 @@ void bus_remove_driver(struct device_driver * drv)
	remove_bind_files(drv);
	driver_remove_attrs(drv->bus, drv);
	driver_remove_file(drv, &driver_attr_uevent);
	klist_remove(&drv->knode_bus);
	klist_remove(&drv->p->knode_bus);
	pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
	driver_detach(drv);
	module_remove_driver(drv);
	kobject_unregister(&drv->kobj);
	kobject_unregister(&drv->p->kobj);
	bus_put(drv->bus);
}

+12 −12
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
 *
 *	Copyright (c) 2002-5 Patrick Mochel
 *	Copyright (c) 2002-3 Open Source Development Labs
 *	Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
 *	Copyright (c) 2007 Novell Inc.
 *
 *	This file is released under the GPLv2
 */
@@ -23,8 +25,6 @@
#include "base.h"
#include "power/power.h"

#define to_drv(node) container_of(node, struct device_driver, kobj.entry)


static void driver_bound(struct device *dev)
{
@@ -41,20 +41,20 @@ static void driver_bound(struct device *dev)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_BOUND_DRIVER, dev);

	klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
	klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
}

static int driver_sysfs_add(struct device *dev)
{
	int ret;

	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
			  kobject_name(&dev->kobj));
	if (ret == 0) {
		ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,
		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
					"driver");
		if (ret)
			sysfs_remove_link(&dev->driver->kobj,
			sysfs_remove_link(&dev->driver->p->kobj,
					kobject_name(&dev->kobj));
	}
	return ret;
@@ -65,7 +65,7 @@ static void driver_sysfs_remove(struct device *dev)
	struct device_driver *drv = dev->driver;

	if (drv) {
		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
		sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
		sysfs_remove_link(&dev->kobj, "driver");
	}
}
@@ -339,15 +339,15 @@ void driver_detach(struct device_driver * drv)
	struct device * dev;

	for (;;) {
		spin_lock(&drv->klist_devices.k_lock);
		if (list_empty(&drv->klist_devices.k_list)) {
			spin_unlock(&drv->klist_devices.k_lock);
		spin_lock(&drv->p->klist_devices.k_lock);
		if (list_empty(&drv->p->klist_devices.k_list)) {
			spin_unlock(&drv->p->klist_devices.k_lock);
			break;
		}
		dev = list_entry(drv->klist_devices.k_list.prev,
		dev = list_entry(drv->p->klist_devices.k_list.prev,
				struct device, knode_driver.n_node);
		get_device(dev);
		spin_unlock(&drv->klist_devices.k_lock);
		spin_unlock(&drv->p->klist_devices.k_lock);

		if (dev->parent)	/* Needed for USB */
			down(&dev->parent->sem);
+26 −14
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
 *
 * Copyright (c) 2002-3 Patrick Mochel
 * Copyright (c) 2002-3 Open Source Development Labs
 * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
 * Copyright (c) 2007 Novell Inc.
 *
 * This file is released under the GPLv2
 *
@@ -15,7 +17,6 @@
#include "base.h"

#define to_dev(node) container_of(node, struct device, driver_list)
#define to_drv(obj) container_of(obj, struct device_driver, kobj)


static struct device * next_device(struct klist_iter * i)
@@ -44,7 +45,7 @@ int driver_for_each_device(struct device_driver * drv, struct device * start,
	if (!drv)
		return -EINVAL;

	klist_iter_init_node(&drv->klist_devices, &i,
	klist_iter_init_node(&drv->p->klist_devices, &i,
			     start ? &start->knode_driver : NULL);
	while ((dev = next_device(&i)) && !error)
		error = fn(dev, data);
@@ -80,7 +81,7 @@ struct device * driver_find_device(struct device_driver *drv,
	if (!drv)
		return NULL;

	klist_iter_init_node(&drv->klist_devices, &i,
	klist_iter_init_node(&drv->p->klist_devices, &i,
			     (start ? &start->knode_driver : NULL));
	while ((dev = next_device(&i)))
		if (match(dev, data) && get_device(dev))
@@ -100,7 +101,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att
{
	int error;
	if (get_driver(drv)) {
		error = sysfs_create_file(&drv->kobj, &attr->attr);
		error = sysfs_create_file(&drv->p->kobj, &attr->attr);
		put_driver(drv);
	} else
		error = -EINVAL;
@@ -117,7 +118,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
{
	if (get_driver(drv)) {
		sysfs_remove_file(&drv->kobj, &attr->attr);
		sysfs_remove_file(&drv->p->kobj, &attr->attr);
		put_driver(drv);
	}
}
@@ -143,7 +144,7 @@ int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
	if (!name)
		return -ENOMEM;

	return kobject_add_ng(kobj, &drv->kobj, "%s", name);
	return kobject_add_ng(kobj, &drv->p->kobj, "%s", name);
}
EXPORT_SYMBOL_GPL(driver_add_kobj);

@@ -153,7 +154,15 @@ EXPORT_SYMBOL_GPL(driver_add_kobj);
 */
struct device_driver * get_driver(struct device_driver * drv)
{
	return drv ? to_drv(kobject_get(&drv->kobj)) : NULL;
	if (drv) {
		struct driver_private *priv;
		struct kobject *kobj;

		kobj = kobject_get(&drv->p->kobj);
		priv = to_driver(kobj);
		return priv->driver;
	}
	return NULL;
}


@@ -163,7 +172,7 @@ struct device_driver * get_driver(struct device_driver * drv)
 */
void put_driver(struct device_driver * drv)
{
	kobject_put(&drv->kobj);
	kobject_put(&drv->p->kobj);
}

static int driver_add_groups(struct device_driver *drv,
@@ -174,10 +183,10 @@ static int driver_add_groups(struct device_driver *drv,

	if (groups) {
		for (i = 0; groups[i]; i++) {
			error = sysfs_create_group(&drv->kobj, groups[i]);
			error = sysfs_create_group(&drv->p->kobj, groups[i]);
			if (error) {
				while (--i >= 0)
					sysfs_remove_group(&drv->kobj,
					sysfs_remove_group(&drv->p->kobj,
							   groups[i]);
				break;
			}
@@ -193,7 +202,7 @@ static void driver_remove_groups(struct device_driver *drv,

	if (groups)
		for (i = 0; groups[i]; i++)
			sysfs_remove_group(&drv->kobj, groups[i]);
			sysfs_remove_group(&drv->p->kobj, groups[i]);
}


@@ -214,7 +223,6 @@ int driver_register(struct device_driver * drv)
	    (drv->bus->shutdown && drv->shutdown)) {
		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
	}
	klist_init(&drv->klist_devices, NULL, NULL);
	ret = bus_add_driver(drv);
	if (ret)
		return ret;
@@ -250,8 +258,12 @@ void driver_unregister(struct device_driver * drv)
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
	if (k)
		return to_drv(k);
	struct driver_private *priv;

	if (k) {
		priv = to_driver(k);
		return priv->driver;
	}
	return NULL;
}

+6 −6
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ void module_add_driver(struct module *mod, struct device_driver *drv)
		if (mkobj) {
			mk = container_of(mkobj, struct module_kobject, kobj);
			/* remember our module structure */
			drv->mkobj = mk;
			drv->p->mkobj = mk;
			/* kset_find_obj took a reference */
			kobject_put(mkobj);
		}
@@ -60,11 +60,11 @@ void module_add_driver(struct module *mod, struct device_driver *drv)
		return;

	/* Don't check return codes; these calls are idempotent */
	no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
	driver_name = make_driver_name(drv);
	if (driver_name) {
		module_create_drivers_dir(mk);
		no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
					    driver_name);
		kfree(driver_name);
	}
@@ -78,12 +78,12 @@ void module_remove_driver(struct device_driver *drv)
	if (!drv)
		return;

	sysfs_remove_link(&drv->kobj, "module");
	sysfs_remove_link(&drv->p->kobj, "module");

	if (drv->owner)
		mk = &drv->owner->mkobj;
	else if (drv->mkobj)
		mk = drv->mkobj;
	else if (drv->p->mkobj)
		mk = drv->p->mkobj;
	if (mk && mk->drivers_dir) {
		driver_name = make_driver_name(drv);
		if (driver_name) {
Loading